abi
});
+impl_stable_hash_for!(struct ty::ResolvedOpaqueTy<'tcx> {
+ concrete_type,
+ substs
+});
+
impl<'a, 'gcx, T> HashStable<StableHashingContext<'a>> for ty::Binder<T>
where T: HashStable<StableHashingContext<'a>>
{
///
/// 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]`.
}
}
+/// 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<A, B>; fn foo<T, U>() -> Foo<T, U> { .. }` 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.
/// All the existential types that are restricted to concrete types
/// by this function
- pub concrete_existential_types: FxHashMap<DefId, Ty<'tcx>>,
+ pub concrete_existential_types: FxHashMap<DefId, ResolvedOpaqueTy<'tcx>>,
/// 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
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};
}
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);
}
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,
);
}
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;
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
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<usize>)>,
}
impl<'a, 'tcx> ConstraintLocator<'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<ty::ParamTy, usize> = 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<usize>| {
+ 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));
}
}
}
}
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");
}
existential type Foo<V>: Trait<V>;
+//~^ ERROR could not find defining uses
trait Trait<U> {}
impl<W> Trait<W> for () {}
-fn foo_desugared<T: TraitWithAssoc>(_: T) -> Foo<T::Assoc> { //~ ERROR non-defining
+fn foo_desugared<T: TraitWithAssoc>(_: T) -> Foo<T::Assoc> { //~ ERROR does not fully define
()
}
-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: TraitWithAssoc>(_: T) -> Foo<T::Assoc> { //~ ERROR non-defining
+LL | / fn foo_desugared<T: TraitWithAssoc>(_: T) -> Foo<T::Assoc> { //~ ERROR does not fully define
LL | | ()
LL | | }
| |_^
- |
-note: used non-generic type <T as TraitWithAssoc>::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<V>: Trait<V>;
- | ^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: aborting due to previous error
+error: aborting due to 2 previous errors
""
}
-fn bar() -> Foo { //~ ERROR defining existential type use differs from previous
+fn bar() -> Foo { //~ ERROR concrete type differs from previous
42i32
}
-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
""
}
-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 {}
}
-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
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
std::iter::once(t)
}
-fn my_iter2<T>(t: T) -> MyIter<T> { //~ ERROR defining existential type use differs from previous
+fn my_iter2<T>(t: T) -> MyIter<T> { //~ ERROR concrete type differs from previous
Some(t).into_iter()
}
-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: T) -> MyIter<T> { //~ ERROR defining existential type use differs from previous
+LL | / fn my_iter2<T>(t: T) -> MyIter<T> { //~ ERROR concrete type differs from previous
LL | | Some(t).into_iter()
LL | | }
- | |_^
+ | |_^ expected `std::iter::Once<T>`, got `std::option::IntoIter<T>`
|
note: previous use here
--> $DIR/generic_different_defining_uses.rs:7:1
#![feature(existential_type)]
+use std::fmt::Debug;
+
fn main() {}
-existential type Two<T, U>: 'static; //~ ERROR type parameter `U` is unused
+// test that unused generic parameters are ok
+existential type Two<T, U>: Debug;
+//~^ could not find defining uses
-fn one<T: 'static>(t: T) -> Two<T, T> {
+fn one<T: Debug>(t: T) -> Two<T, T> {
+//~^ ERROR defining existential type use restricts existential type
t
}
-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<T, U>: 'static; //~ ERROR type parameter `U` is unused
- | ^ unused type parameter
+LL | / fn one<T: Debug>(t: T) -> Two<T, T> {
+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<T, U>: Debug;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0091`.
--- /dev/null
+// compile-pass
+#![feature(existential_type)]
+
+use std::fmt::Debug;
+
+fn main() {}
+
+existential type Two<T, U>: Debug;
+
+fn two<T: Debug, U: Debug>(t: T, _: U) -> Two<T, U> {
+ (t, 4u32)
+}
--- /dev/null
+#![feature(existential_type)]
+
+use std::fmt::Debug;
+
+fn main() {}
+
+// test that unused generic parameters are ok
+existential type Two<T, U>: Debug;
+
+fn one<T: Debug>(t: T) -> Two<T, T> {
+//~^ defining existential type use restricts existential type
+ t
+}
+
+fn two<T: Debug, U>(t: T, _: U) -> Two<T, U> {
+ t
+}
--- /dev/null
+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: Debug>(t: T) -> Two<T, T> {
+LL | | //~^ defining existential type use restricts existential type
+LL | | t
+LL | | }
+ | |_^
+
+error: aborting due to previous error
+
--- /dev/null
+#![feature(existential_type)]
+
+use std::fmt::Debug;
+
+fn main() {}
+
+// test that unused generic parameters are ok
+existential type Two<T, U>: Debug;
+
+fn one<T: Debug>(t: T) -> Two<T, T> {
+//~^ defining existential type use restricts existential type
+ t
+}
+
+fn two<T: Debug, U>(t: T, _: U) -> Two<T, U> {
+ t
+}
+
+fn three<T, U: Debug>(_: T, u: U) -> Two<T, U> {
+//~^ concrete type's generic parameters differ from previous defining use
+ u
+}
--- /dev/null
+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: Debug>(t: T) -> Two<T, T> {
+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: Debug>(_: T, u: U) -> Two<T, U> {
+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: Debug, U>(t: T, _: U) -> Two<T, U> {
+LL | | t
+LL | | }
+ | |_^
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+#![feature(existential_type)]
+
+use std::fmt::Debug;
+
+fn main() {}
+
+// test that unused generic parameters are ok
+existential type Two<T, U>: Debug;
+
+fn one<T: Debug>(t: T) -> Two<T, T> {
+//~^ ERROR defining existential type use restricts existential type
+ t
+}
+
+fn three<T, U: Debug>(_: T, u: U) -> Two<T, U> {
+ u
+}
--- /dev/null
+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: Debug>(t: T) -> Two<T, T> {
+LL | | //~^ ERROR defining existential type use restricts existential type
+LL | | t
+LL | | }
+ | |_^
+
+error: aborting due to previous error
+
--- /dev/null
+#![feature(existential_type)]
+
+use std::fmt::Debug;
+
+fn main() {}
+
+// test that unused generic parameters are ok
+existential type Two<T, U>: Debug;
+
+fn two<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
+ (t, u)
+}
+
+fn three<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
+//~^ concrete type differs from previous
+ (u, t)
+}
--- /dev/null
+error: concrete type differs from previous defining existential type use
+ --> $DIR/generic_duplicate_param_use5.rs:14:1
+ |
+LL | / fn three<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
+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: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
+LL | | (t, u)
+LL | | }
+ | |_^
+
+error: aborting due to previous error
+
--- /dev/null
+#![feature(existential_type)]
+
+use std::fmt::Debug;
+
+fn main() {}
+
+// test that unused generic parameters are ok
+existential type Two<T, U>: Debug;
+
+fn two<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
+ (t, t)
+}
+
+fn three<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
+//~^ concrete type differs from previous
+ (u, t)
+}
--- /dev/null
+error: concrete type differs from previous defining existential type use
+ --> $DIR/generic_duplicate_param_use6.rs:14:1
+ |
+LL | / fn three<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
+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: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
+LL | | (t, t)
+LL | | }
+ | |_^
+
+error: aborting due to previous error
+
--- /dev/null
+// compile-pass
+#![feature(existential_type)]
+
+use std::fmt::Debug;
+
+fn main() {}
+
+existential type Two<A, B>: Debug;
+
+fn two<T: Debug + Copy, U>(t: T, u: U) -> Two<T, U> {
+ (t, t)
+}
+
+fn three<T: Debug, U>(t: T, t2: T, u: U) -> Two<T, U> {
+ (t, t2)
+}
+
+fn four<T: Debug, U, V>(t: T, t2: T, u: U, v: V) -> Two<T, U> {
+ (t, t2)
+}
+
+fn five<X, Y: Debug>(x: X, y: Y, y2: Y) -> Two<Y, X> {
+ (y, y2)
+}
+
--- /dev/null
+#![feature(existential_type)]
+
+use std::fmt::Debug;
+
+fn main() {}
+
+existential type Two<T, U>: Debug;
+
+fn two<T: Debug, U: Debug>(t: T, _: U) -> Two<T, U> {
+ (t, 4u32)
+}
+
+fn three<T: Debug, U: Debug>(_: T, u: U) -> Two<T, U> {
+//~^ concrete type differs from previous
+ (u, 4u32)
+}
--- /dev/null
+error: concrete type differs from previous defining existential type use
+ --> $DIR/generic_duplicate_param_use8.rs:13:1
+ |
+LL | / fn three<T: Debug, U: Debug>(_: T, u: U) -> Two<T, U> {
+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: Debug, U: Debug>(t: T, _: U) -> Two<T, U> {
+LL | | (t, 4u32)
+LL | | }
+ | |_^
+
+error: aborting due to previous error
+
--- /dev/null
+#![feature(existential_type)]
+
+use std::fmt::Debug;
+
+fn main() {}
+
+existential type Two<A, B>: Debug;
+
+trait Foo {
+ type Bar: Debug;
+ const BAR: Self::Bar;
+}
+
+fn two<T: Debug + Foo, U: Debug>(t: T, u: U) -> Two<T, U> {
+ (t, u, T::BAR)
+}
+
+fn three<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
+ (t, u, 42) //~^ ERROR concrete type differs from previous
+}
--- /dev/null
+error: concrete type differs from previous defining existential type use
+ --> $DIR/generic_duplicate_param_use9.rs:18:1
+ |
+LL | / fn three<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
+LL | | (t, u, 42) //~^ ERROR concrete type differs from previous
+LL | | }
+ | |_^ expected `(A, B, <A as Foo>::Bar)`, got `(A, B, i32)`
+ |
+note: previous use here
+ --> $DIR/generic_duplicate_param_use9.rs:14:1
+ |
+LL | / fn two<T: Debug + Foo, U: Debug>(t: T, u: U) -> Two<T, U> {
+LL | | (t, u, T::BAR)
+LL | | }
+ | |_^
+
+error: aborting due to previous error
+
fn main() {}
existential type Cmp<T>: 'static;
+//~^ ERROR could not find defining uses
// not a defining use, because it doesn't define *all* possible generics
-fn cmp() -> Cmp<u32> { //~ ERROR non-defining existential type use in defining scope
+fn cmp() -> Cmp<u32> { //~ ERROR defining existential type use does not fully define
5u32
}
-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<u32> { //~ ERROR non-defining existential type use in defining scope
+LL | / fn cmp() -> Cmp<u32> { //~ 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<T>: 'static;
- | ^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: aborting due to previous error
+error: aborting due to 2 previous errors
--- /dev/null
+#![feature(existential_type)]
+
+use std::fmt::Debug;
+
+fn main() {}
+
+existential type Two<T, U>: Debug;
+
+fn two<T: Debug>(t: T) -> Two<T, u32> {
+ //~^ ERROR defining existential type use does not fully define existential type
+ (t, 4i8)
+}
+
+fn three<T: Debug, U>(t: T) -> Two<T, U> {
+ (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: Debug, U: Bar>(t: T) -> Two<T, U> { //~ concrete type differs from previous
+ (t, <U as Bar>::FOO)
+}
+
+fn is_sync<T: Sync>() {}
+
+fn asdfl() {
+ //FIXME(oli-obk): these currently cause cycle errors
+ //is_sync::<Two<i32, u32>>();
+ //is_sync::<Two<i32, *const i32>>();
+}
--- /dev/null
+error: defining existential type use does not fully define existential type
+ --> $DIR/not_a_defining_use.rs:9:1
+ |
+LL | / fn two<T: Debug>(t: T) -> Two<T, u32> {
+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: Debug, U: Bar>(t: T) -> Two<T, U> { //~ concrete type differs from previous
+LL | | (t, <U as Bar>::FOO)
+LL | | }
+ | |_^ expected `(T, i8)`, got `(T, <U as Bar>::Blub)`
+ |
+note: previous use here
+ --> $DIR/not_a_defining_use.rs:14:1
+ |
+LL | / fn three<T: Debug, U>(t: T) -> Two<T, U> {
+LL | | (t, 5i8)
+LL | | }
+ | |_^
+
+error: aborting due to 2 previous errors
+
+// compile-pass
#![feature(existential_type)]
fn main() {
}
-existential type PartiallyDefined<T>: 'static; //~ `T` is unused
+// test that unused generic parameters are ok
+existential type PartiallyDefined<T>: 'static;
fn partially_defined<T: std::fmt::Debug>(_: T) -> PartiallyDefined<T> {
4u32
}
-existential type PartiallyDefined2<T>: 'static; //~ `T` is unused
+// test that unused generic parameters are ok
+existential type PartiallyDefined2<T>: 'static;
fn partially_defined2<T: std::fmt::Debug>(_: T) -> PartiallyDefined2<T> {
4u32
+++ /dev/null
-error[E0091]: type parameter `T` is unused
- --> $DIR/unused_generic_param.rs:6:35
- |
-LL | existential type PartiallyDefined<T>: '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<T>: 'static; //~ `T` is unused
- | ^ unused type parameter
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0091`.