From 381c5416855f53e130d5156aec5f9067fc981dfa Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 25 Jan 2019 15:04:15 +0100 Subject: [PATCH 01/10] Add FIXME --- src/librustc_typeck/check/writeback.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 238b087fe32f8..00917be538fb3 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -561,6 +561,8 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { if def_id == defin_ty_def_id { // Concrete type resolved to the existential type itself // Force a cycle error + // FIXME(oli-obk): we could just not insert it into `concrete_existential_types` + // which simply would make this use not a defining use. self.tcx().at(span).type_of(defin_ty_def_id); } } From 6982fd21d1d7963b2acc489d9de246f2715aab80 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 25 Jan 2019 16:14:59 +0100 Subject: [PATCH 02/10] Be more permissive with required bounds on existential types --- src/librustc_typeck/check/mod.rs | 3 --- .../ui/existential_types/generic_duplicate_param_use.rs | 4 +++- src/test/ui/existential_types/unused_generic_param.rs | 7 +++++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 48475b3dcb802..5390382ee2d76 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1385,10 +1385,7 @@ pub fn check_item_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Ite } hir::ItemKind::Existential(..) => { let def_id = tcx.hir().local_def_id(it.id); - let pty_ty = tcx.type_of(def_id); - let generics = tcx.generics_of(def_id); - check_bounds_are_used(tcx, &generics, pty_ty); let substs = Substs::identity_for_item(tcx, def_id); check_opaque(tcx, def_id, substs, it.span); } diff --git a/src/test/ui/existential_types/generic_duplicate_param_use.rs b/src/test/ui/existential_types/generic_duplicate_param_use.rs index 380fbdeb8c27c..14d63ecc6bb5d 100644 --- a/src/test/ui/existential_types/generic_duplicate_param_use.rs +++ b/src/test/ui/existential_types/generic_duplicate_param_use.rs @@ -1,8 +1,10 @@ +// compile-pass #![feature(existential_type)] fn main() {} -existential type Two: 'static; //~ ERROR type parameter `U` is unused +// test that unused generic parameters are ok +existential type Two: 'static; fn one(t: T) -> Two { t diff --git a/src/test/ui/existential_types/unused_generic_param.rs b/src/test/ui/existential_types/unused_generic_param.rs index bd7b343b402f5..7af6508788129 100644 --- a/src/test/ui/existential_types/unused_generic_param.rs +++ b/src/test/ui/existential_types/unused_generic_param.rs @@ -1,15 +1,18 @@ +// compile-pass #![feature(existential_type)] fn main() { } -existential type PartiallyDefined: 'static; //~ `T` is unused +// test that unused generic parameters are ok +existential type PartiallyDefined: 'static; fn partially_defined(_: T) -> PartiallyDefined { 4u32 } -existential type PartiallyDefined2: 'static; //~ `T` is unused +// test that unused generic parameters are ok +existential type PartiallyDefined2: 'static; fn partially_defined2(_: T) -> PartiallyDefined2 { 4u32 From ed10a5ba01cb0e73e3872434da65bf4f3a976f28 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 25 Jan 2019 20:32:45 +0100 Subject: [PATCH 03/10] Test all the things --- .../generic_duplicate_param_use.stderr | 9 --------- .../generic_duplicate_param_use2.rs | 15 +++++++++++++++ .../generic_duplicate_param_use3.rs | 19 +++++++++++++++++++ .../generic_duplicate_param_use3.stderr | 19 +++++++++++++++++++ .../generic_duplicate_param_use4.rs | 15 +++++++++++++++ .../generic_duplicate_param_use4.stderr | 19 +++++++++++++++++++ .../unused_generic_param.stderr | 15 --------------- 7 files changed, 87 insertions(+), 24 deletions(-) delete mode 100644 src/test/ui/existential_types/generic_duplicate_param_use.stderr create mode 100644 src/test/ui/existential_types/generic_duplicate_param_use2.rs create mode 100644 src/test/ui/existential_types/generic_duplicate_param_use3.rs create mode 100644 src/test/ui/existential_types/generic_duplicate_param_use3.stderr create mode 100644 src/test/ui/existential_types/generic_duplicate_param_use4.rs create mode 100644 src/test/ui/existential_types/generic_duplicate_param_use4.stderr delete mode 100644 src/test/ui/existential_types/unused_generic_param.stderr diff --git a/src/test/ui/existential_types/generic_duplicate_param_use.stderr b/src/test/ui/existential_types/generic_duplicate_param_use.stderr deleted file mode 100644 index 66706c210541c..0000000000000 --- a/src/test/ui/existential_types/generic_duplicate_param_use.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0091]: type parameter `U` is unused - --> $DIR/generic_duplicate_param_use.rs:5:25 - | -LL | existential type Two: 'static; //~ ERROR type parameter `U` is unused - | ^ unused type parameter - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0091`. diff --git a/src/test/ui/existential_types/generic_duplicate_param_use2.rs b/src/test/ui/existential_types/generic_duplicate_param_use2.rs new file mode 100644 index 0000000000000..b6cb22da41d7f --- /dev/null +++ b/src/test/ui/existential_types/generic_duplicate_param_use2.rs @@ -0,0 +1,15 @@ +// compile-pass +#![feature(existential_type)] + +fn main() {} + +// test that unused generic parameters are ok +existential type Two: 'static; + +fn one(t: T) -> Two { + t +} + +fn two(t: T, _: U) -> Two { + t +} diff --git a/src/test/ui/existential_types/generic_duplicate_param_use3.rs b/src/test/ui/existential_types/generic_duplicate_param_use3.rs new file mode 100644 index 0000000000000..43650a6a35296 --- /dev/null +++ b/src/test/ui/existential_types/generic_duplicate_param_use3.rs @@ -0,0 +1,19 @@ +#![feature(existential_type)] + +fn main() {} + +// test that unused generic parameters are ok +existential type Two: 'static; + +fn one(t: T) -> Two { + t +} + +fn two(t: T, _: U) -> Two { + t +} + +fn three(_: T, u: U) -> Two { + //~^ ERROR defining existential type use differs from previous + u +} diff --git a/src/test/ui/existential_types/generic_duplicate_param_use3.stderr b/src/test/ui/existential_types/generic_duplicate_param_use3.stderr new file mode 100644 index 0000000000000..67c30ad648b35 --- /dev/null +++ b/src/test/ui/existential_types/generic_duplicate_param_use3.stderr @@ -0,0 +1,19 @@ +error: defining existential type use differs from previous + --> $DIR/generic_duplicate_param_use3.rs:16:1 + | +LL | / fn three(_: T, u: U) -> Two { +LL | | //~^ ERROR defining existential type use differs from previous +LL | | u +LL | | } + | |_^ + | +note: previous use here + --> $DIR/generic_duplicate_param_use3.rs:8:1 + | +LL | / fn one(t: T) -> Two { +LL | | t +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/existential_types/generic_duplicate_param_use4.rs b/src/test/ui/existential_types/generic_duplicate_param_use4.rs new file mode 100644 index 0000000000000..79df528d209c6 --- /dev/null +++ b/src/test/ui/existential_types/generic_duplicate_param_use4.rs @@ -0,0 +1,15 @@ +#![feature(existential_type)] + +fn main() {} + +// test that unused generic parameters are ok +existential type Two: 'static; + +fn one(t: T) -> Two { + t +} + +fn three(_: T, u: U) -> Two { +//~^ ERROR defining existential type use differs from previous + u +} diff --git a/src/test/ui/existential_types/generic_duplicate_param_use4.stderr b/src/test/ui/existential_types/generic_duplicate_param_use4.stderr new file mode 100644 index 0000000000000..e7a372e0e0c9b --- /dev/null +++ b/src/test/ui/existential_types/generic_duplicate_param_use4.stderr @@ -0,0 +1,19 @@ +error: defining existential type use differs from previous + --> $DIR/generic_duplicate_param_use4.rs:12:1 + | +LL | / fn three(_: T, u: U) -> Two { +LL | | //~^ ERROR defining existential type use differs from previous +LL | | u +LL | | } + | |_^ + | +note: previous use here + --> $DIR/generic_duplicate_param_use4.rs:8:1 + | +LL | / fn one(t: T) -> Two { +LL | | t +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/existential_types/unused_generic_param.stderr b/src/test/ui/existential_types/unused_generic_param.stderr deleted file mode 100644 index 348aed3c43914..0000000000000 --- a/src/test/ui/existential_types/unused_generic_param.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0091]: type parameter `T` is unused - --> $DIR/unused_generic_param.rs:6:35 - | -LL | existential type PartiallyDefined: 'static; //~ `T` is unused - | ^ unused type parameter - -error[E0091]: type parameter `T` is unused - --> $DIR/unused_generic_param.rs:12:36 - | -LL | existential type PartiallyDefined2: 'static; //~ `T` is unused - | ^ unused type parameter - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0091`. From 0d25ff8842ca35b7eabd2d8a22669c5b2216ad82 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 25 Jan 2019 20:37:10 +0100 Subject: [PATCH 04/10] Test aller things --- .../generic_duplicate_param_use5.rs | 15 +++++++++++++++ .../generic_duplicate_param_use5.stderr | 19 +++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 src/test/ui/existential_types/generic_duplicate_param_use5.rs create mode 100644 src/test/ui/existential_types/generic_duplicate_param_use5.stderr diff --git a/src/test/ui/existential_types/generic_duplicate_param_use5.rs b/src/test/ui/existential_types/generic_duplicate_param_use5.rs new file mode 100644 index 0000000000000..f9d336d759b62 --- /dev/null +++ b/src/test/ui/existential_types/generic_duplicate_param_use5.rs @@ -0,0 +1,15 @@ +#![feature(existential_type)] + +fn main() {} + +// test that unused generic parameters are ok +existential type Two: 'static; + +fn one(t: T) -> Two { + t +} + +fn two(t: T, _: U) -> Two { +//~^ ERROR defining existential type use differs from previous + t +} diff --git a/src/test/ui/existential_types/generic_duplicate_param_use5.stderr b/src/test/ui/existential_types/generic_duplicate_param_use5.stderr new file mode 100644 index 0000000000000..e2bf4a9e0dfef --- /dev/null +++ b/src/test/ui/existential_types/generic_duplicate_param_use5.stderr @@ -0,0 +1,19 @@ +error: defining existential type use differs from previous + --> $DIR/generic_duplicate_param_use5.rs:12:1 + | +LL | / fn two(t: T, _: U) -> Two { +LL | | //~^ ERROR defining existential type use differs from previous +LL | | t +LL | | } + | |_^ + | +note: previous use here + --> $DIR/generic_duplicate_param_use5.rs:8:1 + | +LL | / fn one(t: T) -> Two { +LL | | t +LL | | } + | |_^ + +error: aborting due to previous error + From cf01b514c876656696e87672a1c118a3ce7817ed Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 25 Jan 2019 22:57:31 +0100 Subject: [PATCH 05/10] Generic type parameters are flexible even for existential types --- src/librustc_typeck/collect.rs | 11 ++++++++++- .../generic_duplicate_param_use.rs | 6 ++++-- .../generic_duplicate_param_use2.rs | 8 +++++--- .../generic_duplicate_param_use3.rs | 12 +++++++----- .../generic_duplicate_param_use3.stderr | 19 ------------------- .../generic_duplicate_param_use4.rs | 10 ++++++---- .../generic_duplicate_param_use4.stderr | 19 ------------------- .../generic_duplicate_param_use5.rs | 15 --------------- .../generic_duplicate_param_use5.stderr | 19 ------------------- 9 files changed, 32 insertions(+), 87 deletions(-) delete mode 100644 src/test/ui/existential_types/generic_duplicate_param_use3.stderr delete mode 100644 src/test/ui/existential_types/generic_duplicate_param_use4.stderr delete mode 100644 src/test/ui/existential_types/generic_duplicate_param_use5.rs delete mode 100644 src/test/ui/existential_types/generic_duplicate_param_use5.stderr diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index b0b266a61a5b6..e4fc1925eb377 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1346,7 +1346,16 @@ fn find_existential_constraints<'a, 'tcx>( // FIXME(oli-obk): trace the actual span from inference to improve errors let span = self.tcx.def_span(def_id); if let Some((prev_span, prev_ty)) = self.found { - if ty != prev_ty { + let mut ty = ty.walk().fuse(); + let mut prev_ty = prev_ty.walk().fuse(); + let iter_eq = (&mut ty).zip(&mut prev_ty).all(|(t, p)| match (&t.sty, &p.sty) { + // type parameters are equal to any other type parameter for the purpose of + // concrete type equality, as it is possible to obtain the same type just + // by passing matching parameters to a function. + (ty::Param(_), ty::Param(_)) => true, + _ => t == p, + }); + if !iter_eq || ty.next().is_some() || prev_ty.next().is_some() { // found different concrete types for the existential type let mut err = self.tcx.sess.struct_span_err( span, diff --git a/src/test/ui/existential_types/generic_duplicate_param_use.rs b/src/test/ui/existential_types/generic_duplicate_param_use.rs index 14d63ecc6bb5d..d08cd88c600d0 100644 --- a/src/test/ui/existential_types/generic_duplicate_param_use.rs +++ b/src/test/ui/existential_types/generic_duplicate_param_use.rs @@ -1,11 +1,13 @@ // compile-pass #![feature(existential_type)] +use std::fmt::Debug; + fn main() {} // test that unused generic parameters are ok -existential type Two: 'static; +existential type Two: Debug; -fn one(t: T) -> Two { +fn one(t: T) -> Two { t } diff --git a/src/test/ui/existential_types/generic_duplicate_param_use2.rs b/src/test/ui/existential_types/generic_duplicate_param_use2.rs index b6cb22da41d7f..c27fbb74cf19d 100644 --- a/src/test/ui/existential_types/generic_duplicate_param_use2.rs +++ b/src/test/ui/existential_types/generic_duplicate_param_use2.rs @@ -1,15 +1,17 @@ // compile-pass #![feature(existential_type)] +use std::fmt::Debug; + fn main() {} // test that unused generic parameters are ok -existential type Two: 'static; +existential type Two: Debug; -fn one(t: T) -> Two { +fn one(t: T) -> Two { t } -fn two(t: T, _: U) -> Two { +fn two(t: T, _: U) -> Two { t } diff --git a/src/test/ui/existential_types/generic_duplicate_param_use3.rs b/src/test/ui/existential_types/generic_duplicate_param_use3.rs index 43650a6a35296..b4d1b26dbabda 100644 --- a/src/test/ui/existential_types/generic_duplicate_param_use3.rs +++ b/src/test/ui/existential_types/generic_duplicate_param_use3.rs @@ -1,19 +1,21 @@ +// compile-pass #![feature(existential_type)] +use std::fmt::Debug; + fn main() {} // test that unused generic parameters are ok -existential type Two: 'static; +existential type Two: Debug; -fn one(t: T) -> Two { +fn one(t: T) -> Two { t } -fn two(t: T, _: U) -> Two { +fn two(t: T, _: U) -> Two { t } -fn three(_: T, u: U) -> Two { - //~^ ERROR defining existential type use differs from previous +fn three(_: T, u: U) -> Two { u } diff --git a/src/test/ui/existential_types/generic_duplicate_param_use3.stderr b/src/test/ui/existential_types/generic_duplicate_param_use3.stderr deleted file mode 100644 index 67c30ad648b35..0000000000000 --- a/src/test/ui/existential_types/generic_duplicate_param_use3.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error: defining existential type use differs from previous - --> $DIR/generic_duplicate_param_use3.rs:16:1 - | -LL | / fn three(_: T, u: U) -> Two { -LL | | //~^ ERROR defining existential type use differs from previous -LL | | u -LL | | } - | |_^ - | -note: previous use here - --> $DIR/generic_duplicate_param_use3.rs:8:1 - | -LL | / fn one(t: T) -> Two { -LL | | t -LL | | } - | |_^ - -error: aborting due to previous error - diff --git a/src/test/ui/existential_types/generic_duplicate_param_use4.rs b/src/test/ui/existential_types/generic_duplicate_param_use4.rs index 79df528d209c6..afab86c3ff075 100644 --- a/src/test/ui/existential_types/generic_duplicate_param_use4.rs +++ b/src/test/ui/existential_types/generic_duplicate_param_use4.rs @@ -1,15 +1,17 @@ +// compile-pass #![feature(existential_type)] +use std::fmt::Debug; + fn main() {} // test that unused generic parameters are ok -existential type Two: 'static; +existential type Two: Debug; -fn one(t: T) -> Two { +fn one(t: T) -> Two { t } -fn three(_: T, u: U) -> Two { -//~^ ERROR defining existential type use differs from previous +fn three(_: T, u: U) -> Two { u } diff --git a/src/test/ui/existential_types/generic_duplicate_param_use4.stderr b/src/test/ui/existential_types/generic_duplicate_param_use4.stderr deleted file mode 100644 index e7a372e0e0c9b..0000000000000 --- a/src/test/ui/existential_types/generic_duplicate_param_use4.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error: defining existential type use differs from previous - --> $DIR/generic_duplicate_param_use4.rs:12:1 - | -LL | / fn three(_: T, u: U) -> Two { -LL | | //~^ ERROR defining existential type use differs from previous -LL | | u -LL | | } - | |_^ - | -note: previous use here - --> $DIR/generic_duplicate_param_use4.rs:8:1 - | -LL | / fn one(t: T) -> Two { -LL | | t -LL | | } - | |_^ - -error: aborting due to previous error - diff --git a/src/test/ui/existential_types/generic_duplicate_param_use5.rs b/src/test/ui/existential_types/generic_duplicate_param_use5.rs deleted file mode 100644 index f9d336d759b62..0000000000000 --- a/src/test/ui/existential_types/generic_duplicate_param_use5.rs +++ /dev/null @@ -1,15 +0,0 @@ -#![feature(existential_type)] - -fn main() {} - -// test that unused generic parameters are ok -existential type Two: 'static; - -fn one(t: T) -> Two { - t -} - -fn two(t: T, _: U) -> Two { -//~^ ERROR defining existential type use differs from previous - t -} diff --git a/src/test/ui/existential_types/generic_duplicate_param_use5.stderr b/src/test/ui/existential_types/generic_duplicate_param_use5.stderr deleted file mode 100644 index e2bf4a9e0dfef..0000000000000 --- a/src/test/ui/existential_types/generic_duplicate_param_use5.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error: defining existential type use differs from previous - --> $DIR/generic_duplicate_param_use5.rs:12:1 - | -LL | / fn two(t: T, _: U) -> Two { -LL | | //~^ ERROR defining existential type use differs from previous -LL | | t -LL | | } - | |_^ - | -note: previous use here - --> $DIR/generic_duplicate_param_use5.rs:8:1 - | -LL | / fn one(t: T) -> Two { -LL | | t -LL | | } - | |_^ - -error: aborting due to previous error - From 6f83dcc192e989eba6f4e531f4931ae057e62f9e Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 29 Jan 2019 16:33:53 +0100 Subject: [PATCH 06/10] Restrict concrete types to equivalent types --- src/librustc/ich/impls_ty.rs | 5 ++ src/librustc/infer/opaque_types/mod.rs | 2 +- src/librustc/ty/context.rs | 13 +++- src/librustc/ty/mod.rs | 2 +- src/librustc_typeck/check/writeback.rs | 12 ++- src/librustc_typeck/collect.rs | 74 ++++++++++++++++--- .../different_defining_uses.rs | 2 +- .../different_defining_uses.stderr | 4 +- .../different_defining_uses_never_type.rs | 4 +- .../different_defining_uses_never_type.stderr | 8 +- .../generic_different_defining_uses.rs | 2 +- .../generic_different_defining_uses.stderr | 4 +- .../generic_duplicate_param_use.rs | 3 +- .../generic_duplicate_param_use.stderr | 17 +++++ .../generic_duplicate_param_use2.rs | 2 +- .../generic_duplicate_param_use2.stderr | 11 +++ .../generic_duplicate_param_use3.rs | 3 +- .../generic_duplicate_param_use3.stderr | 28 +++++++ .../generic_duplicate_param_use4.rs | 2 +- .../generic_duplicate_param_use4.stderr | 11 +++ .../generic_duplicate_param_use5.rs | 17 +++++ .../generic_duplicate_param_use5.stderr | 19 +++++ .../generic_duplicate_param_use6.rs | 17 +++++ .../generic_duplicate_param_use6.stderr | 19 +++++ .../generic_duplicate_param_use7.rs | 16 ++++ 25 files changed, 264 insertions(+), 33 deletions(-) create mode 100644 src/test/ui/existential_types/generic_duplicate_param_use.stderr create mode 100644 src/test/ui/existential_types/generic_duplicate_param_use2.stderr create mode 100644 src/test/ui/existential_types/generic_duplicate_param_use3.stderr create mode 100644 src/test/ui/existential_types/generic_duplicate_param_use4.stderr create mode 100644 src/test/ui/existential_types/generic_duplicate_param_use5.rs create mode 100644 src/test/ui/existential_types/generic_duplicate_param_use5.stderr create mode 100644 src/test/ui/existential_types/generic_duplicate_param_use6.rs create mode 100644 src/test/ui/existential_types/generic_duplicate_param_use6.stderr create mode 100644 src/test/ui/existential_types/generic_duplicate_param_use7.rs diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index bd2349161f74a..040494a279941 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -233,6 +233,11 @@ impl_stable_hash_for!(struct ty::FnSig<'tcx> { abi }); +impl_stable_hash_for!(struct ty::ResolvedOpaqueTy<'tcx> { + concrete_type, + substs +}); + impl<'a, 'gcx, T> HashStable> for ty::Binder where T: HashStable> { diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs index 5e94bb1f877fb..eabbb943c6ef2 100644 --- a/src/librustc/infer/opaque_types/mod.rs +++ b/src/librustc/infer/opaque_types/mod.rs @@ -26,7 +26,7 @@ pub struct OpaqueTypeDecl<'tcx> { /// /// winds up desugared to: /// - /// abstract type Foo<'x, T>: Trait<'x> + /// abstract type Foo<'x, X>: Trait<'x> /// fn foo<'a, 'b, T>() -> Foo<'a, T> /// /// then `substs` would be `['a, T]`. diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 881c0d4e6d239..350dcdf571be3 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -315,6 +315,17 @@ impl<'a, V> LocalTableInContextMut<'a, V> { } } +/// All information necessary to validate and reveal an `impl Trait` or `existential Type` +#[derive(RustcEncodable, RustcDecodable, Debug)] +pub struct ResolvedOpaqueTy<'tcx> { + /// The revealed type as seen by this function. + pub concrete_type: Ty<'tcx>, + /// Generic parameters on the opaque type as passed by this function. + /// For `existential type Foo; fn foo() -> Foo { .. }` this is `[T, U]`, not + /// `[A, B]` + pub substs: &'tcx Substs<'tcx>, +} + #[derive(RustcEncodable, RustcDecodable, Debug)] pub struct TypeckTables<'tcx> { /// The HirId::owner all ItemLocalIds in this table are relative to. @@ -417,7 +428,7 @@ pub struct TypeckTables<'tcx> { /// All the existential types that are restricted to concrete types /// by this function - pub concrete_existential_types: FxHashMap>, + pub concrete_existential_types: FxHashMap>, /// Given the closure ID this map provides the list of UpvarIDs used by it. /// The upvarID contains the HIR node ID and it also contains the full path diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index c9089428b2324..3a7441e9215df 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -74,7 +74,7 @@ pub use self::context::{TyCtxt, FreeRegionInfo, GlobalArenas, AllArenas, tls, ke pub use self::context::{Lift, TypeckTables, CtxtInterners}; pub use self::context::{ UserTypeAnnotationIndex, UserType, CanonicalUserType, - CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, + CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, ResolvedOpaqueTy, }; pub use self::instance::{Instance, InstanceDef}; diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 00917be538fb3..c9dd83dcd5e22 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -567,17 +567,23 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } } + let new = ty::ResolvedOpaqueTy { + concrete_type: definition_ty, + substs: self.tcx().lift_to_global(&opaque_defn.substs).unwrap(), + }; + let old = self.tables .concrete_existential_types - .insert(def_id, definition_ty); + .insert(def_id, new); if let Some(old) = old { - if old != definition_ty { + if old.concrete_type != definition_ty || old.substs != opaque_defn.substs { span_bug!( span, "visit_opaque_types tried to write \ - different types for the same existential type: {:?}, {:?}, {:?}", + different types for the same existential type: {:?}, {:?}, {:?}, {:?}", def_id, definition_ty, + opaque_defn, old, ); } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index e4fc1925eb377..7cdcfec339eee 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -23,9 +23,10 @@ use middle::resolve_lifetime as rl; use middle::weak_lang_items; use rustc::mir::mono::Linkage; use rustc::ty::query::Providers; -use rustc::ty::subst::Substs; +use rustc::ty::subst::{Subst, Substs}; use rustc::ty::util::Discr; use rustc::ty::util::IntTypeExt; +use rustc::ty::subst::UnpackedKind; use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt}; use rustc::ty::{ReprOptions, ToPredicate}; use rustc::util::captures::Captures; @@ -1193,7 +1194,7 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Ty<'tcx> { tcx.typeck_tables_of(owner) .concrete_existential_types .get(&def_id) - .cloned() + .map(|opaque| opaque.concrete_type) .unwrap_or_else(|| { // This can occur if some error in the // owner fn prevented us from populating @@ -1325,7 +1326,13 @@ fn find_existential_constraints<'a, 'tcx>( struct ConstraintLocator<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, - found: Option<(Span, ty::Ty<'tcx>)>, + // First found type span, actual type, mapping from the existential type's generic + // parameters to the concrete type's generic parameters + // + // The mapping is an index for each use site of a generic parameter in the concrete type + // + // The indices index into the generic parameters on the existential type. + found: Option<(Span, ty::Ty<'tcx>, Vec)>, } impl<'a, 'tcx> ConstraintLocator<'a, 'tcx> { @@ -1340,13 +1347,50 @@ fn find_existential_constraints<'a, 'tcx>( .tcx .typeck_tables_of(def_id) .concrete_existential_types - .get(&self.def_id) - .cloned(); - if let Some(ty) = ty { + .get(&self.def_id); + if let Some(ty::ResolvedOpaqueTy { concrete_type, substs }) = ty { // FIXME(oli-obk): trace the actual span from inference to improve errors let span = self.tcx.def_span(def_id); - if let Some((prev_span, prev_ty)) = self.found { - let mut ty = ty.walk().fuse(); + // used to quickly look up the position of a generic parameter + let mut index_map: FxHashMap = FxHashMap::default(); + // skip binder is ok, since we only use this to find generic parameters and their + // positions. + for subst in substs.iter() { + if let UnpackedKind::Type(ty) = subst.unpack() { + if let ty::Param(p) = ty.sty { + let idx = index_map.len(); + if index_map.insert(p, idx).is_some() { + // there was already an entry for `p`, meaning a generic parameter + // was used twice + self.tcx.sess.span_err( + span, + &format!("defining existential type use restricts existential \ + type by using the generic parameter `{}` twice", p.name), + ); + return; + } + } else { + self.tcx.sess.delay_span_bug( + span, + &format!( + "non-defining exist ty use in defining scope: {:?}, {:?}", + concrete_type, substs, + ), + ); + } + } + } + // compute the index within the existential type for each generic parameter used in + // the concrete type + let indices = concrete_type + .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 { + let mut ty = concrete_type.walk().fuse(); let mut prev_ty = prev_ty.walk().fuse(); let iter_eq = (&mut ty).zip(&mut prev_ty).all(|(t, p)| match (&t.sty, &p.sty) { // type parameters are equal to any other type parameter for the purpose of @@ -1359,13 +1403,21 @@ fn find_existential_constraints<'a, 'tcx>( // found different concrete types for the existential type let mut err = self.tcx.sess.struct_span_err( span, - "defining existential type use differs from previous", + "concrete type differs from previous defining existential type use", + ); + err.span_note(prev_span, "previous use here"); + err.emit(); + } else if indices != *prev_indices { + // found "same" concrete types, but the generic parameter order differs + let mut err = self.tcx.sess.struct_span_err( + span, + "concrete type's generic parameters differ from previous defining use", ); err.span_note(prev_span, "previous use here"); err.emit(); } } else { - self.found = Some((span, ty)); + self.found = Some((span, concrete_type, indices)); } } } @@ -1424,7 +1476,7 @@ fn find_existential_constraints<'a, 'tcx>( } match locator.found { - Some((_, ty)) => ty, + Some((_, ty, _)) => ty, None => { let span = tcx.def_span(def_id); tcx.sess.span_err(span, "could not find defining uses"); diff --git a/src/test/ui/existential_types/different_defining_uses.rs b/src/test/ui/existential_types/different_defining_uses.rs index c51fca75a24e9..a8670cc07f2e1 100644 --- a/src/test/ui/existential_types/different_defining_uses.rs +++ b/src/test/ui/existential_types/different_defining_uses.rs @@ -9,6 +9,6 @@ fn foo() -> Foo { "" } -fn bar() -> Foo { //~ ERROR defining existential type use differs from previous +fn bar() -> Foo { //~ ERROR concrete type differs from previous 42i32 } diff --git a/src/test/ui/existential_types/different_defining_uses.stderr b/src/test/ui/existential_types/different_defining_uses.stderr index f782a00229732..3b3449bbf11f4 100644 --- a/src/test/ui/existential_types/different_defining_uses.stderr +++ b/src/test/ui/existential_types/different_defining_uses.stderr @@ -1,7 +1,7 @@ -error: defining existential type use differs from previous +error: concrete type differs from previous defining existential type use --> $DIR/different_defining_uses.rs:12:1 | -LL | / fn bar() -> Foo { //~ ERROR defining existential type use differs from previous +LL | / fn bar() -> Foo { //~ ERROR concrete type differs from previous LL | | 42i32 LL | | } | |_^ diff --git a/src/test/ui/existential_types/different_defining_uses_never_type.rs b/src/test/ui/existential_types/different_defining_uses_never_type.rs index c6c6ae8d2dccf..13ada63e4bc45 100644 --- a/src/test/ui/existential_types/different_defining_uses_never_type.rs +++ b/src/test/ui/existential_types/different_defining_uses_never_type.rs @@ -9,10 +9,10 @@ fn foo() -> Foo { "" } -fn bar() -> Foo { //~ ERROR defining existential type use differs from previous +fn bar() -> Foo { //~ ERROR concrete type differs from previous panic!() } -fn boo() -> Foo { //~ ERROR defining existential type use differs from previous +fn boo() -> Foo { //~ ERROR concrete type differs from previous loop {} } diff --git a/src/test/ui/existential_types/different_defining_uses_never_type.stderr b/src/test/ui/existential_types/different_defining_uses_never_type.stderr index 04b0cf2778455..161111e3379f5 100644 --- a/src/test/ui/existential_types/different_defining_uses_never_type.stderr +++ b/src/test/ui/existential_types/different_defining_uses_never_type.stderr @@ -1,7 +1,7 @@ -error: defining existential type use differs from previous +error: concrete type differs from previous defining existential type use --> $DIR/different_defining_uses_never_type.rs:12:1 | -LL | / fn bar() -> Foo { //~ ERROR defining existential type use differs from previous +LL | / fn bar() -> Foo { //~ ERROR concrete type differs from previous LL | | panic!() LL | | } | |_^ @@ -14,10 +14,10 @@ LL | | "" LL | | } | |_^ -error: defining existential type use differs from previous +error: concrete type differs from previous defining existential type use --> $DIR/different_defining_uses_never_type.rs:16:1 | -LL | / fn boo() -> Foo { //~ ERROR defining existential type use differs from previous +LL | / fn boo() -> Foo { //~ ERROR concrete type differs from previous LL | | loop {} LL | | } | |_^ diff --git a/src/test/ui/existential_types/generic_different_defining_uses.rs b/src/test/ui/existential_types/generic_different_defining_uses.rs index 3bd104251fb70..ce3ab88a1c0bb 100644 --- a/src/test/ui/existential_types/generic_different_defining_uses.rs +++ b/src/test/ui/existential_types/generic_different_defining_uses.rs @@ -8,6 +8,6 @@ fn my_iter(t: T) -> MyIter { std::iter::once(t) } -fn my_iter2(t: T) -> MyIter { //~ ERROR defining existential type use differs from previous +fn my_iter2(t: T) -> MyIter { //~ ERROR concrete type differs from previous Some(t).into_iter() } diff --git a/src/test/ui/existential_types/generic_different_defining_uses.stderr b/src/test/ui/existential_types/generic_different_defining_uses.stderr index 234bcf232ae79..89f70a873d9dc 100644 --- a/src/test/ui/existential_types/generic_different_defining_uses.stderr +++ b/src/test/ui/existential_types/generic_different_defining_uses.stderr @@ -1,7 +1,7 @@ -error: defining existential type use differs from previous +error: concrete type differs from previous defining existential type use --> $DIR/generic_different_defining_uses.rs:11:1 | -LL | / fn my_iter2(t: T) -> MyIter { //~ ERROR defining existential type use differs from previous +LL | / fn my_iter2(t: T) -> MyIter { //~ ERROR concrete type differs from previous LL | | Some(t).into_iter() LL | | } | |_^ diff --git a/src/test/ui/existential_types/generic_duplicate_param_use.rs b/src/test/ui/existential_types/generic_duplicate_param_use.rs index d08cd88c600d0..3f8753333aa7a 100644 --- a/src/test/ui/existential_types/generic_duplicate_param_use.rs +++ b/src/test/ui/existential_types/generic_duplicate_param_use.rs @@ -1,4 +1,3 @@ -// compile-pass #![feature(existential_type)] use std::fmt::Debug; @@ -7,7 +6,9 @@ fn main() {} // test that unused generic parameters are ok existential type Two: Debug; +//~^ could not find defining uses fn one(t: T) -> Two { +//~^ ERROR defining existential type use restricts existential type t } diff --git a/src/test/ui/existential_types/generic_duplicate_param_use.stderr b/src/test/ui/existential_types/generic_duplicate_param_use.stderr new file mode 100644 index 0000000000000..d4deda999da16 --- /dev/null +++ b/src/test/ui/existential_types/generic_duplicate_param_use.stderr @@ -0,0 +1,17 @@ +error: defining existential type use restricts existential type by using the generic parameter `T` twice + --> $DIR/generic_duplicate_param_use.rs:11:1 + | +LL | / fn one(t: T) -> Two { +LL | | //~^ ERROR defining existential type use restricts existential type +LL | | t +LL | | } + | |_^ + +error: could not find defining uses + --> $DIR/generic_duplicate_param_use.rs:8:1 + | +LL | existential type Two: Debug; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/existential_types/generic_duplicate_param_use2.rs b/src/test/ui/existential_types/generic_duplicate_param_use2.rs index c27fbb74cf19d..3842292decd57 100644 --- a/src/test/ui/existential_types/generic_duplicate_param_use2.rs +++ b/src/test/ui/existential_types/generic_duplicate_param_use2.rs @@ -1,4 +1,3 @@ -// compile-pass #![feature(existential_type)] use std::fmt::Debug; @@ -9,6 +8,7 @@ fn main() {} existential type Two: Debug; fn one(t: T) -> Two { +//~^ defining existential type use restricts existential type t } diff --git a/src/test/ui/existential_types/generic_duplicate_param_use2.stderr b/src/test/ui/existential_types/generic_duplicate_param_use2.stderr new file mode 100644 index 0000000000000..0a8be3218c759 --- /dev/null +++ b/src/test/ui/existential_types/generic_duplicate_param_use2.stderr @@ -0,0 +1,11 @@ +error: defining existential type use restricts existential type by using the generic parameter `T` twice + --> $DIR/generic_duplicate_param_use2.rs:10:1 + | +LL | / fn one(t: T) -> Two { +LL | | //~^ defining existential type use restricts existential type +LL | | t +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/existential_types/generic_duplicate_param_use3.rs b/src/test/ui/existential_types/generic_duplicate_param_use3.rs index b4d1b26dbabda..05c77c8947333 100644 --- a/src/test/ui/existential_types/generic_duplicate_param_use3.rs +++ b/src/test/ui/existential_types/generic_duplicate_param_use3.rs @@ -1,4 +1,3 @@ -// compile-pass #![feature(existential_type)] use std::fmt::Debug; @@ -9,6 +8,7 @@ fn main() {} existential type Two: Debug; fn one(t: T) -> Two { +//~^ defining existential type use restricts existential type t } @@ -17,5 +17,6 @@ fn two(t: T, _: U) -> Two { } fn three(_: T, u: U) -> Two { +//~^ concrete type's generic parameters differ from previous defining use u } diff --git a/src/test/ui/existential_types/generic_duplicate_param_use3.stderr b/src/test/ui/existential_types/generic_duplicate_param_use3.stderr new file mode 100644 index 0000000000000..8f860e7ee0a40 --- /dev/null +++ b/src/test/ui/existential_types/generic_duplicate_param_use3.stderr @@ -0,0 +1,28 @@ +error: defining existential type use restricts existential type by using the generic parameter `T` twice + --> $DIR/generic_duplicate_param_use3.rs:10:1 + | +LL | / fn one(t: T) -> Two { +LL | | //~^ defining existential type use restricts existential type +LL | | t +LL | | } + | |_^ + +error: concrete type's generic parameters differ from previous defining use + --> $DIR/generic_duplicate_param_use3.rs:19:1 + | +LL | / fn three(_: T, u: U) -> Two { +LL | | //~^ concrete type's generic parameters differ from previous defining use +LL | | u +LL | | } + | |_^ + | +note: previous use here + --> $DIR/generic_duplicate_param_use3.rs:15:1 + | +LL | / fn two(t: T, _: U) -> Two { +LL | | t +LL | | } + | |_^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/existential_types/generic_duplicate_param_use4.rs b/src/test/ui/existential_types/generic_duplicate_param_use4.rs index afab86c3ff075..609dbe06cd733 100644 --- a/src/test/ui/existential_types/generic_duplicate_param_use4.rs +++ b/src/test/ui/existential_types/generic_duplicate_param_use4.rs @@ -1,4 +1,3 @@ -// compile-pass #![feature(existential_type)] use std::fmt::Debug; @@ -9,6 +8,7 @@ fn main() {} existential type Two: Debug; fn one(t: T) -> Two { +//~^ ERROR defining existential type use restricts existential type t } diff --git a/src/test/ui/existential_types/generic_duplicate_param_use4.stderr b/src/test/ui/existential_types/generic_duplicate_param_use4.stderr new file mode 100644 index 0000000000000..24b1caf7c1bfe --- /dev/null +++ b/src/test/ui/existential_types/generic_duplicate_param_use4.stderr @@ -0,0 +1,11 @@ +error: defining existential type use restricts existential type by using the generic parameter `T` twice + --> $DIR/generic_duplicate_param_use4.rs:10:1 + | +LL | / fn one(t: T) -> Two { +LL | | //~^ ERROR defining existential type use restricts existential type +LL | | t +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/existential_types/generic_duplicate_param_use5.rs b/src/test/ui/existential_types/generic_duplicate_param_use5.rs new file mode 100644 index 0000000000000..3f4a23b8b41fa --- /dev/null +++ b/src/test/ui/existential_types/generic_duplicate_param_use5.rs @@ -0,0 +1,17 @@ +#![feature(existential_type)] + +use std::fmt::Debug; + +fn main() {} + +// test that unused generic parameters are ok +existential type Two: Debug; + +fn two(t: T, u: U) -> Two { + (t, u) +} + +fn three(t: T, u: U) -> Two { +//~^ concrete type differs from previous + (u, t) +} diff --git a/src/test/ui/existential_types/generic_duplicate_param_use5.stderr b/src/test/ui/existential_types/generic_duplicate_param_use5.stderr new file mode 100644 index 0000000000000..52befb9c2e12c --- /dev/null +++ b/src/test/ui/existential_types/generic_duplicate_param_use5.stderr @@ -0,0 +1,19 @@ +error: concrete type differs from previous defining existential type use + --> $DIR/generic_duplicate_param_use5.rs:14:1 + | +LL | / fn three(t: T, u: U) -> Two { +LL | | //~^ concrete type differs from previous +LL | | (u, t) +LL | | } + | |_^ + | +note: previous use here + --> $DIR/generic_duplicate_param_use5.rs:10:1 + | +LL | / fn two(t: T, u: U) -> Two { +LL | | (t, u) +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/existential_types/generic_duplicate_param_use6.rs b/src/test/ui/existential_types/generic_duplicate_param_use6.rs new file mode 100644 index 0000000000000..3b8c56352bda4 --- /dev/null +++ b/src/test/ui/existential_types/generic_duplicate_param_use6.rs @@ -0,0 +1,17 @@ +#![feature(existential_type)] + +use std::fmt::Debug; + +fn main() {} + +// test that unused generic parameters are ok +existential type Two: Debug; + +fn two(t: T, u: U) -> Two { + (t, t) +} + +fn three(t: T, u: U) -> Two { +//~^ concrete type differs from previous + (u, t) +} diff --git a/src/test/ui/existential_types/generic_duplicate_param_use6.stderr b/src/test/ui/existential_types/generic_duplicate_param_use6.stderr new file mode 100644 index 0000000000000..2bf1d0c05e625 --- /dev/null +++ b/src/test/ui/existential_types/generic_duplicate_param_use6.stderr @@ -0,0 +1,19 @@ +error: concrete type differs from previous defining existential type use + --> $DIR/generic_duplicate_param_use6.rs:14:1 + | +LL | / fn three(t: T, u: U) -> Two { +LL | | //~^ concrete type differs from previous +LL | | (u, t) +LL | | } + | |_^ + | +note: previous use here + --> $DIR/generic_duplicate_param_use6.rs:10:1 + | +LL | / fn two(t: T, u: U) -> Two { +LL | | (t, t) +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/existential_types/generic_duplicate_param_use7.rs b/src/test/ui/existential_types/generic_duplicate_param_use7.rs new file mode 100644 index 0000000000000..3906b85aadbde --- /dev/null +++ b/src/test/ui/existential_types/generic_duplicate_param_use7.rs @@ -0,0 +1,16 @@ +// compile-pass +#![feature(existential_type)] + +use std::fmt::Debug; + +fn main() {} + +existential type Two: Debug; + +fn two(t: T, u: U) -> Two { + (t, t) +} + +fn three(t: T, t2: T, u: U) -> Two { + (t, t2) +} From 984688ace34ec0add8f365ead6587237537fc230 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 29 Jan 2019 16:36:46 +0100 Subject: [PATCH 07/10] Test more related cases --- .../ui/existential_types/generic_duplicate_param_use7.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/test/ui/existential_types/generic_duplicate_param_use7.rs b/src/test/ui/existential_types/generic_duplicate_param_use7.rs index 3906b85aadbde..2bcac315f5a96 100644 --- a/src/test/ui/existential_types/generic_duplicate_param_use7.rs +++ b/src/test/ui/existential_types/generic_duplicate_param_use7.rs @@ -14,3 +14,12 @@ fn two(t: T, u: U) -> Two { fn three(t: T, t2: T, u: U) -> Two { (t, t2) } + +fn four(t: T, t2: T, u: U, v: V) -> Two { + (t, t2) +} + +fn five(x: X, y: Y, y2: Y) -> Two { + (y, y2) +} + From f2241f640bb9f04cce88b2d28092cbfcee04c43e Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 29 Jan 2019 17:10:08 +0100 Subject: [PATCH 08/10] Make the existential type errors a little bit more helpful --- src/librustc_typeck/collect.rs | 30 +++++++++++++++---- .../different_defining_uses.stderr | 2 +- .../different_defining_uses_never_type.stderr | 4 +-- .../generic_different_defining_uses.stderr | 2 +- .../generic_duplicate_param_use3.stderr | 2 +- .../generic_duplicate_param_use5.stderr | 2 +- .../generic_duplicate_param_use6.stderr | 2 +- 7 files changed, 32 insertions(+), 12 deletions(-) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 7cdcfec339eee..b26a6a2292a04 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1355,10 +1355,9 @@ fn find_existential_constraints<'a, 'tcx>( let mut index_map: FxHashMap = FxHashMap::default(); // skip binder is ok, since we only use this to find generic parameters and their // positions. - for subst in substs.iter() { + for (idx, subst) in substs.iter().enumerate() { if let UnpackedKind::Type(ty) = subst.unpack() { if let ty::Param(p) = ty.sty { - let idx = index_map.len(); if index_map.insert(p, idx).is_some() { // there was already an entry for `p`, meaning a generic parameter // was used twice @@ -1391,20 +1390,24 @@ fn find_existential_constraints<'a, 'tcx>( }).collect(); if let Some((prev_span, prev_ty, ref prev_indices)) = self.found { let mut ty = concrete_type.walk().fuse(); - let mut prev_ty = prev_ty.walk().fuse(); - let iter_eq = (&mut ty).zip(&mut prev_ty).all(|(t, p)| match (&t.sty, &p.sty) { + 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) { // type parameters are equal to any other type parameter for the purpose of // concrete type equality, as it is possible to obtain the same type just // by passing matching parameters to a function. (ty::Param(_), ty::Param(_)) => true, _ => t == p, }); - if !iter_eq || ty.next().is_some() || prev_ty.next().is_some() { + if !iter_eq || ty.next().is_some() || p_ty.next().is_some() { // found different concrete types for the existential type let mut err = self.tcx.sess.struct_span_err( span, "concrete type differs from previous defining existential type use", ); + err.span_label( + span, + format!("expected `{}`, got `{}`", prev_ty, concrete_type), + ); err.span_note(prev_span, "previous use here"); err.emit(); } else if indices != *prev_indices { @@ -1413,6 +1416,23 @@ fn find_existential_constraints<'a, 'tcx>( span, "concrete type's generic parameters differ from previous defining use", ); + use std::fmt::Write; + let mut s = String::new(); + write!(s, "expected [").unwrap(); + let list = |s: &mut String, indices: &Vec| { + let mut indices = indices.iter().cloned(); + if let Some(first) = indices.next() { + write!(s, "`{}`", substs[first]).unwrap(); + for i in indices { + write!(s, ", `{}`", substs[i]).unwrap(); + } + } + }; + list(&mut s, prev_indices); + write!(s, "], got [").unwrap(); + list(&mut s, &indices); + write!(s, "]").unwrap(); + err.span_label(span, s); err.span_note(prev_span, "previous use here"); err.emit(); } diff --git a/src/test/ui/existential_types/different_defining_uses.stderr b/src/test/ui/existential_types/different_defining_uses.stderr index 3b3449bbf11f4..3f9ed96400b54 100644 --- a/src/test/ui/existential_types/different_defining_uses.stderr +++ b/src/test/ui/existential_types/different_defining_uses.stderr @@ -4,7 +4,7 @@ error: concrete type differs from previous defining existential type use LL | / fn bar() -> Foo { //~ ERROR concrete type differs from previous LL | | 42i32 LL | | } - | |_^ + | |_^ expected `&'static str`, got `i32` | note: previous use here --> $DIR/different_defining_uses.rs:8:1 diff --git a/src/test/ui/existential_types/different_defining_uses_never_type.stderr b/src/test/ui/existential_types/different_defining_uses_never_type.stderr index 161111e3379f5..e29256a5014f9 100644 --- a/src/test/ui/existential_types/different_defining_uses_never_type.stderr +++ b/src/test/ui/existential_types/different_defining_uses_never_type.stderr @@ -4,7 +4,7 @@ error: concrete type differs from previous defining existential type use LL | / fn bar() -> Foo { //~ ERROR concrete type differs from previous LL | | panic!() LL | | } - | |_^ + | |_^ expected `&'static str`, got `()` | note: previous use here --> $DIR/different_defining_uses_never_type.rs:8:1 @@ -20,7 +20,7 @@ error: concrete type differs from previous defining existential type use LL | / fn boo() -> Foo { //~ ERROR concrete type differs from previous LL | | loop {} LL | | } - | |_^ + | |_^ expected `&'static str`, got `()` | note: previous use here --> $DIR/different_defining_uses_never_type.rs:8:1 diff --git a/src/test/ui/existential_types/generic_different_defining_uses.stderr b/src/test/ui/existential_types/generic_different_defining_uses.stderr index 89f70a873d9dc..3f129658b8fd0 100644 --- a/src/test/ui/existential_types/generic_different_defining_uses.stderr +++ b/src/test/ui/existential_types/generic_different_defining_uses.stderr @@ -4,7 +4,7 @@ error: concrete type differs from previous defining existential type use LL | / fn my_iter2(t: T) -> MyIter { //~ ERROR concrete type differs from previous LL | | Some(t).into_iter() LL | | } - | |_^ + | |_^ expected `std::iter::Once`, got `std::option::IntoIter` | note: previous use here --> $DIR/generic_different_defining_uses.rs:7:1 diff --git a/src/test/ui/existential_types/generic_duplicate_param_use3.stderr b/src/test/ui/existential_types/generic_duplicate_param_use3.stderr index 8f860e7ee0a40..1c96c15a76919 100644 --- a/src/test/ui/existential_types/generic_duplicate_param_use3.stderr +++ b/src/test/ui/existential_types/generic_duplicate_param_use3.stderr @@ -14,7 +14,7 @@ LL | / fn three(_: T, u: U) -> Two { LL | | //~^ concrete type's generic parameters differ from previous defining use LL | | u LL | | } - | |_^ + | |_^ expected [`T`], got [`U`] | note: previous use here --> $DIR/generic_duplicate_param_use3.rs:15:1 diff --git a/src/test/ui/existential_types/generic_duplicate_param_use5.stderr b/src/test/ui/existential_types/generic_duplicate_param_use5.stderr index 52befb9c2e12c..166623801c246 100644 --- a/src/test/ui/existential_types/generic_duplicate_param_use5.stderr +++ b/src/test/ui/existential_types/generic_duplicate_param_use5.stderr @@ -5,7 +5,7 @@ LL | / fn three(t: T, u: U) -> Two { LL | | //~^ concrete type differs from previous LL | | (u, t) LL | | } - | |_^ + | |_^ expected `(T, U)`, got `(U, T)` | note: previous use here --> $DIR/generic_duplicate_param_use5.rs:10:1 diff --git a/src/test/ui/existential_types/generic_duplicate_param_use6.stderr b/src/test/ui/existential_types/generic_duplicate_param_use6.stderr index 2bf1d0c05e625..da49a83be1f70 100644 --- a/src/test/ui/existential_types/generic_duplicate_param_use6.stderr +++ b/src/test/ui/existential_types/generic_duplicate_param_use6.stderr @@ -5,7 +5,7 @@ LL | / fn three(t: T, u: U) -> Two { LL | | //~^ concrete type differs from previous LL | | (u, t) LL | | } - | |_^ + | |_^ expected `(T, T)`, got `(U, T)` | note: previous use here --> $DIR/generic_duplicate_param_use6.rs:10:1 From c93bce85e5e085274febf1ca71b551de3f51429c Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 5 Feb 2019 14:18:09 +0100 Subject: [PATCH 09/10] Add more tests --- .../generic_duplicate_param_use8.rs | 16 ++++++++ .../generic_duplicate_param_use8.stderr | 19 +++++++++ .../existential_types/not_a_defining_use.rs | 39 +++++++++++++++++++ .../not_a_defining_use.stderr | 18 +++++++++ 4 files changed, 92 insertions(+) create mode 100644 src/test/ui/existential_types/generic_duplicate_param_use8.rs create mode 100644 src/test/ui/existential_types/generic_duplicate_param_use8.stderr create mode 100644 src/test/ui/existential_types/not_a_defining_use.rs create mode 100644 src/test/ui/existential_types/not_a_defining_use.stderr diff --git a/src/test/ui/existential_types/generic_duplicate_param_use8.rs b/src/test/ui/existential_types/generic_duplicate_param_use8.rs new file mode 100644 index 0000000000000..83501ad8c41a7 --- /dev/null +++ b/src/test/ui/existential_types/generic_duplicate_param_use8.rs @@ -0,0 +1,16 @@ +#![feature(existential_type)] + +use std::fmt::Debug; + +fn main() {} + +existential type Two: Debug; + +fn two(t: T, _: U) -> Two { + (t, 4u32) +} + +fn three(_: T, u: U) -> Two { +//~^ concrete type differs from previous + (u, 4u32) +} diff --git a/src/test/ui/existential_types/generic_duplicate_param_use8.stderr b/src/test/ui/existential_types/generic_duplicate_param_use8.stderr new file mode 100644 index 0000000000000..80c7441c857d1 --- /dev/null +++ b/src/test/ui/existential_types/generic_duplicate_param_use8.stderr @@ -0,0 +1,19 @@ +error: concrete type differs from previous defining existential type use + --> $DIR/generic_duplicate_param_use8.rs:13:1 + | +LL | / fn three(_: T, u: U) -> Two { +LL | | //~^ concrete type differs from previous +LL | | (u, 4u32) +LL | | } + | |_^ expected `(T, u32)`, got `(U, u32)` + | +note: previous use here + --> $DIR/generic_duplicate_param_use8.rs:9:1 + | +LL | / fn two(t: T, _: U) -> Two { +LL | | (t, 4u32) +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/existential_types/not_a_defining_use.rs b/src/test/ui/existential_types/not_a_defining_use.rs new file mode 100644 index 0000000000000..413cc6788c281 --- /dev/null +++ b/src/test/ui/existential_types/not_a_defining_use.rs @@ -0,0 +1,39 @@ +#![feature(existential_type)] + +use std::fmt::Debug; + +fn main() {} + +existential type Two: Debug; + +fn two(t: T) -> Two { + (t, 4i8) +} + +fn three(t: T) -> Two { + (t, 5i8) +} + +trait Bar { + type Blub: Debug; + const FOO: Self::Blub; +} + +impl Bar for u32 { + type Blub = i32; + const FOO: i32 = 42; +} + +// this should work! But it requires `two` and `three` not to be defining uses, +// just restricting uses +fn four(t: T) -> Two { //~ concrete type differs from previous + (t, ::FOO) +} + +fn is_sync() {} + +fn asdfl() { + //FIXME(oli-obk): these currently cause cycle errors + //is_sync::>(); + //is_sync::>(); +} diff --git a/src/test/ui/existential_types/not_a_defining_use.stderr b/src/test/ui/existential_types/not_a_defining_use.stderr new file mode 100644 index 0000000000000..a6ed5dbe0a9dd --- /dev/null +++ b/src/test/ui/existential_types/not_a_defining_use.stderr @@ -0,0 +1,18 @@ +error: concrete type differs from previous defining existential type use + --> $DIR/not_a_defining_use.rs:29:1 + | +LL | / fn four(t: T) -> Two { //~ concrete type differs from previous +LL | | (t, ::FOO) +LL | | } + | |_^ expected `(T, i8)`, got `(T, ::Blub)` + | +note: previous use here + --> $DIR/not_a_defining_use.rs:9:1 + | +LL | / fn two(t: T) -> Two { +LL | | (t, 4i8) +LL | | } + | |_^ + +error: aborting due to previous error + From eb98d318b28cc177f608d57fb5b9b017235b515d Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 14 Feb 2019 13:02:36 +0100 Subject: [PATCH 10/10] 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 b26a6a2292a04..b50a165ba9cd0 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 d8ade50c79c82..542e076d88d64 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 8e822ca6d8bc7..f51f1c9a4e563 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 0000000000000..10f2c630582fc --- /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 0000000000000..4c6897298c44f --- /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 0000000000000..a3ce480d66dcd --- /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 caa8f0f2ee1bc..75af5d9570ff2 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 41877791e9ae9..8dd88006be9c6 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 413cc6788c281..3f81f5177d0a4 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 a6ed5dbe0a9dd..288a32fc14edd 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