From 381c5416855f53e130d5156aec5f9067fc981dfa Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 25 Jan 2019 15:04:15 +0100 Subject: Add FIXME --- src/librustc_typeck/check/writeback.rs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 238b087fe32..00917be538f 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); } } -- cgit 1.4.1-3-g733a5 From 6982fd21d1d7963b2acc489d9de246f2715aab80 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 25 Jan 2019 16:14:59 +0100 Subject: Be more permissive with required bounds on existential types --- src/librustc_typeck/check/mod.rs | 3 --- src/test/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(-) (limited to 'src') diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 48475b3dcb8..5390382ee2d 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 380fbdeb8c2..14d63ecc6bb 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 bd7b343b402..7af65087881 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 -- cgit 1.4.1-3-g733a5 From ed10a5ba01cb0e73e3872434da65bf4f3a976f28 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 25 Jan 2019 20:32:45 +0100 Subject: Test all the things --- .../generic_duplicate_param_use.stderr | 9 --------- .../existential_types/generic_duplicate_param_use2.rs | 15 +++++++++++++++ .../existential_types/generic_duplicate_param_use3.rs | 19 +++++++++++++++++++ .../generic_duplicate_param_use3.stderr | 19 +++++++++++++++++++ .../existential_types/generic_duplicate_param_use4.rs | 15 +++++++++++++++ .../generic_duplicate_param_use4.stderr | 19 +++++++++++++++++++ .../ui/existential_types/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 (limited to 'src') 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 66706c21054..00000000000 --- 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 00000000000..b6cb22da41d --- /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 00000000000..43650a6a352 --- /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 00000000000..67c30ad648b --- /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 00000000000..79df528d209 --- /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 00000000000..e7a372e0e0c --- /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 348aed3c439..00000000000 --- 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`. -- cgit 1.4.1-3-g733a5 From 0d25ff8842ca35b7eabd2d8a22669c5b2216ad82 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 25 Jan 2019 20:37:10 +0100 Subject: Test aller things --- .../existential_types/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 (limited to 'src') 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 00000000000..f9d336d759b --- /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 00000000000..e2bf4a9e0df --- /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 + -- cgit 1.4.1-3-g733a5 From cf01b514c876656696e87672a1c118a3ce7817ed Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 25 Jan 2019 22:57:31 +0100 Subject: Generic type parameters are flexible even for existential types --- src/librustc_typeck/collect.rs | 11 ++++++++++- .../existential_types/generic_duplicate_param_use.rs | 6 ++++-- .../existential_types/generic_duplicate_param_use2.rs | 8 +++++--- .../existential_types/generic_duplicate_param_use3.rs | 12 +++++++----- .../generic_duplicate_param_use3.stderr | 19 ------------------- .../existential_types/generic_duplicate_param_use4.rs | 10 ++++++---- .../generic_duplicate_param_use4.stderr | 19 ------------------- .../existential_types/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 (limited to 'src') diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index b0b266a61a5..e4fc1925eb3 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 14d63ecc6bb..d08cd88c600 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 b6cb22da41d..c27fbb74cf1 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 43650a6a352..b4d1b26dbab 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 67c30ad648b..00000000000 --- 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 79df528d209..afab86c3ff0 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 e7a372e0e0c..00000000000 --- 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 f9d336d759b..00000000000 --- 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 e2bf4a9e0df..00000000000 --- 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 - -- cgit 1.4.1-3-g733a5 From 6f83dcc192e989eba6f4e531f4931ae057e62f9e Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 29 Jan 2019 16:33:53 +0100 Subject: 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 ++++++++++++++++++---- .../existential_types/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 (limited to 'src') diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index bd2349161f7..040494a2799 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 5e94bb1f877..eabbb943c6e 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 881c0d4e6d2..350dcdf571b 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 c9089428b23..3a7441e9215 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 00917be538f..c9dd83dcd5e 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 e4fc1925eb3..7cdcfec339e 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 c51fca75a24..a8670cc07f2 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 f782a002297..3b3449bbf11 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 c6c6ae8d2dc..13ada63e4bc 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 04b0cf27784..161111e3379 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 3bd104251fb..ce3ab88a1c0 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 234bcf232ae..89f70a873d9 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 d08cd88c600..3f8753333aa 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 00000000000..d4deda999da --- /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 c27fbb74cf1..3842292decd 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 00000000000..0a8be3218c7 --- /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 b4d1b26dbab..05c77c89473 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 00000000000..8f860e7ee0a --- /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 afab86c3ff0..609dbe06cd7 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 00000000000..24b1caf7c1b --- /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 00000000000..3f4a23b8b41 --- /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 00000000000..52befb9c2e1 --- /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 00000000000..3b8c56352bd --- /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 00000000000..2bf1d0c05e6 --- /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 00000000000..3906b85aadb --- /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) +} -- cgit 1.4.1-3-g733a5 From 984688ace34ec0add8f365ead6587237537fc230 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 29 Jan 2019 16:36:46 +0100 Subject: Test more related cases --- src/test/ui/existential_types/generic_duplicate_param_use7.rs | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src') 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 3906b85aadb..2bcac315f5a 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) +} + -- cgit 1.4.1-3-g733a5 From f2241f640bb9f04cce88b2d28092cbfcee04c43e Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 29 Jan 2019 17:10:08 +0100 Subject: 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(-) (limited to 'src') diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 7cdcfec339e..b26a6a2292a 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 3b3449bbf11..3f9ed96400b 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 161111e3379..e29256a5014 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 89f70a873d9..3f129658b8f 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 8f860e7ee0a..1c96c15a769 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 52befb9c2e1..166623801c2 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 2bf1d0c05e6..da49a83be1f 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 -- cgit 1.4.1-3-g733a5 From c93bce85e5e085274febf1ca71b551de3f51429c Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 5 Feb 2019 14:18:09 +0100 Subject: Add more tests --- .../generic_duplicate_param_use8.rs | 16 +++++++++ .../generic_duplicate_param_use8.stderr | 19 +++++++++++ .../ui/existential_types/not_a_defining_use.rs | 39 ++++++++++++++++++++++ .../ui/existential_types/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 (limited to 'src') 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 00000000000..83501ad8c41 --- /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 00000000000..80c7441c857 --- /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 00000000000..413cc6788c2 --- /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 00000000000..a6ed5dbe0a9 --- /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 + -- cgit 1.4.1-3-g733a5 From eb98d318b28cc177f608d57fb5b9b017235b515d Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 14 Feb 2019 13:02:36 +0100 Subject: Require defining uses to use generic parameters for all parameters of a generic existential type --- src/librustc_typeck/collect.rs | 17 +++++++++++++---- src/test/ui/existential_types/bound_reduction2.rs | 3 ++- .../ui/existential_types/bound_reduction2.stderr | 16 ++++++++-------- .../generic_duplicate_param_use10.rs | 12 ++++++++++++ .../generic_duplicate_param_use9.rs | 20 ++++++++++++++++++++ .../generic_duplicate_param_use9.stderr | 18 ++++++++++++++++++ .../ui/existential_types/generic_nondefining_use.rs | 3 ++- .../existential_types/generic_nondefining_use.stderr | 16 ++++++++-------- src/test/ui/existential_types/not_a_defining_use.rs | 1 + .../ui/existential_types/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 (limited to 'src') diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index b26a6a2292a..b50a165ba9c 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 d8ade50c79c..542e076d88d 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 8e822ca6d8b..f51f1c9a4e5 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 00000000000..10f2c630582 --- /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 00000000000..4c6897298c4 --- /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 00000000000..a3ce480d66d --- /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 caa8f0f2ee1..75af5d9570f 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 41877791e9a..8dd88006be9 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 413cc6788c2..3f81f5177d0 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 a6ed5dbe0a9..288a32fc14e 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 -- cgit 1.4.1-3-g733a5