Skip to content

Commit eb98d31

Browse files
committed
Require defining uses to use generic parameters for all parameters of a generic existential type
1 parent c93bce8 commit eb98d31

10 files changed

+98
-27
lines changed

src/librustc_typeck/collect.rs

+13-4
Original file line numberDiff line numberDiff line change
@@ -1385,10 +1385,19 @@ fn find_existential_constraints<'a, 'tcx>(
13851385
.subst(self.tcx, substs)
13861386
.walk()
13871387
.filter_map(|t| match &t.sty {
1388-
ty::Param(p) => Some(*index_map.get(p).unwrap()),
1389-
_ => None,
1390-
}).collect();
1391-
if let Some((prev_span, prev_ty, ref prev_indices)) = self.found {
1388+
ty::Param(p) => Some(*index_map.get(p).unwrap()),
1389+
_ => None,
1390+
}).collect();
1391+
let is_param = |ty: ty::Ty| match ty.sty {
1392+
ty::Param(_) => true,
1393+
_ => false,
1394+
};
1395+
if !substs.types().all(is_param) {
1396+
self.tcx.sess.span_err(
1397+
span,
1398+
"defining existential type use does not fully define existential type",
1399+
);
1400+
} else if let Some((prev_span, prev_ty, ref prev_indices)) = self.found {
13921401
let mut ty = concrete_type.walk().fuse();
13931402
let mut p_ty = prev_ty.walk().fuse();
13941403
let iter_eq = (&mut ty).zip(&mut p_ty).all(|(t, p)| match (&t.sty, &p.sty) {

src/test/ui/existential_types/bound_reduction2.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@ trait TraitWithAssoc {
88
}
99

1010
existential type Foo<V>: Trait<V>;
11+
//~^ ERROR could not find defining uses
1112

1213
trait Trait<U> {}
1314

1415
impl<W> Trait<W> for () {}
1516

16-
fn foo_desugared<T: TraitWithAssoc>(_: T) -> Foo<T::Assoc> { //~ ERROR non-defining
17+
fn foo_desugared<T: TraitWithAssoc>(_: T) -> Foo<T::Assoc> { //~ ERROR does not fully define
1718
()
1819
}
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
error: non-defining existential type use in defining scope
2-
--> $DIR/bound_reduction2.rs:16:1
1+
error: defining existential type use does not fully define existential type
2+
--> $DIR/bound_reduction2.rs:17:1
33
|
4-
LL | / fn foo_desugared<T: TraitWithAssoc>(_: T) -> Foo<T::Assoc> { //~ ERROR non-defining
4+
LL | / fn foo_desugared<T: TraitWithAssoc>(_: T) -> Foo<T::Assoc> { //~ ERROR does not fully define
55
LL | | ()
66
LL | | }
77
| |_^
8-
|
9-
note: used non-generic type <T as TraitWithAssoc>::Assoc for generic parameter
10-
--> $DIR/bound_reduction2.rs:10:22
8+
9+
error: could not find defining uses
10+
--> $DIR/bound_reduction2.rs:10:1
1111
|
1212
LL | existential type Foo<V>: Trait<V>;
13-
| ^
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1414

15-
error: aborting due to previous error
15+
error: aborting due to 2 previous errors
1616

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// compile-pass
2+
#![feature(existential_type)]
3+
4+
use std::fmt::Debug;
5+
6+
fn main() {}
7+
8+
existential type Two<T, U>: Debug;
9+
10+
fn two<T: Debug, U: Debug>(t: T, _: U) -> Two<T, U> {
11+
(t, 4u32)
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#![feature(existential_type)]
2+
3+
use std::fmt::Debug;
4+
5+
fn main() {}
6+
7+
existential type Two<A, B>: Debug;
8+
9+
trait Foo {
10+
type Bar: Debug;
11+
const BAR: Self::Bar;
12+
}
13+
14+
fn two<T: Debug + Foo, U: Debug>(t: T, u: U) -> Two<T, U> {
15+
(t, u, T::BAR)
16+
}
17+
18+
fn three<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
19+
(t, u, 42) //~^ ERROR concrete type differs from previous
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
error: concrete type differs from previous defining existential type use
2+
--> $DIR/generic_duplicate_param_use9.rs:18:1
3+
|
4+
LL | / fn three<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
5+
LL | | (t, u, 42) //~^ ERROR concrete type differs from previous
6+
LL | | }
7+
| |_^ expected `(A, B, <A as Foo>::Bar)`, got `(A, B, i32)`
8+
|
9+
note: previous use here
10+
--> $DIR/generic_duplicate_param_use9.rs:14:1
11+
|
12+
LL | / fn two<T: Debug + Foo, U: Debug>(t: T, u: U) -> Two<T, U> {
13+
LL | | (t, u, T::BAR)
14+
LL | | }
15+
| |_^
16+
17+
error: aborting due to previous error
18+

src/test/ui/existential_types/generic_nondefining_use.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
fn main() {}
44

55
existential type Cmp<T>: 'static;
6+
//~^ ERROR could not find defining uses
67

78
// not a defining use, because it doesn't define *all* possible generics
8-
fn cmp() -> Cmp<u32> { //~ ERROR non-defining existential type use in defining scope
9+
fn cmp() -> Cmp<u32> { //~ ERROR defining existential type use does not fully define
910
5u32
1011
}
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
error: non-defining existential type use in defining scope
2-
--> $DIR/generic_nondefining_use.rs:8:1
1+
error: defining existential type use does not fully define existential type
2+
--> $DIR/generic_nondefining_use.rs:9:1
33
|
4-
LL | / fn cmp() -> Cmp<u32> { //~ ERROR non-defining existential type use in defining scope
4+
LL | / fn cmp() -> Cmp<u32> { //~ ERROR defining existential type use does not fully define
55
LL | | 5u32
66
LL | | }
77
| |_^
8-
|
9-
note: used non-generic type u32 for generic parameter
10-
--> $DIR/generic_nondefining_use.rs:5:22
8+
9+
error: could not find defining uses
10+
--> $DIR/generic_nondefining_use.rs:5:1
1111
|
1212
LL | existential type Cmp<T>: 'static;
13-
| ^
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1414

15-
error: aborting due to previous error
15+
error: aborting due to 2 previous errors
1616

src/test/ui/existential_types/not_a_defining_use.rs

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ fn main() {}
77
existential type Two<T, U>: Debug;
88

99
fn two<T: Debug>(t: T) -> Two<T, u32> {
10+
//~^ ERROR defining existential type use does not fully define existential type
1011
(t, 4i8)
1112
}
1213

Original file line numberDiff line numberDiff line change
@@ -1,18 +1,27 @@
1+
error: defining existential type use does not fully define existential type
2+
--> $DIR/not_a_defining_use.rs:9:1
3+
|
4+
LL | / fn two<T: Debug>(t: T) -> Two<T, u32> {
5+
LL | | //~^ ERROR defining existential type use does not fully define existential type
6+
LL | | (t, 4i8)
7+
LL | | }
8+
| |_^
9+
110
error: concrete type differs from previous defining existential type use
2-
--> $DIR/not_a_defining_use.rs:29:1
11+
--> $DIR/not_a_defining_use.rs:30:1
312
|
413
LL | / fn four<T: Debug, U: Bar>(t: T) -> Two<T, U> { //~ concrete type differs from previous
514
LL | | (t, <U as Bar>::FOO)
615
LL | | }
716
| |_^ expected `(T, i8)`, got `(T, <U as Bar>::Blub)`
817
|
918
note: previous use here
10-
--> $DIR/not_a_defining_use.rs:9:1
19+
--> $DIR/not_a_defining_use.rs:14:1
1120
|
12-
LL | / fn two<T: Debug>(t: T) -> Two<T, u32> {
13-
LL | | (t, 4i8)
21+
LL | / fn three<T: Debug, U>(t: T) -> Two<T, U> {
22+
LL | | (t, 5i8)
1423
LL | | }
1524
| |_^
1625

17-
error: aborting due to previous error
26+
error: aborting due to 2 previous errors
1827

0 commit comments

Comments
 (0)