diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 6f04a68a6ed6..53ed0bfb12ee 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -237,6 +237,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 1f81321d22d6..e75446b01c11 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 18b0afe1fd91..6bb322251256 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -317,6 +317,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. @@ -419,7 +430,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 18dba3092ad5..02e4fb12af5c 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/mod.rs b/src/librustc_typeck/check/mod.rs index 91e44a158826..10f234fd3ca6 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1386,10 +1386,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/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index e68c50d752bd..e4c0e3bd54d5 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -560,21 +560,29 @@ 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); } } + 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 4a2d526263c0..ac033c83f3e4 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -23,9 +23,10 @@ use crate::middle::resolve_lifetime as rl; use crate::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; @@ -1191,7 +1192,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 @@ -1323,7 +1324,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> { @@ -1338,23 +1345,106 @@ 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 { - if ty != prev_ty { + // 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 (idx, subst) in substs.iter().enumerate() { + if let UnpackedKind::Type(ty) = subst.unpack() { + if let ty::Param(p) = ty.sty { + 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(); + 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) { + // 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() || p_ty.next().is_some() { // 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_label( + span, + format!("expected `{}`, got `{}`", prev_ty, concrete_type), + ); + 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", ); + 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(); } } else { - self.found = Some((span, ty)); + self.found = Some((span, concrete_type, indices)); } } } @@ -1413,7 +1503,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/bound_reduction2.rs b/src/test/ui/existential_types/bound_reduction2.rs index d8ade50c79c8..542e076d88d6 100644 --- a/src/test/ui/existential_types/bound_reduction2.rs +++ b/src/test/ui/existential_types/bound_reduction2.rs @@ -8,11 +8,12 @@ trait TraitWithAssoc { } existential type Foo: Trait; +//~^ ERROR could not find defining uses trait Trait {} impl Trait for () {} -fn foo_desugared(_: T) -> Foo { //~ ERROR non-defining +fn foo_desugared(_: T) -> Foo { //~ ERROR does not fully define () } diff --git a/src/test/ui/existential_types/bound_reduction2.stderr b/src/test/ui/existential_types/bound_reduction2.stderr index 8e822ca6d8bc..f51f1c9a4e56 100644 --- a/src/test/ui/existential_types/bound_reduction2.stderr +++ b/src/test/ui/existential_types/bound_reduction2.stderr @@ -1,16 +1,16 @@ -error: non-defining existential type use in defining scope - --> $DIR/bound_reduction2.rs:16:1 +error: defining existential type use does not fully define existential type + --> $DIR/bound_reduction2.rs:17:1 | -LL | / fn foo_desugared(_: T) -> Foo { //~ ERROR non-defining +LL | / fn foo_desugared(_: T) -> Foo { //~ ERROR does not fully define LL | | () LL | | } | |_^ - | -note: used non-generic type ::Assoc for generic parameter - --> $DIR/bound_reduction2.rs:10:22 + +error: could not find defining uses + --> $DIR/bound_reduction2.rs:10:1 | LL | existential type Foo: Trait; - | ^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error: aborting due to 2 previous errors diff --git a/src/test/ui/existential_types/different_defining_uses.rs b/src/test/ui/existential_types/different_defining_uses.rs index c51fca75a24e..a8670cc07f2e 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 f782a0022973..3f9ed96400b5 100644 --- a/src/test/ui/existential_types/different_defining_uses.stderr +++ b/src/test/ui/existential_types/different_defining_uses.stderr @@ -1,10 +1,10 @@ -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 | | } - | |_^ + | |_^ 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.rs b/src/test/ui/existential_types/different_defining_uses_never_type.rs index c6c6ae8d2dcc..13ada63e4bc4 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 04b0cf277845..e29256a5014f 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,10 +1,10 @@ -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 | | } - | |_^ + | |_^ expected `&'static str`, got `()` | note: previous use here --> $DIR/different_defining_uses_never_type.rs:8:1 @@ -14,13 +14,13 @@ 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 | | } - | |_^ + | |_^ 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.rs b/src/test/ui/existential_types/generic_different_defining_uses.rs index 3bd104251fb7..ce3ab88a1c0b 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 234bcf232ae7..3f129658b8fd 100644 --- a/src/test/ui/existential_types/generic_different_defining_uses.stderr +++ b/src/test/ui/existential_types/generic_different_defining_uses.stderr @@ -1,10 +1,10 @@ -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 | | } - | |_^ + | |_^ 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_use.rs b/src/test/ui/existential_types/generic_duplicate_param_use.rs index 380fbdeb8c27..3f8753333aa7 100644 --- a/src/test/ui/existential_types/generic_duplicate_param_use.rs +++ b/src/test/ui/existential_types/generic_duplicate_param_use.rs @@ -1,9 +1,14 @@ #![feature(existential_type)] +use std::fmt::Debug; + fn main() {} -existential type Two: 'static; //~ ERROR type parameter `U` is unused +// test that unused generic parameters are ok +existential type Two: Debug; +//~^ could not find defining uses -fn one(t: T) -> Two { +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 index 66706c210541..d4deda999da1 100644 --- a/src/test/ui/existential_types/generic_duplicate_param_use.stderr +++ b/src/test/ui/existential_types/generic_duplicate_param_use.stderr @@ -1,9 +1,17 @@ -error[E0091]: type parameter `U` is unused - --> $DIR/generic_duplicate_param_use.rs:5:25 +error: defining existential type use restricts existential type by using the generic parameter `T` twice + --> $DIR/generic_duplicate_param_use.rs:11:1 | -LL | existential type Two: 'static; //~ ERROR type parameter `U` is unused - | ^ unused type parameter +LL | / fn one(t: T) -> Two { +LL | | //~^ ERROR defining existential type use restricts existential type +LL | | t +LL | | } + | |_^ -error: aborting due to previous error +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 -For more information about this error, try `rustc --explain E0091`. diff --git a/src/test/ui/existential_types/generic_duplicate_param_use10.rs b/src/test/ui/existential_types/generic_duplicate_param_use10.rs new file mode 100644 index 000000000000..10f2c630582f --- /dev/null +++ b/src/test/ui/existential_types/generic_duplicate_param_use10.rs @@ -0,0 +1,12 @@ +// compile-pass +#![feature(existential_type)] + +use std::fmt::Debug; + +fn main() {} + +existential type Two: Debug; + +fn two(t: T, _: U) -> Two { + (t, 4u32) +} diff --git a/src/test/ui/existential_types/generic_duplicate_param_use2.rs b/src/test/ui/existential_types/generic_duplicate_param_use2.rs new file mode 100644 index 000000000000..3842292decd5 --- /dev/null +++ b/src/test/ui/existential_types/generic_duplicate_param_use2.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 one(t: T) -> Two { +//~^ defining existential type use restricts existential type + t +} + +fn two(t: T, _: U) -> Two { + 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 000000000000..0a8be3218c75 --- /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 new file mode 100644 index 000000000000..05c77c894733 --- /dev/null +++ b/src/test/ui/existential_types/generic_duplicate_param_use3.rs @@ -0,0 +1,22 @@ +#![feature(existential_type)] + +use std::fmt::Debug; + +fn main() {} + +// test that unused generic parameters are ok +existential type Two: Debug; + +fn one(t: T) -> Two { +//~^ defining existential type use restricts existential type + t +} + +fn two(t: T, _: U) -> Two { + t +} + +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 000000000000..1c96c15a7691 --- /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 | | } + | |_^ expected [`T`], got [`U`] + | +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 new file mode 100644 index 000000000000..609dbe06cd73 --- /dev/null +++ b/src/test/ui/existential_types/generic_duplicate_param_use4.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 one(t: T) -> Two { +//~^ ERROR defining existential type use restricts existential type + t +} + +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 new file mode 100644 index 000000000000..24b1caf7c1bf --- /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 000000000000..3f4a23b8b41f --- /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 000000000000..166623801c24 --- /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 | | } + | |_^ expected `(T, U)`, got `(U, T)` + | +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 000000000000..3b8c56352bda --- /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 000000000000..da49a83be1f7 --- /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 | | } + | |_^ expected `(T, T)`, got `(U, T)` + | +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 000000000000..2bcac315f5a9 --- /dev/null +++ b/src/test/ui/existential_types/generic_duplicate_param_use7.rs @@ -0,0 +1,25 @@ +// 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) +} + +fn four(t: T, t2: T, u: U, v: V) -> Two { + (t, t2) +} + +fn five(x: X, y: Y, y2: Y) -> Two { + (y, y2) +} + 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 000000000000..83501ad8c41a --- /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 000000000000..80c7441c857d --- /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/generic_duplicate_param_use9.rs b/src/test/ui/existential_types/generic_duplicate_param_use9.rs new file mode 100644 index 000000000000..4c6897298c44 --- /dev/null +++ b/src/test/ui/existential_types/generic_duplicate_param_use9.rs @@ -0,0 +1,20 @@ +#![feature(existential_type)] + +use std::fmt::Debug; + +fn main() {} + +existential type Two: Debug; + +trait Foo { + type Bar: Debug; + const BAR: Self::Bar; +} + +fn two(t: T, u: U) -> Two { + (t, u, T::BAR) +} + +fn three(t: T, u: U) -> Two { + (t, u, 42) //~^ ERROR concrete type differs from previous +} diff --git a/src/test/ui/existential_types/generic_duplicate_param_use9.stderr b/src/test/ui/existential_types/generic_duplicate_param_use9.stderr new file mode 100644 index 000000000000..a3ce480d66dc --- /dev/null +++ b/src/test/ui/existential_types/generic_duplicate_param_use9.stderr @@ -0,0 +1,18 @@ +error: concrete type differs from previous defining existential type use + --> $DIR/generic_duplicate_param_use9.rs:18:1 + | +LL | / fn three(t: T, u: U) -> Two { +LL | | (t, u, 42) //~^ ERROR concrete type differs from previous +LL | | } + | |_^ expected `(A, B, ::Bar)`, got `(A, B, i32)` + | +note: previous use here + --> $DIR/generic_duplicate_param_use9.rs:14:1 + | +LL | / fn two(t: T, u: U) -> Two { +LL | | (t, u, T::BAR) +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/existential_types/generic_nondefining_use.rs b/src/test/ui/existential_types/generic_nondefining_use.rs index caa8f0f2ee1b..75af5d9570ff 100644 --- a/src/test/ui/existential_types/generic_nondefining_use.rs +++ b/src/test/ui/existential_types/generic_nondefining_use.rs @@ -3,8 +3,9 @@ fn main() {} existential type Cmp: 'static; +//~^ ERROR could not find defining uses // not a defining use, because it doesn't define *all* possible generics -fn cmp() -> Cmp { //~ ERROR non-defining existential type use in defining scope +fn cmp() -> Cmp { //~ ERROR defining existential type use does not fully define 5u32 } diff --git a/src/test/ui/existential_types/generic_nondefining_use.stderr b/src/test/ui/existential_types/generic_nondefining_use.stderr index 41877791e9ae..8dd88006be9c 100644 --- a/src/test/ui/existential_types/generic_nondefining_use.stderr +++ b/src/test/ui/existential_types/generic_nondefining_use.stderr @@ -1,16 +1,16 @@ -error: non-defining existential type use in defining scope - --> $DIR/generic_nondefining_use.rs:8:1 +error: defining existential type use does not fully define existential type + --> $DIR/generic_nondefining_use.rs:9:1 | -LL | / fn cmp() -> Cmp { //~ ERROR non-defining existential type use in defining scope +LL | / fn cmp() -> Cmp { //~ ERROR defining existential type use does not fully define LL | | 5u32 LL | | } | |_^ - | -note: used non-generic type u32 for generic parameter - --> $DIR/generic_nondefining_use.rs:5:22 + +error: could not find defining uses + --> $DIR/generic_nondefining_use.rs:5:1 | LL | existential type Cmp: 'static; - | ^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error: aborting due to 2 previous errors diff --git a/src/test/ui/existential_types/not_a_defining_use.rs b/src/test/ui/existential_types/not_a_defining_use.rs new file mode 100644 index 000000000000..3f81f5177d0a --- /dev/null +++ b/src/test/ui/existential_types/not_a_defining_use.rs @@ -0,0 +1,40 @@ +#![feature(existential_type)] + +use std::fmt::Debug; + +fn main() {} + +existential type Two: Debug; + +fn two(t: T) -> Two { + //~^ ERROR defining existential type use does not fully define existential type + (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 000000000000..288a32fc14ed --- /dev/null +++ b/src/test/ui/existential_types/not_a_defining_use.stderr @@ -0,0 +1,27 @@ +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:30: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:14:1 + | +LL | / fn three(t: T) -> Two { +LL | | (t, 5i8) +LL | | } + | |_^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/existential_types/unused_generic_param.rs b/src/test/ui/existential_types/unused_generic_param.rs index bd7b343b402f..7af650878812 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 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 348aed3c4391..000000000000 --- 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`.