From eb98d318b28cc177f608d57fb5b9b017235b515d Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 14 Feb 2019 13:02:36 +0100 Subject: [PATCH] Require defining uses to use generic parameters for all parameters of a generic existential type --- src/librustc_typeck/collect.rs | 17 ++++++++++++---- .../ui/existential_types/bound_reduction2.rs | 3 ++- .../existential_types/bound_reduction2.stderr | 16 +++++++-------- .../generic_duplicate_param_use10.rs | 12 +++++++++++ .../generic_duplicate_param_use9.rs | 20 +++++++++++++++++++ .../generic_duplicate_param_use9.stderr | 18 +++++++++++++++++ .../generic_nondefining_use.rs | 3 ++- .../generic_nondefining_use.stderr | 16 +++++++-------- .../existential_types/not_a_defining_use.rs | 1 + .../not_a_defining_use.stderr | 19 +++++++++++++----- 10 files changed, 98 insertions(+), 27 deletions(-) create mode 100644 src/test/ui/existential_types/generic_duplicate_param_use10.rs create mode 100644 src/test/ui/existential_types/generic_duplicate_param_use9.rs create mode 100644 src/test/ui/existential_types/generic_duplicate_param_use9.stderr diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index b26a6a2292a0..b50a165ba9cd 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1385,10 +1385,19 @@ fn find_existential_constraints<'a, 'tcx>( .subst(self.tcx, substs) .walk() .filter_map(|t| match &t.sty { - ty::Param(p) => Some(*index_map.get(p).unwrap()), - _ => None, - }).collect(); - if let Some((prev_span, prev_ty, ref prev_indices)) = self.found { + ty::Param(p) => Some(*index_map.get(p).unwrap()), + _ => None, + }).collect(); + let is_param = |ty: ty::Ty| match ty.sty { + ty::Param(_) => true, + _ => false, + }; + if !substs.types().all(is_param) { + self.tcx.sess.span_err( + span, + "defining existential type use does not fully define existential type", + ); + } else if let Some((prev_span, prev_ty, ref prev_indices)) = self.found { let mut ty = concrete_type.walk().fuse(); let mut p_ty = prev_ty.walk().fuse(); let iter_eq = (&mut ty).zip(&mut p_ty).all(|(t, p)| match (&t.sty, &p.sty) { diff --git a/src/test/ui/existential_types/bound_reduction2.rs b/src/test/ui/existential_types/bound_reduction2.rs index d8ade50c79c8..542e076d88d6 100644 --- a/src/test/ui/existential_types/bound_reduction2.rs +++ b/src/test/ui/existential_types/bound_reduction2.rs @@ -8,11 +8,12 @@ trait TraitWithAssoc { } existential type Foo: Trait; +//~^ ERROR could not find defining uses trait Trait {} impl Trait for () {} -fn foo_desugared(_: T) -> Foo { //~ ERROR non-defining +fn foo_desugared(_: T) -> Foo { //~ ERROR does not fully define () } diff --git a/src/test/ui/existential_types/bound_reduction2.stderr b/src/test/ui/existential_types/bound_reduction2.stderr index 8e822ca6d8bc..f51f1c9a4e56 100644 --- a/src/test/ui/existential_types/bound_reduction2.stderr +++ b/src/test/ui/existential_types/bound_reduction2.stderr @@ -1,16 +1,16 @@ -error: non-defining existential type use in defining scope - --> $DIR/bound_reduction2.rs:16:1 +error: defining existential type use does not fully define existential type + --> $DIR/bound_reduction2.rs:17:1 | -LL | / fn foo_desugared(_: T) -> Foo { //~ ERROR non-defining +LL | / fn foo_desugared(_: T) -> Foo { //~ ERROR does not fully define LL | | () LL | | } | |_^ - | -note: used non-generic type ::Assoc for generic parameter - --> $DIR/bound_reduction2.rs:10:22 + +error: could not find defining uses + --> $DIR/bound_reduction2.rs:10:1 | LL | existential type Foo: Trait; - | ^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error: aborting due to 2 previous errors diff --git a/src/test/ui/existential_types/generic_duplicate_param_use10.rs b/src/test/ui/existential_types/generic_duplicate_param_use10.rs new file mode 100644 index 000000000000..10f2c630582f --- /dev/null +++ b/src/test/ui/existential_types/generic_duplicate_param_use10.rs @@ -0,0 +1,12 @@ +// compile-pass +#![feature(existential_type)] + +use std::fmt::Debug; + +fn main() {} + +existential type Two: Debug; + +fn two(t: T, _: U) -> Two { + (t, 4u32) +} diff --git a/src/test/ui/existential_types/generic_duplicate_param_use9.rs b/src/test/ui/existential_types/generic_duplicate_param_use9.rs new file mode 100644 index 000000000000..4c6897298c44 --- /dev/null +++ b/src/test/ui/existential_types/generic_duplicate_param_use9.rs @@ -0,0 +1,20 @@ +#![feature(existential_type)] + +use std::fmt::Debug; + +fn main() {} + +existential type Two: Debug; + +trait Foo { + type Bar: Debug; + const BAR: Self::Bar; +} + +fn two(t: T, u: U) -> Two { + (t, u, T::BAR) +} + +fn three(t: T, u: U) -> Two { + (t, u, 42) //~^ ERROR concrete type differs from previous +} diff --git a/src/test/ui/existential_types/generic_duplicate_param_use9.stderr b/src/test/ui/existential_types/generic_duplicate_param_use9.stderr new file mode 100644 index 000000000000..a3ce480d66dc --- /dev/null +++ b/src/test/ui/existential_types/generic_duplicate_param_use9.stderr @@ -0,0 +1,18 @@ +error: concrete type differs from previous defining existential type use + --> $DIR/generic_duplicate_param_use9.rs:18:1 + | +LL | / fn three(t: T, u: U) -> Two { +LL | | (t, u, 42) //~^ ERROR concrete type differs from previous +LL | | } + | |_^ expected `(A, B, ::Bar)`, got `(A, B, i32)` + | +note: previous use here + --> $DIR/generic_duplicate_param_use9.rs:14:1 + | +LL | / fn two(t: T, u: U) -> Two { +LL | | (t, u, T::BAR) +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/existential_types/generic_nondefining_use.rs b/src/test/ui/existential_types/generic_nondefining_use.rs index caa8f0f2ee1b..75af5d9570ff 100644 --- a/src/test/ui/existential_types/generic_nondefining_use.rs +++ b/src/test/ui/existential_types/generic_nondefining_use.rs @@ -3,8 +3,9 @@ fn main() {} existential type Cmp: 'static; +//~^ ERROR could not find defining uses // not a defining use, because it doesn't define *all* possible generics -fn cmp() -> Cmp { //~ ERROR non-defining existential type use in defining scope +fn cmp() -> Cmp { //~ ERROR defining existential type use does not fully define 5u32 } diff --git a/src/test/ui/existential_types/generic_nondefining_use.stderr b/src/test/ui/existential_types/generic_nondefining_use.stderr index 41877791e9ae..8dd88006be9c 100644 --- a/src/test/ui/existential_types/generic_nondefining_use.stderr +++ b/src/test/ui/existential_types/generic_nondefining_use.stderr @@ -1,16 +1,16 @@ -error: non-defining existential type use in defining scope - --> $DIR/generic_nondefining_use.rs:8:1 +error: defining existential type use does not fully define existential type + --> $DIR/generic_nondefining_use.rs:9:1 | -LL | / fn cmp() -> Cmp { //~ ERROR non-defining existential type use in defining scope +LL | / fn cmp() -> Cmp { //~ ERROR defining existential type use does not fully define LL | | 5u32 LL | | } | |_^ - | -note: used non-generic type u32 for generic parameter - --> $DIR/generic_nondefining_use.rs:5:22 + +error: could not find defining uses + --> $DIR/generic_nondefining_use.rs:5:1 | LL | existential type Cmp: 'static; - | ^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error: aborting due to 2 previous errors diff --git a/src/test/ui/existential_types/not_a_defining_use.rs b/src/test/ui/existential_types/not_a_defining_use.rs index 413cc6788c28..3f81f5177d0a 100644 --- a/src/test/ui/existential_types/not_a_defining_use.rs +++ b/src/test/ui/existential_types/not_a_defining_use.rs @@ -7,6 +7,7 @@ fn main() {} existential type Two: Debug; fn two(t: T) -> Two { + //~^ ERROR defining existential type use does not fully define existential type (t, 4i8) } diff --git a/src/test/ui/existential_types/not_a_defining_use.stderr b/src/test/ui/existential_types/not_a_defining_use.stderr index a6ed5dbe0a9d..288a32fc14ed 100644 --- a/src/test/ui/existential_types/not_a_defining_use.stderr +++ b/src/test/ui/existential_types/not_a_defining_use.stderr @@ -1,5 +1,14 @@ +error: defining existential type use does not fully define existential type + --> $DIR/not_a_defining_use.rs:9:1 + | +LL | / fn two(t: T) -> Two { +LL | | //~^ ERROR defining existential type use does not fully define existential type +LL | | (t, 4i8) +LL | | } + | |_^ + error: concrete type differs from previous defining existential type use - --> $DIR/not_a_defining_use.rs:29:1 + --> $DIR/not_a_defining_use.rs:30:1 | LL | / fn four(t: T) -> Two { //~ concrete type differs from previous LL | | (t, ::FOO) @@ -7,12 +16,12 @@ LL | | } | |_^ expected `(T, i8)`, got `(T, ::Blub)` | note: previous use here - --> $DIR/not_a_defining_use.rs:9:1 + --> $DIR/not_a_defining_use.rs:14:1 | -LL | / fn two(t: T) -> Two { -LL | | (t, 4i8) +LL | / fn three(t: T) -> Two { +LL | | (t, 5i8) LL | | } | |_^ -error: aborting due to previous error +error: aborting due to 2 previous errors