From 34792d9f6a831027a9c21ba2439b4a008a5ab1ad Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Fri, 12 Oct 2018 01:50:03 +0100 Subject: [PATCH 01/10] Added support for trait aliases as bounds. --- src/librustc/hir/map/mod.rs | 4 +- src/librustc/ich/impls_ty.rs | 17 +++ src/librustc/traits/mod.rs | 34 ++++-- src/librustc/traits/project.rs | 13 +-- src/librustc/traits/select.rs | 140 ++++++++++++++++++------ src/librustc/traits/structural_impls.rs | 42 ++++++- src/librustc/ty/instance.rs | 4 +- src/librustc/ty/mod.rs | 24 +++- src/librustc_resolve/lib.rs | 4 +- src/librustc_typeck/collect.rs | 9 +- src/libsyntax/feature_gate.rs | 17 +-- src/test/run-pass/traits/trait-alias.rs | 22 ++++ 12 files changed, 248 insertions(+), 82 deletions(-) create mode 100644 src/test/run-pass/traits/trait-alias.rs diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index f5f8e3512a0ea..cf7a7abf95a6c 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -301,9 +301,7 @@ impl<'hir> Map<'hir> { ItemKind::Struct(..) => Some(Def::Struct(def_id())), ItemKind::Union(..) => Some(Def::Union(def_id())), ItemKind::Trait(..) => Some(Def::Trait(def_id())), - ItemKind::TraitAlias(..) => { - bug!("trait aliases are not yet implemented (see issue #41517)") - }, + ItemKind::TraitAlias(..) => Some(Def::TraitAlias(def_id())), ItemKind::ExternCrate(_) | ItemKind::Use(..) | ItemKind::ForeignMod(..) | diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 0c93b86ee4d11..091ea9f52ff62 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -1119,6 +1119,7 @@ for traits::Vtable<'gcx, N> where N: HashStable> { &VtableClosure(ref table_closure) => table_closure.hash_stable(hcx, hasher), &VtableFnPointer(ref table_fn_pointer) => table_fn_pointer.hash_stable(hcx, hasher), &VtableGenerator(ref table_generator) => table_generator.hash_stable(hcx, hasher), + &VtableTraitAlias(ref table_alias) => table_alias.hash_stable(hcx, hasher), } } } @@ -1227,6 +1228,22 @@ for traits::VtableGeneratorData<'gcx, N> where N: HashStable HashStable> +for traits::VtableTraitAliasData<'gcx, N> where N: HashStable> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher) { + let traits::VtableTraitAliasData { + alias_def_id, + substs, + ref nested, + } = *self; + alias_def_id.hash_stable(hcx, hasher); + substs.hash_stable(hcx, hasher); + nested.hash_stable(hcx, hasher); + } +} + impl_stable_hash_for!( impl<'tcx, V> for struct infer::canonical::Canonical<'tcx, V> { max_universe, variables, value diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 6b2ec64668e9b..6b8d66c6fc629 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -534,8 +534,11 @@ pub enum Vtable<'tcx, N> { /// Same as above, but for a fn pointer type with the given signature. VtableFnPointer(VtableFnPointerData<'tcx, N>), - /// Vtable automatically generated for a generator + /// Vtable automatically generated for a generator. VtableGenerator(VtableGeneratorData<'tcx, N>), + + /// Vtable for a trait alias. + VtableTraitAlias(VtableTraitAliasData<'tcx, N>), } /// Identifies a particular impl in the source, along with a set of @@ -605,6 +608,13 @@ pub struct VtableFnPointerData<'tcx, N> { pub nested: Vec } +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable)] +pub struct VtableTraitAliasData<'tcx, N> { + pub alias_def_id: DefId, + pub substs: &'tcx Substs<'tcx>, + pub nested: Vec, +} + /// Creates predicate obligations from the generic bounds. pub fn predicates_for_generics<'tcx>(cause: ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -1067,6 +1077,7 @@ impl<'tcx, N> Vtable<'tcx, N> { VtableGenerator(c) => c.nested, VtableObject(d) => d.nested, VtableFnPointer(d) => d.nested, + VtableTraitAlias(d) => d.nested, } } @@ -1090,20 +1101,25 @@ impl<'tcx, N> Vtable<'tcx, N> { trait_def_id: d.trait_def_id, nested: d.nested.into_iter().map(f).collect(), }), - VtableFnPointer(p) => VtableFnPointer(VtableFnPointerData { - fn_ty: p.fn_ty, - nested: p.nested.into_iter().map(f).collect(), + VtableClosure(c) => VtableClosure(VtableClosureData { + closure_def_id: c.closure_def_id, + substs: c.substs, + nested: c.nested.into_iter().map(f).collect(), }), VtableGenerator(c) => VtableGenerator(VtableGeneratorData { generator_def_id: c.generator_def_id, substs: c.substs, nested: c.nested.into_iter().map(f).collect(), }), - VtableClosure(c) => VtableClosure(VtableClosureData { - closure_def_id: c.closure_def_id, - substs: c.substs, - nested: c.nested.into_iter().map(f).collect(), - }) + VtableFnPointer(p) => VtableFnPointer(VtableFnPointerData { + fn_ty: p.fn_ty, + nested: p.nested.into_iter().map(f).collect(), + }), + VtableTraitAlias(d) => VtableTraitAlias(VtableTraitAliasData { + alias_def_id: d.alias_def_id, + substs: d.substs, + nested: d.nested.into_iter().map(f).collect(), + }), } } } diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 4eda47d31ebb5..b7754ae4fc58d 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -19,10 +19,7 @@ use super::PredicateObligation; use super::Selection; use super::SelectionContext; use super::SelectionError; -use super::VtableClosureData; -use super::VtableGeneratorData; -use super::VtableFnPointerData; -use super::VtableImplData; +use super::{VtableImplData, VtableClosureData, VtableGeneratorData, VtableFnPointerData}; use super::util; use hir::def_id::DefId; @@ -1073,7 +1070,8 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>( super::VtableClosure(_) | super::VtableGenerator(_) | super::VtableFnPointer(_) | - super::VtableObject(_) => { + super::VtableObject(_) | + super::VtableTraitAlias(_) => { debug!("assemble_candidates_from_impls: vtable={:?}", vtable); true @@ -1235,7 +1233,8 @@ fn confirm_select_candidate<'cx, 'gcx, 'tcx>( confirm_object_candidate(selcx, obligation, obligation_trait_ref), super::VtableAutoImpl(..) | super::VtableParam(..) | - super::VtableBuiltin(..) => + super::VtableBuiltin(..) | + super::VtableTraitAlias(..) => // we don't create Select candidates with this kind of resolution span_bug!( obligation.cause.span, @@ -1486,7 +1485,7 @@ fn confirm_impl_candidate<'cx, 'gcx, 'tcx>( impl_vtable: VtableImplData<'tcx, PredicateObligation<'tcx>>) -> Progress<'tcx> { - let VtableImplData { substs, nested, impl_def_id } = impl_vtable; + let VtableImplData { impl_def_id, substs, nested } = impl_vtable; let tcx = selcx.tcx(); let param_env = obligation.param_env; diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index e2a5fdd362217..6d9e8d2fbe0f3 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -30,11 +30,11 @@ use super::{ObligationCause, PredicateObligation, TraitObligation}; use super::{OutputTypeParameterMismatch, Overflow, SelectionError, Unimplemented}; use super::{ VtableAutoImpl, VtableBuiltin, VtableClosure, VtableFnPointer, VtableGenerator, VtableImpl, - VtableObject, VtableParam, + VtableObject, VtableParam, VtableTraitAlias, }; use super::{ VtableAutoImplData, VtableBuiltinData, VtableClosureData, VtableFnPointerData, - VtableGeneratorData, VtableImplData, VtableObjectData, + VtableGeneratorData, VtableImplData, VtableObjectData, VtableTraitAliasData, }; use dep_graph::{DepKind, DepNodeIndex}; @@ -271,6 +271,8 @@ enum SelectionCandidate<'tcx> { /// types generated for a fn pointer type (e.g., `fn(int)->int`) FnPointerCandidate, + TraitAliasCandidate(DefId), + ObjectCandidate, BuiltinObjectCandidate, @@ -286,12 +288,13 @@ impl<'a, 'tcx> ty::Lift<'tcx> for SelectionCandidate<'a> { ImplCandidate(def_id) => ImplCandidate(def_id), AutoImplCandidate(def_id) => AutoImplCandidate(def_id), ProjectionCandidate => ProjectionCandidate, + ClosureCandidate => ClosureCandidate, + GeneratorCandidate => GeneratorCandidate, FnPointerCandidate => FnPointerCandidate, + TraitAliasCandidate(def_id) => TraitAliasCandidate(def_id), ObjectCandidate => ObjectCandidate, BuiltinObjectCandidate => BuiltinObjectCandidate, BuiltinUnsizeCandidate => BuiltinUnsizeCandidate, - ClosureCandidate => ClosureCandidate, - GeneratorCandidate => GeneratorCandidate, ParamCandidate(ref trait_ref) => { return tcx.lift(trait_ref).map(ParamCandidate); @@ -1452,7 +1455,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let predicate = self.infcx() .resolve_type_vars_if_possible(&obligation.predicate); - // ok to skip binder because of the nature of the + // OK to skip binder because of the nature of the // trait-ref-is-knowable check, which does not care about // bound regions let trait_ref = predicate.skip_binder().trait_ref; @@ -1632,6 +1635,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ambiguous: false, }; + self.assemble_candidates_for_alias(obligation, &mut candidates)?; + // Other bounds. Consider both in-scope bounds from fn decl // and applicable impls. There is a certain set of precedence rules here. let def_id = obligation.predicate.def_id(); @@ -1879,7 +1884,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { return Ok(()); } - // ok to skip binder because the substs on generator types never + // OK to skip binder because the substs on generator types never // touch bound regions, they just capture the in-scope // type/region parameters let self_ty = *obligation.self_ty().skip_binder(); @@ -1923,7 +1928,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } }; - // ok to skip binder because the substs on closure types never + // OK to skip binder because the substs on closure types never // touch bound regions, they just capture the in-scope // type/region parameters match obligation.self_ty().skip_binder().sty { @@ -1973,7 +1978,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { return Ok(()); } - // ok to skip binder because what we are inspecting doesn't involve bound regions + // OK to skip binder because what we are inspecting doesn't involve bound regions let self_ty = *obligation.self_ty().skip_binder(); match self_ty.sty { ty::Infer(ty::TyVar(_)) => { @@ -2250,6 +2255,24 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } } + fn assemble_candidates_for_alias( + &mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) -> Result<(), SelectionError<'tcx>> { + // OK to skip binder here because the tests we do below do not involve bound regions + let self_ty = *obligation.self_ty().skip_binder(); + debug!("assemble_candidates_for_alias(self_ty={:?})", self_ty); + + let def_id = obligation.predicate.def_id(); + + if ty::is_trait_alias(self.tcx(), def_id) { + candidates.vec.push(TraitAliasCandidate(def_id.clone())); + } + + Ok(()) + } + /////////////////////////////////////////////////////////////////////////// // WINNOW // @@ -2300,7 +2323,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { | FnPointerCandidate | BuiltinObjectCandidate | BuiltinUnsizeCandidate - | BuiltinCandidate { .. } => { + | BuiltinCandidate { .. } + | TraitAliasCandidate(..) => { // Global bounds from the where clause should be ignored // here (see issue #50825). Otherwise, we have a where // clause so don't go around looking for impls. @@ -2330,7 +2354,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { | FnPointerCandidate | BuiltinObjectCandidate | BuiltinUnsizeCandidate - | BuiltinCandidate { .. } => true, + | BuiltinCandidate { .. } + | TraitAliasCandidate(..) => true, ObjectCandidate | ProjectionCandidate => { // Arbitrarily give param candidates priority // over projection and object candidates. @@ -2724,15 +2749,20 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { Ok(VtableParam(obligations)) } + ImplCandidate(impl_def_id) => Ok(VtableImpl(self.confirm_impl_candidate( + obligation, + impl_def_id, + ))), + AutoImplCandidate(trait_def_id) => { let data = self.confirm_auto_impl_candidate(obligation, trait_def_id); Ok(VtableAutoImpl(data)) } - ImplCandidate(impl_def_id) => Ok(VtableImpl(self.confirm_impl_candidate( - obligation, - impl_def_id, - ))), + ProjectionCandidate => { + self.confirm_projection_candidate(obligation); + Ok(VtableParam(Vec::new())) + } ClosureCandidate => { let vtable_closure = self.confirm_closure_candidate(obligation)?; @@ -2744,13 +2774,14 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { Ok(VtableGenerator(vtable_generator)) } - BuiltinObjectCandidate => { - // This indicates something like `(Trait+Send) : - // Send`. In this case, we know that this holds - // because that's what the object type is telling us, - // and there's really no additional obligations to - // prove and no types in particular to unify etc. - Ok(VtableParam(Vec::new())) + FnPointerCandidate => { + let data = self.confirm_fn_pointer_candidate(obligation)?; + Ok(VtableFnPointer(data)) + } + + TraitAliasCandidate(alias_def_id) => { + let data = self.confirm_trait_alias_candidate(obligation, alias_def_id); + Ok(VtableTraitAlias(data)) } ObjectCandidate => { @@ -2758,13 +2789,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { Ok(VtableObject(data)) } - FnPointerCandidate => { - let data = self.confirm_fn_pointer_candidate(obligation)?; - Ok(VtableFnPointer(data)) - } - - ProjectionCandidate => { - self.confirm_projection_candidate(obligation); + BuiltinObjectCandidate => { + // This indicates something like `(Trait+Send) : + // Send`. In this case, we know that this holds + // because that's what the object type is telling us, + // and there's really no additional obligations to + // prove and no types in particular to unify etc. Ok(VtableParam(Vec::new())) } @@ -2998,10 +3028,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ) -> VtableObjectData<'tcx, PredicateObligation<'tcx>> { debug!("confirm_object_candidate({:?})", obligation); - // FIXME skipping binder here seems wrong -- we should - // probably flatten the binder from the obligation and the - // binder from the object. Have to try to make a broken test - // case that results. -nmatsakis + // FIXME(nmatsakis) skipping binder here seems wrong -- we should + // probably flatten the binder from the obligation and the binder + // from the object. Have to try to make a broken test case that + // results. let self_ty = self.infcx .shallow_resolve(*obligation.self_ty().skip_binder()); let poly_trait_ref = match self_ty.sty { @@ -3053,7 +3083,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ) -> Result>, SelectionError<'tcx>> { debug!("confirm_fn_pointer_candidate({:?})", obligation); - // ok to skip binder; it is reintroduced below + // OK to skip binder; it is reintroduced below let self_ty = self.infcx .shallow_resolve(*obligation.self_ty().skip_binder()); let sig = self_ty.fn_sig(self.tcx()); @@ -3089,11 +3119,51 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { }) } + fn confirm_trait_alias_candidate( + &mut self, + obligation: &TraitObligation<'tcx>, + alias_def_id: DefId, + ) -> VtableTraitAliasData<'tcx, PredicateObligation<'tcx>> { + debug!( + "confirm_trait_alias_candidate({:?}, {:?})", + obligation, alias_def_id + ); + + self.in_snapshot(|this, snapshot| { + let (predicate, placeholder_map) = this.infcx() + .replace_late_bound_regions_with_placeholders(&obligation.predicate); + let trait_ref = predicate.trait_ref; + let trait_def_id = trait_ref.def_id; + let substs = trait_ref.substs; + + let trait_obligations = this.impl_or_trait_obligations( + obligation.cause.clone(), + obligation.recursion_depth, + obligation.param_env, + trait_def_id, + &substs, + placeholder_map, + snapshot, + ); + + debug!( + "confirm_trait_alias_candidate: trait_def_id={:?} trait_obligations={:?}", + trait_def_id, trait_obligations + ); + + VtableTraitAliasData { + alias_def_id, + substs: substs, + nested: trait_obligations, + } + }) + } + fn confirm_generator_candidate( &mut self, obligation: &TraitObligation<'tcx>, ) -> Result>, SelectionError<'tcx>> { - // ok to skip binder because the substs on generator types never + // OK to skip binder because the substs on generator types never // touch bound regions, they just capture the in-scope // type/region parameters let self_ty = self.infcx @@ -3151,7 +3221,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { .fn_trait_kind(obligation.predicate.def_id()) .unwrap_or_else(|| bug!("closure candidate for non-fn trait {:?}", obligation)); - // ok to skip binder because the substs on closure types never + // OK to skip binder because the substs on closure types never // touch bound regions, they just capture the in-scope // type/region parameters let self_ty = self.infcx diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index 24779a350d74b..e83d085971caa 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -62,6 +62,8 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::Vtable<'tcx, N> { super::VtableParam(ref n) => write!(f, "VtableParam({:?})", n), super::VtableBuiltin(ref d) => write!(f, "{:?}", d), + + super::VtableTraitAlias(ref d) => write!(f, "{:?}", d), } } } @@ -70,7 +72,7 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableImplData<'tcx, N> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, - "VtableImpl(impl_def_id={:?}, substs={:?}, nested={:?})", + "VtableImplData(impl_def_id={:?}, substs={:?}, nested={:?})", self.impl_def_id, self.substs, self.nested ) } @@ -80,7 +82,7 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableGeneratorData<'tcx, N> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, - "VtableGenerator(generator_def_id={:?}, substs={:?}, nested={:?})", + "VtableGeneratorData(generator_def_id={:?}, substs={:?}, nested={:?})", self.generator_def_id, self.substs, self.nested ) } @@ -90,7 +92,7 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableClosureData<'tcx, N> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, - "VtableClosure(closure_def_id={:?}, substs={:?}, nested={:?})", + "VtableClosureData(closure_def_id={:?}, substs={:?}, nested={:?})", self.closure_def_id, self.substs, self.nested ) } @@ -98,7 +100,7 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableClosureData<'tcx, N> { impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableBuiltinData { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "VtableBuiltin(nested={:?})", self.nested) + write!(f, "VtableBuiltinData(nested={:?})", self.nested) } } @@ -116,7 +118,7 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableObjectData<'tcx, N> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, - "VtableObject(upcast={:?}, vtable_base={}, nested={:?})", + "VtableObjectData(upcast={:?}, vtable_base={}, nested={:?})", self.upcast_trait_ref, self.vtable_base, self.nested ) } @@ -126,12 +128,22 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableFnPointerData<'tcx, N> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, - "VtableFnPointer(fn_ty={:?}, nested={:?})", + "VtableFnPointerData(fn_ty={:?}, nested={:?})", self.fn_ty, self.nested ) } } +impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableTraitAliasData<'tcx, N> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "VtableTraitAlias(alias_def_id={:?}, substs={:?}, nested={:?})", + self.alias_def_id, self.substs, self.nested + ) + } +} + impl<'tcx> fmt::Debug for traits::FulfillmentError<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "FulfillmentError({:?},{:?})", self.obligation, self.code) @@ -321,6 +333,17 @@ impl<'a, 'tcx> Lift<'tcx> for traits::Vtable<'a, ()> { nested, }) ), + traits::VtableTraitAlias(traits::VtableTraitAliasData { + alias_def_id, + substs, + nested, + }) => tcx.lift(&substs).map(|substs| + traits::VtableTraitAlias(traits::VtableTraitAliasData { + alias_def_id, + substs, + nested, + }) + ), } } } @@ -386,6 +409,12 @@ BraceStructTypeFoldableImpl! { } where N: TypeFoldable<'tcx> } +BraceStructTypeFoldableImpl! { + impl<'tcx, N> TypeFoldable<'tcx> for traits::VtableTraitAliasData<'tcx, N> { + alias_def_id, substs, nested + } where N: TypeFoldable<'tcx> +} + EnumTypeFoldableImpl! { impl<'tcx, N> TypeFoldable<'tcx> for traits::Vtable<'tcx, N> { (traits::VtableImpl)(a), @@ -396,6 +425,7 @@ EnumTypeFoldableImpl! { (traits::VtableParam)(a), (traits::VtableBuiltin)(a), (traits::VtableObject)(a), + (traits::VtableTraitAlias)(a), } where N: TypeFoldable<'tcx> } diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 041565c8b5a07..1627f9a766c4e 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -400,7 +400,9 @@ fn resolve_associated_item<'a, 'tcx>( None } } - traits::VtableAutoImpl(..) | traits::VtableParam(..) => None + traits::VtableAutoImpl(..) | + traits::VtableParam(..) | + traits::VtableTraitAlias(..) => None } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index ad26383df6ac2..f3ae15e3b3c53 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2801,7 +2801,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } - /// Determine whether an item is annotated with an attribute + /// Determine whether an item is annotated with an attribute. pub fn has_attr(self, did: DefId, attr: &str) -> bool { attr::contains_name(&self.get_attrs(did), attr) } @@ -2815,14 +2815,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.optimized_mir(def_id).generator_layout.as_ref().unwrap() } - /// Given the def_id of an impl, return the def_id of the trait it implements. + /// Given the def-id of an impl, return the def_id of the trait it implements. /// If it implements no trait, return `None`. pub fn trait_id_of_impl(self, def_id: DefId) -> Option { self.impl_trait_ref(def_id).map(|tr| tr.def_id) } - /// If the given def ID describes a method belonging to an impl, return the - /// ID of the impl that the method belongs to. Otherwise, return `None`. + /// If the given defid describes a method belonging to an impl, return the + /// def-id of the impl that the method belongs to. Otherwise, return `None`. pub fn impl_of_method(self, def_id: DefId) -> Option { let item = if def_id.krate != LOCAL_CRATE { if let Some(Def::Method(_)) = self.describe_def(def_id) { @@ -2987,7 +2987,7 @@ fn trait_of_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Option }) } -/// Yields the parent function's `DefId` if `def_id` is an `impl Trait` definition +/// Yields the parent function's `DefId` if `def_id` is an `impl Trait` definition. pub fn is_impl_trait_defn(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) -> Option { if let Some(node_id) = tcx.hir.as_local_node_id(def_id) { if let Node::Item(item) = tcx.hir.get(node_id) { @@ -2999,7 +2999,19 @@ pub fn is_impl_trait_defn(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) -> Option, def_id: DefId) -> bool { + if let Some(node_id) = tcx.hir.as_local_node_id(def_id) { + if let Node::Item(item) = tcx.hir.get(node_id) { + if let hir::ItemKind::TraitAlias(..) = item.node { + return true; + } + } + } + false +} + +/// See `ParamEnv` struct definition for details. fn param_env<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ParamEnv<'tcx> diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 7b5e704f60f6e..a7eccd6b44dbf 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -3888,7 +3888,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { // report an error. if record_used { resolve_error(self, span, - ResolutionError::CannotCaptureDynamicEnvironmentInFnItem); + ResolutionError::CannotCaptureDynamicEnvironmentInFnItem); } return Def::Err; } @@ -3896,7 +3896,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { // Still doesn't deal with upvars if record_used { resolve_error(self, span, - ResolutionError::AttemptToUseNonConstantValueInConstant); + ResolutionError::AttemptToUseNonConstantValueInConstant); } return Def::Err; } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index eb52a013b0566..a8b24019af0a0 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -419,12 +419,9 @@ fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: ast::NodeId) { tcx.predicates_of(def_id); } hir::ItemKind::TraitAlias(..) => { - span_err!( - tcx.sess, - it.span, - E0645, - "trait aliases are not yet implemented (see issue #41517)" - ); + tcx.generics_of(def_id); + tcx.at(it.span).super_predicates_of(def_id); + tcx.predicates_of(def_id); } hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => { tcx.generics_of(def_id); diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index da0ec33030e06..6abc506c07b73 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -1635,19 +1635,13 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { if name == "packed" { gate_feature_post!(&self, repr_packed, attr.span, "the `#[repr(packed(n))]` attribute \ - is experimental"); + is experimental"); } } } } } - ast::ItemKind::TraitAlias(..) => { - gate_feature_post!(&self, trait_alias, - i.span, - "trait aliases are not yet fully implemented"); - } - ast::ItemKind::Impl(_, polarity, defaultness, _, _, _, _) => { if polarity == ast::ImplPolarity::Negative { gate_feature_post!(&self, optin_builtin_traits, @@ -1669,6 +1663,15 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { "auto traits are experimental and possibly buggy"); } + ast::ItemKind::TraitAlias(..) => { + gate_feature_post!( + &self, + trait_alias, + i.span, + "trait aliases are experimental" + ); + } + ast::ItemKind::MacroDef(ast::MacroDef { legacy: false, .. }) => { let msg = "`macro` is experimental"; gate_feature_post!(&self, decl_macro, i.span, msg); diff --git a/src/test/run-pass/traits/trait-alias.rs b/src/test/run-pass/traits/trait-alias.rs new file mode 100644 index 0000000000000..7659655be97b4 --- /dev/null +++ b/src/test/run-pass/traits/trait-alias.rs @@ -0,0 +1,22 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(trait_alias)] + +trait Foo = std::fmt::Debug; + +fn foo(v: &T) { + println!("{:?}", v); +} + +pub fn main() { + foo(&12345); + let foo: &Foo = &0i32; +} From 90041d638b1363d3ed89dde8245563bac4c4062c Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Mon, 22 Oct 2018 00:45:24 +0100 Subject: [PATCH 02/10] Added support for trait aliases as object types. --- src/librustc/hir/lowering.rs | 33 +++++++++++++------------ src/librustc_resolve/lib.rs | 11 ++++++--- src/librustc_typeck/astconv.rs | 13 +++++----- src/libsyntax/ast.rs | 6 ++--- src/libsyntax/ext/expand.rs | 2 +- src/libsyntax/parse/parser.rs | 2 +- src/test/run-pass/traits/trait-alias.rs | 10 ++++++-- 7 files changed, 43 insertions(+), 34 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index b6621e0962cf6..e558d94551671 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -4875,23 +4875,24 @@ impl<'a> LoweringContext<'a> { let node = match qpath { hir::QPath::Resolved(None, path) => { // Turn trait object paths into `TyKind::TraitObject` instead. - if let Def::Trait(_) = path.def { - let principal = hir::PolyTraitRef { - bound_generic_params: hir::HirVec::new(), - trait_ref: hir::TraitRef { - path: path.and_then(|path| path), - ref_id: id.node_id, - hir_ref_id: id.hir_id, - }, - span, - }; + match path.def { + Def::Trait(_) | Def::TraitAlias(_) => { + let principal = hir::PolyTraitRef { + bound_generic_params: hir::HirVec::new(), + trait_ref: hir::TraitRef { + path: path.and_then(|path| path), + ref_id: id.node_id, + hir_ref_id: id.hir_id, + }, + span, + }; - // The original ID is taken by the `PolyTraitRef`, - // so the `Ty` itself needs a different one. - id = self.next_id(); - hir::TyKind::TraitObject(hir_vec![principal], self.elided_dyn_bound(span)) - } else { - hir::TyKind::Path(hir::QPath::Resolved(None, path)) + // The original ID is taken by the `PolyTraitRef`, + // so the `Ty` itself needs a different one. + id = self.next_id(); + hir::TyKind::TraitObject(hir_vec![principal], self.elided_dyn_bound(span)) + } + _ => hir::TyKind::Path(hir::QPath::Resolved(None, path)), } } _ => hir::TyKind::Path(qpath), diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index a7eccd6b44dbf..17ca8c275c3cb 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -538,9 +538,9 @@ impl<'a> PathSource<'a> { match self { PathSource::Type => match def { Def::Struct(..) | Def::Union(..) | Def::Enum(..) | - Def::Trait(..) | Def::TyAlias(..) | Def::AssociatedTy(..) | - Def::PrimTy(..) | Def::TyParam(..) | Def::SelfTy(..) | - Def::Existential(..) | + Def::Trait(..) | Def::TraitAlias(..) | Def::TyAlias(..) | + Def::AssociatedTy(..) | Def::PrimTy(..) | Def::TyParam(..) | + Def::SelfTy(..) | Def::Existential(..) | Def::ForeignTy(..) => true, _ => false, }, @@ -3122,7 +3122,10 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { return (err, candidates); } (Def::TyAlias(..), PathSource::Trait(_)) => { - err.span_label(span, "type aliases cannot be used for traits"); + err.span_label(span, "type aliases cannot be used as traits"); + if nightly_options::is_nightly_build() { + err.note("did you mean to use a trait alias?"); + } return (err, candidates); } (Def::Mod(..), PathSource::Expr(Some(parent))) => match parent.node { diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 7ddc56974d816..e8a502d6ca888 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Conversion from AST representation of types to the ty.rs +//! Conversion from AST representation of types to the `ty.rs` //! representation. The main routine here is `ast_ty_to_ty()`: each use //! is parameterized by an instance of `AstConv`. @@ -181,7 +181,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { item_segment: &hir::PathSegment) -> &'tcx Substs<'tcx> { - let (substs, assoc_bindings) = item_segment.with_generic_args(|generic_args| { self.create_substs_for_ast_path( span, @@ -948,8 +947,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { ) } - /// Transform a PolyTraitRef into a PolyExistentialTraitRef by - /// removing the dummy Self type (TRAIT_OBJECT_DUMMY_SELF). + /// Transform a `PolyTraitRef` into a `PolyExistentialTraitRef` by + /// removing the dummy `Self` type (`TRAIT_OBJECT_DUMMY_SELF`). fn trait_ref_to_existential(&self, trait_ref: ty::TraitRef<'tcx>) -> ty::ExistentialTraitRef<'tcx> { assert_eq!(trait_ref.self_ty().sty, TRAIT_OBJECT_DUMMY_SELF); @@ -1347,7 +1346,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { err.span_label(span, "associated type not allowed here").emit(); } - // Check a type Path and convert it to a Ty. + // Check a type `Path` and convert it to a `Ty`. pub fn def_to_ty(&self, opt_self_ty: Option>, path: &hir::Path, @@ -1442,8 +1441,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { /// Parses the programmer's textual representation of a type into our /// internal notion of a type. pub fn ast_ty_to_ty(&self, ast_ty: &hir::Ty) -> Ty<'tcx> { - debug!("ast_ty_to_ty(id={:?}, ast_ty={:?})", - ast_ty.id, ast_ty); + debug!("ast_ty_to_ty(id={:?}, ast_ty={:?} ty_ty={:?})", + ast_ty.id, ast_ty, ast_ty.node); let tcx = self.tcx(); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index a9acc70d1a5b9..cfedda18a7e22 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -288,9 +288,9 @@ pub enum TraitBoundModifier { } /// The AST represents all type param bounds as types. -/// typeck::collect::compute_bounds matches these against -/// the "special" built-in traits (see middle::lang_items) and -/// detects Copy, Send and Sync. +/// `typeck::collect::compute_bounds` matches these against +/// the "special" built-in traits (see `middle::lang_items`) and +/// detects `Copy`, `Send` and `Sync`. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub enum GenericBound { Trait(PolyTraitRef, TraitBoundModifier), diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 41ed90fb94eed..a148a6496656a 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -252,7 +252,7 @@ impl Invocation { pub struct MacroExpander<'a, 'b:'a> { pub cx: &'a mut ExtCtxt<'b>, - monotonic: bool, // c.f. `cx.monotonic_expander()` + monotonic: bool, // cf. `cx.monotonic_expander()` } impl<'a, 'b> MacroExpander<'a, 'b> { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index be448f960df3f..6018744215b7d 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1532,7 +1532,7 @@ impl<'a> Parser<'a> { if maybe_bounds && bounds.len() == 1 && !trailing_plus => { let path = match bounds[0] { GenericBound::Trait(ref pt, ..) => pt.trait_ref.path.clone(), - _ => self.bug("unexpected lifetime bound"), + GenericBound::Outlives(..) => self.bug("unexpected lifetime bound"), }; self.parse_remaining_bounds(Vec::new(), path, lo, true)? } diff --git a/src/test/run-pass/traits/trait-alias.rs b/src/test/run-pass/traits/trait-alias.rs index 7659655be97b4..604344c93c2f8 100644 --- a/src/test/run-pass/traits/trait-alias.rs +++ b/src/test/run-pass/traits/trait-alias.rs @@ -10,7 +10,8 @@ #![feature(trait_alias)] -trait Foo = std::fmt::Debug; +type Foo = std::fmt::Debug; +type Bar = Foo; fn foo(v: &T) { println!("{:?}", v); @@ -18,5 +19,10 @@ fn foo(v: &T) { pub fn main() { foo(&12345); - let foo: &Foo = &0i32; + + let bar1: &Bar = &54321; + println!("{:?}", bar1); + + let bar2 = Box::new(42) as Box; + println!("{:?}", bar2); } From 4751953d5f2cd88243e3fac9a84271ed7a2636b4 Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Mon, 22 Oct 2018 01:58:34 +0100 Subject: [PATCH 03/10] Added tests. --- .../traits/trait-alias-bounds.rs} | 19 ++++----- ...it-alias.rs => trait-alias-object-type.rs} | 19 +++------ src/test/ui/codemap_tests/two_files.stderr | 4 +- .../feature-gates/feature-gate-trait-alias.rs | 13 +++++++ .../feature-gate-trait-alias.stderr | 11 ++++++ src/test/ui/resolve/issue-3907.stderr | 4 +- src/test/ui/resolve/issue-5035.stderr | 4 +- ...xed-closure-sugar-nonexistent-trait.stderr | 4 +- src/test/ui/trait-alias-fail.rs | 27 ------------- src/test/ui/traits/trait-alias-fail.rs | 20 ++++++++++ .../ui/{ => traits}/trait-alias-fail.stderr | 26 +++++-------- src/test/ui/traits/trait-alias.stderr | 39 ------------------- 12 files changed, 82 insertions(+), 108 deletions(-) rename src/test/{ui/traits/trait-alias.rs => run-pass/traits/trait-alias-bounds.rs} (69%) rename src/test/run-pass/traits/{trait-alias.rs => trait-alias-object-type.rs} (67%) create mode 100644 src/test/ui/feature-gates/feature-gate-trait-alias.rs create mode 100644 src/test/ui/feature-gates/feature-gate-trait-alias.stderr delete mode 100644 src/test/ui/trait-alias-fail.rs create mode 100644 src/test/ui/traits/trait-alias-fail.rs rename src/test/ui/{ => traits}/trait-alias-fail.stderr (53%) delete mode 100644 src/test/ui/traits/trait-alias.stderr diff --git a/src/test/ui/traits/trait-alias.rs b/src/test/run-pass/traits/trait-alias-bounds.rs similarity index 69% rename from src/test/ui/traits/trait-alias.rs rename to src/test/run-pass/traits/trait-alias-bounds.rs index 9ea211b4d7d69..0d59c8e0bd132 100644 --- a/src/test/ui/traits/trait-alias.rs +++ b/src/test/run-pass/traits/trait-alias-bounds.rs @@ -1,4 +1,4 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// Copyright 2017-2018 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -10,21 +10,23 @@ #![feature(trait_alias)] -trait SimpleAlias = Default; //~ERROR E0645 -trait GenericAlias = Iterator; //~ERROR E0645 -trait Partial = IntoIterator; //~ERROR E0645 +trait SimpleAlias = Default; +trait GenericAlias = Iterator; +trait Partial = IntoIterator; trait Things {} trait Romeo {} +#[allow(dead_code)] struct The(T); +#[allow(dead_code)] struct Fore(T); impl Things for The {} impl Romeo for Fore {} -trait WithWhere = Romeo + Romeo where Fore<(Art, Thou)>: Romeo; //~ERROR E0645 -trait BareWhere = where The: Things; //~ERROR E0645 +trait WithWhere = Romeo + Romeo where Fore<(Art, Thou)>: Romeo; +trait BareWhere = where The: Things; -trait CD = Clone + Default; //~ERROR E0645 +trait CD = Clone + Default; fn foo() -> (T, T) { let one = T::default(); @@ -33,11 +35,10 @@ fn foo() -> (T, T) { } fn main() { - let both = foo(); + let both = foo::(); assert_eq!(both.0, 0); assert_eq!(both.1, 0); let both: (i32, i32) = foo(); assert_eq!(both.0, 0); assert_eq!(both.1, 0); } - diff --git a/src/test/run-pass/traits/trait-alias.rs b/src/test/run-pass/traits/trait-alias-object-type.rs similarity index 67% rename from src/test/run-pass/traits/trait-alias.rs rename to src/test/run-pass/traits/trait-alias-object-type.rs index 604344c93c2f8..3f0be573b2892 100644 --- a/src/test/run-pass/traits/trait-alias.rs +++ b/src/test/run-pass/traits/trait-alias-object-type.rs @@ -10,19 +10,12 @@ #![feature(trait_alias)] -type Foo = std::fmt::Debug; -type Bar = Foo; - -fn foo(v: &T) { - println!("{:?}", v); -} +trait Foo = PartialEq + Send; +trait Bar = Foo + Sync; pub fn main() { - foo(&12345); - - let bar1: &Bar = &54321; - println!("{:?}", bar1); - - let bar2 = Box::new(42) as Box; - println!("{:?}", bar2); + let a: &Bar = &123; + assert!(*a == 123); + let b = Box::new(456) as Box; + assert!(*b == 456); } diff --git a/src/test/ui/codemap_tests/two_files.stderr b/src/test/ui/codemap_tests/two_files.stderr index e247e86fbcb22..f60f1dfcf3772 100644 --- a/src/test/ui/codemap_tests/two_files.stderr +++ b/src/test/ui/codemap_tests/two_files.stderr @@ -2,7 +2,9 @@ error[E0404]: expected trait, found type alias `Bar` --> $DIR/two_files.rs:15:6 | LL | impl Bar for Baz { } //~ ERROR expected trait, found type alias - | ^^^ type aliases cannot be used for traits + | ^^^ type aliases cannot be used as traits + | + = note: did you mean to use a trait alias? error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-trait-alias.rs b/src/test/ui/feature-gates/feature-gate-trait-alias.rs new file mode 100644 index 0000000000000..a2a183f80f92e --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-trait-alias.rs @@ -0,0 +1,13 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Foo = Default; + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-trait-alias.stderr b/src/test/ui/feature-gates/feature-gate-trait-alias.stderr new file mode 100644 index 0000000000000..e02dfe27805a4 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-trait-alias.stderr @@ -0,0 +1,11 @@ +error[E0658]: trait aliases are experimental (see issue #41517) + --> $DIR/feature-gate-trait-alias.rs:11:1 + | +LL | trait Foo = Default; + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(trait_alias)] to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/resolve/issue-3907.stderr b/src/test/ui/resolve/issue-3907.stderr index 3627c09b28fd9..3e330f9de6547 100644 --- a/src/test/ui/resolve/issue-3907.stderr +++ b/src/test/ui/resolve/issue-3907.stderr @@ -2,7 +2,9 @@ error[E0404]: expected trait, found type alias `Foo` --> $DIR/issue-3907.rs:20:6 | LL | impl Foo for S { //~ ERROR expected trait, found type alias `Foo` - | ^^^ type aliases cannot be used for traits + | ^^^ type aliases cannot be used as traits + | + = note: did you mean to use a trait alias? help: possible better candidate is found in another module, you can import it into scope | LL | use issue_3907::Foo; diff --git a/src/test/ui/resolve/issue-5035.stderr b/src/test/ui/resolve/issue-5035.stderr index 353a0b1c3d9d0..0acc5c8a93ec6 100644 --- a/src/test/ui/resolve/issue-5035.stderr +++ b/src/test/ui/resolve/issue-5035.stderr @@ -11,7 +11,9 @@ LL | impl K for isize {} //~ ERROR expected trait, found type alias `K` | ^ | | | did you mean `I`? - | type aliases cannot be used for traits + | type aliases cannot be used as traits + | + = note: did you mean to use a trait alias? error: aborting due to 2 previous errors diff --git a/src/test/ui/resolve/unboxed-closure-sugar-nonexistent-trait.stderr b/src/test/ui/resolve/unboxed-closure-sugar-nonexistent-trait.stderr index f32c5e9b2c6bd..d293a77392e89 100644 --- a/src/test/ui/resolve/unboxed-closure-sugar-nonexistent-trait.stderr +++ b/src/test/ui/resolve/unboxed-closure-sugar-nonexistent-trait.stderr @@ -8,7 +8,9 @@ error[E0404]: expected trait, found type alias `Typedef` --> $DIR/unboxed-closure-sugar-nonexistent-trait.rs:16:8 | LL | fn g isize>(x: F) {} - | ^^^^^^^^^^^^^^^^^^^^^^^ type aliases cannot be used for traits + | ^^^^^^^^^^^^^^^^^^^^^^^ type aliases cannot be used as traits + | + = note: did you mean to use a trait alias? error: aborting due to 2 previous errors diff --git a/src/test/ui/trait-alias-fail.rs b/src/test/ui/trait-alias-fail.rs deleted file mode 100644 index 7aca227a76c48..0000000000000 --- a/src/test/ui/trait-alias-fail.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// gate-test-trait_alias - -trait Alias1 = Default where T: Clone; // ok - //~^ERROR trait aliases are not yet fully implemented -trait Alias2 = Default; - //~^ERROR type parameters on the left side of a trait alias cannot be bounded - //~^^ERROR type parameters on the left side of a trait alias cannot have defaults - //~^^^ERROR trait aliases are not yet fully implemented - -impl Alias1 { //~ERROR expected type, found trait alias -} - -impl Alias1 for () { //~ERROR expected trait, found trait alias -} - -fn main() {} - diff --git a/src/test/ui/traits/trait-alias-fail.rs b/src/test/ui/traits/trait-alias-fail.rs new file mode 100644 index 0000000000000..3a47593a8e150 --- /dev/null +++ b/src/test/ui/traits/trait-alias-fail.rs @@ -0,0 +1,20 @@ +// Copyright 2017-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// gate-test-trait_alias + +trait Alias1 = Default where T: Clone; +trait Alias2 = Default; + +impl Alias1 {} + +impl Alias1 for () {} + +fn main() {} diff --git a/src/test/ui/trait-alias-fail.stderr b/src/test/ui/traits/trait-alias-fail.stderr similarity index 53% rename from src/test/ui/trait-alias-fail.stderr rename to src/test/ui/traits/trait-alias-fail.stderr index f7b144c06f80a..829a316ccb81e 100644 --- a/src/test/ui/trait-alias-fail.stderr +++ b/src/test/ui/traits/trait-alias-fail.stderr @@ -1,44 +1,38 @@ error: type parameters on the left side of a trait alias cannot be bounded - --> $DIR/trait-alias-fail.rs:15:14 + --> $DIR/trait-alias-fail.rs:14:14 | LL | trait Alias2 = Default; | ^ error: type parameters on the left side of a trait alias cannot have defaults - --> $DIR/trait-alias-fail.rs:15:14 + --> $DIR/trait-alias-fail.rs:14:14 | LL | trait Alias2 = Default; | ^ -error[E0573]: expected type, found trait alias `Alias1` - --> $DIR/trait-alias-fail.rs:20:6 - | -LL | impl Alias1 { //~ERROR expected type, found trait alias - | ^^^^^^ not a type - error[E0404]: expected trait, found trait alias `Alias1` - --> $DIR/trait-alias-fail.rs:23:6 + --> $DIR/trait-alias-fail.rs:18:6 | -LL | impl Alias1 for () { //~ERROR expected trait, found trait alias +LL | impl Alias1 for () {} | ^^^^^^ not a trait -error[E0658]: trait aliases are not yet fully implemented (see issue #41517) +error[E0658]: trait aliases are experimental (see issue #41517) --> $DIR/trait-alias-fail.rs:13:1 | -LL | trait Alias1 = Default where T: Clone; // ok +LL | trait Alias1 = Default where T: Clone; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(trait_alias)] to the crate attributes to enable -error[E0658]: trait aliases are not yet fully implemented (see issue #41517) - --> $DIR/trait-alias-fail.rs:15:1 +error[E0658]: trait aliases are experimental (see issue #41517) + --> $DIR/trait-alias-fail.rs:14:1 | LL | trait Alias2 = Default; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(trait_alias)] to the crate attributes to enable -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors -Some errors occurred: E0404, E0573, E0658. +Some errors occurred: E0404, E0658. For more information about an error, try `rustc --explain E0404`. diff --git a/src/test/ui/traits/trait-alias.stderr b/src/test/ui/traits/trait-alias.stderr deleted file mode 100644 index 5d290e5c7fba1..0000000000000 --- a/src/test/ui/traits/trait-alias.stderr +++ /dev/null @@ -1,39 +0,0 @@ -error[E0645]: trait aliases are not yet implemented (see issue #41517) - --> $DIR/trait-alias.rs:13:1 - | -LL | trait SimpleAlias = Default; //~ERROR E0645 - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0645]: trait aliases are not yet implemented (see issue #41517) - --> $DIR/trait-alias.rs:14:1 - | -LL | trait GenericAlias = Iterator; //~ERROR E0645 - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0645]: trait aliases are not yet implemented (see issue #41517) - --> $DIR/trait-alias.rs:15:1 - | -LL | trait Partial = IntoIterator; //~ERROR E0645 - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0645]: trait aliases are not yet implemented (see issue #41517) - --> $DIR/trait-alias.rs:24:1 - | -LL | trait WithWhere = Romeo + Romeo where Fore<(Art, Thou)>: Romeo; //~ERROR E0645 - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0645]: trait aliases are not yet implemented (see issue #41517) - --> $DIR/trait-alias.rs:25:1 - | -LL | trait BareWhere = where The: Things; //~ERROR E0645 - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0645]: trait aliases are not yet implemented (see issue #41517) - --> $DIR/trait-alias.rs:27:1 - | -LL | trait CD = Clone + Default; //~ERROR E0645 - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 6 previous errors - -For more information about this error, try `rustc --explain E0645`. From 1cda3c3b49183b60dc90ec1b19e494ff118c976c Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Mon, 22 Oct 2018 02:55:01 +0100 Subject: [PATCH 04/10] Added section to Unstable Book. --- .../src/language-features/trait-alias.md | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/doc/unstable-book/src/language-features/trait-alias.md diff --git a/src/doc/unstable-book/src/language-features/trait-alias.md b/src/doc/unstable-book/src/language-features/trait-alias.md new file mode 100644 index 0000000000000..4f2db040160c3 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/trait-alias.md @@ -0,0 +1,34 @@ +# `trait_alias` + +The tracking issue for this feature is: [#41517] + +[#41417]: https://github.com/rust-lang/rust/issues/41517 + +------------------------ + +The `trait_alias` feature adds support for trait aliases. These allow aliases +to be created for one or more traits (currently just a single regular trait plus +any number of auto-traits), and used wherever traits would normally be used as +either bounds or trait objects. + +```rust +#![feature(trait_alias)] + +trait Foo = std::fmt::Debug + Send; +trait Bar = Foo + Sync; + +// Use trait alias as bound on type parameter. +fn foo(v: &T) { + println!("{:?}", v); +} + +pub fn main() { + foo(&1); + + // Use trait alias for trait objects. + let a: &Bar = &123; + println!("{:?}", a); + let b = Box::new(456) as Box; + println!("{:?}", b); +} +``` From a8fcfcef3087e9770fa016c5776ce5bf25558ed7 Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Thu, 25 Oct 2018 01:03:25 +0100 Subject: [PATCH 05/10] Add more tests. --- .../run-pass/traits/trait-alias-bounds.rs | 52 ++++++++++++++++--- .../traits/trait-alias-object-type.rs | 8 ++- src/test/ui/traits/trait-alias-fail.stderr | 38 -------------- ...ait-alias-fail.rs => trait-alias-fail1.rs} | 9 ++-- src/test/ui/traits/trait-alias-fail1.stderr | 46 ++++++++++++++++ src/test/ui/traits/trait-alias-fail2.rs | 19 +++++++ src/test/ui/traits/trait-alias-fail2.stderr | 19 +++++++ 7 files changed, 142 insertions(+), 49 deletions(-) delete mode 100644 src/test/ui/traits/trait-alias-fail.stderr rename src/test/ui/traits/{trait-alias-fail.rs => trait-alias-fail1.rs} (68%) create mode 100644 src/test/ui/traits/trait-alias-fail1.stderr create mode 100644 src/test/ui/traits/trait-alias-fail2.rs create mode 100644 src/test/ui/traits/trait-alias-fail2.stderr diff --git a/src/test/run-pass/traits/trait-alias-bounds.rs b/src/test/run-pass/traits/trait-alias-bounds.rs index 0d59c8e0bd132..c1c3989107b28 100644 --- a/src/test/run-pass/traits/trait-alias-bounds.rs +++ b/src/test/run-pass/traits/trait-alias-bounds.rs @@ -10,9 +10,14 @@ #![feature(trait_alias)] +use std::marker::PhantomData; + trait SimpleAlias = Default; -trait GenericAlias = Iterator; -trait Partial = IntoIterator; +trait GenericAlias = Iterator; +trait Partial = IntoIterator; +trait SpecificAlias = GenericAlias; +trait PartialEqRef<'a, T> = PartialEq<&'a T>; +trait StaticAlias = 'static; trait Things {} trait Romeo {} @@ -26,19 +31,54 @@ impl Romeo for Fore {} trait WithWhere = Romeo + Romeo where Fore<(Art, Thou)>: Romeo; trait BareWhere = where The: Things; -trait CD = Clone + Default; +trait Empty {} +trait EmptyAlias = Empty; +trait CloneDefault = Clone + Default; +trait SendSyncAlias = Send + Sync; +trait WhereSendAlias = where Self: Send; +trait SendEqAlias = Send where T: PartialEq; +trait I32Iterator = Iterator; + +#[allow(dead_code)] +struct Foo(PhantomData); +#[allow(dead_code)] +struct Bar(PhantomData) where T: SendSyncAlias; + +impl EmptyAlias {} + +impl Empty for T {} -fn foo() -> (T, T) { +fn a() -> (T, T) { let one = T::default(); let two = one.clone(); (one, two) } +fn b(x: &impl SendEqAlias) -> bool { + 22_i32 == *x +} + +fn c(x: &mut T) -> Option { + x.next() +} + +fn d() { + is_send_and_sync::(); +} + +fn is_send_and_sync() {} + fn main() { - let both = foo::(); + let both = a::(); assert_eq!(both.0, 0); assert_eq!(both.1, 0); - let both: (i32, i32) = foo(); + let both: (i32, i32) = a(); assert_eq!(both.0, 0); assert_eq!(both.1, 0); + + assert!(b(&22)); + + assert_eq!(c(&mut vec![22].into_iter()), Some(22)); + + d::(); } diff --git a/src/test/run-pass/traits/trait-alias-object-type.rs b/src/test/run-pass/traits/trait-alias-object-type.rs index 3f0be573b2892..17e30922b2cb8 100644 --- a/src/test/run-pass/traits/trait-alias-object-type.rs +++ b/src/test/run-pass/traits/trait-alias-object-type.rs @@ -13,9 +13,15 @@ trait Foo = PartialEq + Send; trait Bar = Foo + Sync; +trait I32Iterator = Iterator; + pub fn main() { - let a: &Bar = &123; + let a: &dyn Bar = &123; assert!(*a == 123); let b = Box::new(456) as Box; assert!(*b == 456); + + // FIXME(alexreg): associated type should be gotten from trait alias definition + // let c: &dyn I32Iterator = &vec![123].into_iter(); + // assert_eq!(c.next(), Some(123)); } diff --git a/src/test/ui/traits/trait-alias-fail.stderr b/src/test/ui/traits/trait-alias-fail.stderr deleted file mode 100644 index 829a316ccb81e..0000000000000 --- a/src/test/ui/traits/trait-alias-fail.stderr +++ /dev/null @@ -1,38 +0,0 @@ -error: type parameters on the left side of a trait alias cannot be bounded - --> $DIR/trait-alias-fail.rs:14:14 - | -LL | trait Alias2 = Default; - | ^ - -error: type parameters on the left side of a trait alias cannot have defaults - --> $DIR/trait-alias-fail.rs:14:14 - | -LL | trait Alias2 = Default; - | ^ - -error[E0404]: expected trait, found trait alias `Alias1` - --> $DIR/trait-alias-fail.rs:18:6 - | -LL | impl Alias1 for () {} - | ^^^^^^ not a trait - -error[E0658]: trait aliases are experimental (see issue #41517) - --> $DIR/trait-alias-fail.rs:13:1 - | -LL | trait Alias1 = Default where T: Clone; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(trait_alias)] to the crate attributes to enable - -error[E0658]: trait aliases are experimental (see issue #41517) - --> $DIR/trait-alias-fail.rs:14:1 - | -LL | trait Alias2 = Default; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(trait_alias)] to the crate attributes to enable - -error: aborting due to 5 previous errors - -Some errors occurred: E0404, E0658. -For more information about an error, try `rustc --explain E0404`. diff --git a/src/test/ui/traits/trait-alias-fail.rs b/src/test/ui/traits/trait-alias-fail1.rs similarity index 68% rename from src/test/ui/traits/trait-alias-fail.rs rename to src/test/ui/traits/trait-alias-fail1.rs index 3a47593a8e150..135fdf93c2986 100644 --- a/src/test/ui/traits/trait-alias-fail.rs +++ b/src/test/ui/traits/trait-alias-fail1.rs @@ -10,11 +10,12 @@ // gate-test-trait_alias -trait Alias1 = Default where T: Clone; -trait Alias2 = Default; +trait CloneDefault = Default where T: Clone; +trait BoundedAlias = Default; -impl Alias1 {} +trait A {} +trait B = A; // FIXME: parameter T should need a bound here, or semantics should be changed -impl Alias1 for () {} +impl CloneDefault for () {} fn main() {} diff --git a/src/test/ui/traits/trait-alias-fail1.stderr b/src/test/ui/traits/trait-alias-fail1.stderr new file mode 100644 index 0000000000000..565409be782ed --- /dev/null +++ b/src/test/ui/traits/trait-alias-fail1.stderr @@ -0,0 +1,46 @@ +error: type parameters on the left side of a trait alias cannot be bounded + --> $DIR/trait-alias-fail1.rs:14:20 + | +LL | trait BoundedAlias = Default; + | ^ + +error: type parameters on the left side of a trait alias cannot have defaults + --> $DIR/trait-alias-fail1.rs:14:20 + | +LL | trait BoundedAlias = Default; + | ^ + +error[E0404]: expected trait, found trait alias `CloneDefault` + --> $DIR/trait-alias-fail1.rs:19:6 + | +LL | impl CloneDefault for () {} + | ^^^^^^^^^^^^ not a trait + +error[E0658]: trait aliases are experimental (see issue #41517) + --> $DIR/trait-alias-fail1.rs:13:1 + | +LL | trait CloneDefault = Default where T: Clone; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(trait_alias)] to the crate attributes to enable + +error[E0658]: trait aliases are experimental (see issue #41517) + --> $DIR/trait-alias-fail1.rs:14:1 + | +LL | trait BoundedAlias = Default; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(trait_alias)] to the crate attributes to enable + +error[E0658]: trait aliases are experimental (see issue #41517) + --> $DIR/trait-alias-fail1.rs:17:1 + | +LL | trait B = A; // FIXME: this should not work... or should it? + | ^^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(trait_alias)] to the crate attributes to enable + +error: aborting due to 6 previous errors + +Some errors occurred: E0404, E0658. +For more information about an error, try `rustc --explain E0404`. diff --git a/src/test/ui/traits/trait-alias-fail2.rs b/src/test/ui/traits/trait-alias-fail2.rs new file mode 100644 index 0000000000000..3d32cf6d29b6b --- /dev/null +++ b/src/test/ui/traits/trait-alias-fail2.rs @@ -0,0 +1,19 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// gate-test-trait_alias + +trait EqAlias = Eq; +trait IteratorAlias = Iterator; + +fn main() { + let _: &dyn EqAlias = &123; + let _: &dyn IteratorAlias = &vec![123].into_iter(); +} diff --git a/src/test/ui/traits/trait-alias-fail2.stderr b/src/test/ui/traits/trait-alias-fail2.stderr new file mode 100644 index 0000000000000..6ebd8b5e73174 --- /dev/null +++ b/src/test/ui/traits/trait-alias-fail2.stderr @@ -0,0 +1,19 @@ +error[E0658]: trait aliases are experimental (see issue #41517) + --> $DIR/trait-alias-fail2.rs:13:1 + | +LL | trait EqAlias = Eq; + | ^^^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(trait_alias)] to the crate attributes to enable + +error[E0658]: trait aliases are experimental (see issue #41517) + --> $DIR/trait-alias-fail2.rs:14:1 + | +LL | trait IteratorAlias = Iterator; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(trait_alias)] to the crate attributes to enable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. From 4bdc3d833af1229420fce37b245d5cccd1d7cc3f Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Fri, 26 Oct 2018 23:13:12 +0100 Subject: [PATCH 06/10] Extended elaboration for trait aliases to include arbitrary bounds. --- src/librustc/traits/select.rs | 10 +++--- src/librustc/traits/util.rs | 2 +- src/librustc/ty/mod.rs | 12 +++---- src/librustc/ty/util.rs | 2 +- src/librustc_passes/ast_validation.rs | 19 ---------- src/librustc_typeck/astconv.rs | 10 +++--- src/librustc_typeck/collect.rs | 40 ++++++++++++++------- src/libsyntax/parse/parser.rs | 10 +++--- src/test/ui/traits/trait-alias-fail1.rs | 7 ++-- src/test/ui/traits/trait-alias-fail1.stderr | 2 +- src/test/ui/traits/trait-alias-fail2.rs | 2 +- 11 files changed, 57 insertions(+), 59 deletions(-) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 6d9e8d2fbe0f3..4b41831afbb33 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1635,7 +1635,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ambiguous: false, }; - self.assemble_candidates_for_alias(obligation, &mut candidates)?; + self.assemble_candidates_for_trait_alias(obligation, &mut candidates)?; // Other bounds. Consider both in-scope bounds from fn decl // and applicable impls. There is a certain set of precedence rules here. @@ -2255,14 +2255,14 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } } - fn assemble_candidates_for_alias( + fn assemble_candidates_for_trait_alias( &mut self, obligation: &TraitObligation<'tcx>, candidates: &mut SelectionCandidateSet<'tcx>, ) -> Result<(), SelectionError<'tcx>> { // OK to skip binder here because the tests we do below do not involve bound regions let self_ty = *obligation.self_ty().skip_binder(); - debug!("assemble_candidates_for_alias(self_ty={:?})", self_ty); + debug!("assemble_candidates_for_trait_alias(self_ty={:?})", self_ty); let def_id = obligation.predicate.def_id(); @@ -2907,7 +2907,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { self.vtable_auto_impl(obligation, trait_def_id, types) } - /// See `confirm_auto_impl_candidate` + /// See `confirm_auto_impl_candidate`. fn vtable_auto_impl( &mut self, obligation: &TraitObligation<'tcx>, @@ -2964,7 +2964,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // this time not in a probe. self.in_snapshot(|this, snapshot| { let (substs, placeholder_map) = this.rematch_impl(impl_def_id, obligation, snapshot); - debug!("confirm_impl_candidate substs={:?}", substs); + debug!("confirm_impl_candidate: substs={:?}", substs); let cause = obligation.derived_cause(ImplDerivedObligation); this.vtable_impl( impl_def_id, diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index 940cf736012ec..74f8d67ce0484 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -333,7 +333,7 @@ impl FilterToTraits { } } -impl<'tcx,I:Iterator>> Iterator for FilterToTraits { +impl<'tcx,I:Iterator>> Iterator for FilterToTraits { type Item = ty::PolyTraitRef<'tcx>; fn next(&mut self) -> Option> { diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index f3ae15e3b3c53..3d9ec7245f9d6 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1051,24 +1051,24 @@ pub enum Predicate<'tcx> { /// would be the type parameters. Trait(PolyTraitPredicate<'tcx>), - /// where 'a : 'b + /// where `'a : 'b` RegionOutlives(PolyRegionOutlivesPredicate<'tcx>), - /// where T : 'a + /// where `T : 'a` TypeOutlives(PolyTypeOutlivesPredicate<'tcx>), - /// where ::Name == X, approximately. - /// See `ProjectionPredicate` struct for details. + /// where `::Name == X`, approximately. + /// See the `ProjectionPredicate` struct for details. Projection(PolyProjectionPredicate<'tcx>), - /// no syntax: T WF + /// no syntax: `T` well-formed WellFormed(Ty<'tcx>), /// trait must be object-safe ObjectSafe(DefId), /// No direct syntax. May be thought of as `where T : FnFoo<...>` - /// for some substitutions `...` and T being a closure type. + /// for some substitutions `...` and `T` being a closure type. /// Satisfied (or refuted) once we know the closure's kind. ClosureKind(DefId, ClosureSubsts<'tcx>, ClosureKind), diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 00a1bfaacd781..a6997260784d3 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -527,7 +527,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.def_key(def_id).disambiguated_data.data == DefPathData::ClosureExpr } - /// True if `def_id` refers to a trait (e.g., `trait Foo { ... }`). + /// True if `def_id` refers to a trait (i.e., `trait Foo { ... }`). pub fn is_trait(self, def_id: DefId) -> bool { if let DefPathData::Trait(_) = self.def_key(def_id).disambiguated_data.data { true diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 0e9596244cd58..61861da62f759 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -403,25 +403,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } } } - ItemKind::TraitAlias(Generics { ref params, .. }, ..) => { - for param in params { - match param.kind { - GenericParamKind::Lifetime { .. } => {} - GenericParamKind::Type { ref default, .. } => { - if !param.bounds.is_empty() { - self.err_handler() - .span_err(param.ident.span, "type parameters on the left \ - side of a trait alias cannot be bounded"); - } - if !default.is_none() { - self.err_handler() - .span_err(param.ident.span, "type parameters on the left \ - side of a trait alias cannot have defaults"); - } - } - } - } - } ItemKind::Mod(_) => { // Ensure that `path` attributes on modules are recorded as used (c.f. #35584). attr::first_attr_value_str_by_name(&item.attrs, "path"); diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index e8a502d6ca888..9556be6ebfc1c 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -544,7 +544,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { } /// Given the type/region arguments provided to some path (along with - /// an implicit Self, if this is a trait reference) returns the complete + /// an implicit `Self`, if this is a trait reference) returns the complete /// set of substitutions. This may involve applying defaulted type parameters. /// /// Note that the type listing given here is *exactly* what the user provided. @@ -721,7 +721,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { { let trait_def_id = self.trait_def_id(trait_ref); - debug!("ast_path_to_poly_trait_ref({:?}, def_id={:?})", trait_ref, trait_def_id); + debug!("instantiate_poly_trait_ref({:?}, def_id={:?})", trait_ref, trait_def_id); self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1); @@ -738,11 +738,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { let predicate: Result<_, ErrorReported> = self.ast_type_binding_to_poly_projection_predicate( trait_ref.ref_id, poly_trait_ref, binding, speculative, &mut dup_bindings); - // ok to ignore Err() because ErrorReported (see above) + // ok to ignore Err because ErrorReported (see above) Some((predicate.ok()?, binding.span)) })); - debug!("ast_path_to_poly_trait_ref({:?}, projections={:?}) -> {:?}", + debug!("instantiate_poly_trait_ref({:?}, projections={:?}) -> {:?}", trait_ref, poly_projections, poly_trait_ref); poly_trait_ref } @@ -1020,7 +1020,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { return tcx.types.err; } - // use a btreeset to keep output in a more consistent order + // use a BTreeSet to keep output in a more consistent order let mut associated_types = BTreeSet::default(); for tr in traits::supertraits(tcx, principal) { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index a8b24019af0a0..21a1abd97a5a3 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -245,8 +245,8 @@ fn type_param_predicates<'a, 'tcx>( use rustc::hir::*; // In the AST, bounds can derive from two places. Either - // written inline like `` or in a where clause like - // `where T:Foo`. + // written inline like `` or in a where clause like + // `where T : Foo`. let param_id = tcx.hir.as_local_node_id(def_id).unwrap(); let param_owner = tcx.hir.ty_param_owner(param_id); @@ -317,12 +317,12 @@ fn type_param_predicates<'a, 'tcx>( let icx = ItemCtxt::new(tcx, item_def_id); result .predicates - .extend(icx.type_parameter_bounds_in_generics(ast_generics, param_id, ty)); + .extend(icx.type_parameter_bounds_in_generics(ast_generics, param_id, ty, true)); result } impl<'a, 'tcx> ItemCtxt<'a, 'tcx> { - /// Find bounds from hir::Generics. This requires scanning through the + /// Find bounds from `hir::Generics`. This requires scanning through the /// AST. We do this to avoid having to convert *all* the bounds, which /// would create artificial cycles. Instead we can only convert the /// bounds for a type parameter `X` if `X::Foo` is used. @@ -331,6 +331,7 @@ impl<'a, 'tcx> ItemCtxt<'a, 'tcx> { ast_generics: &hir::Generics, param_id: ast::NodeId, ty: Ty<'tcx>, + only_self_bounds: bool, ) -> Vec<(ty::Predicate<'tcx>, Span)> { let from_ty_params = ast_generics .params @@ -350,9 +351,21 @@ impl<'a, 'tcx> ItemCtxt<'a, 'tcx> { hir::WherePredicate::BoundPredicate(ref bp) => Some(bp), _ => None, }) - .filter(|bp| is_param(self.tcx, &bp.bounded_ty, param_id)) - .flat_map(|bp| bp.bounds.iter()) - .flat_map(|b| predicates_from_bound(self, ty, b)); + .flat_map(|bp| { + let bt = if is_param(self.tcx, &bp.bounded_ty, param_id) { + Some(ty) + } else { + if only_self_bounds { + None + } else { + Some(self.to_ty(&bp.bounded_ty)) + } + }; + bp.bounds.iter().filter_map(move |b| { + if let Some(bt) = bt { Some((bt, b)) } else { None } + }) + }) + .flat_map(|(bt, b)| predicates_from_bound(self, bt, b)); from_ty_params.chain(from_where_clauses).collect() } @@ -690,7 +703,7 @@ fn super_predicates_of<'a, 'tcx>( let icx = ItemCtxt::new(tcx, trait_def_id); - // Convert the bounds that follow the colon, e.g. `Bar+Zed` in `trait Foo : Bar+Zed`. + // Convert the bounds that follow the colon, e.g. `Bar + Zed` in `trait Foo : Bar + Zed`. let self_param_ty = tcx.mk_self_type(); let superbounds1 = compute_bounds(&icx, self_param_ty, bounds, SizedByDefault::No, item.span); @@ -698,7 +711,9 @@ fn super_predicates_of<'a, 'tcx>( // Convert any explicit superbounds in the where clause, // e.g. `trait Foo where Self : Bar`: - let superbounds2 = icx.type_parameter_bounds_in_generics(generics, item.id, self_param_ty); + let is_trait_alias = ty::is_trait_alias(tcx, trait_def_id); + let superbounds2 = icx.type_parameter_bounds_in_generics( + generics, item.id, self_param_ty, !is_trait_alias); // Combine the two lists to form the complete set of superbounds: let superbounds: Vec<_> = superbounds1.into_iter().chain(superbounds2).collect(); @@ -706,6 +721,7 @@ fn super_predicates_of<'a, 'tcx>( // Now require that immediate supertraits are converted, // which will, in turn, reach indirect supertraits. for &(pred, span) in &superbounds { + debug!("superbound: {:?}", pred); if let ty::Predicate::Trait(bound) = pred { tcx.at(span).super_predicates_of(bound.def_id()); } @@ -2007,10 +2023,10 @@ pub fn compute_bounds<'gcx: 'tcx, 'tcx>( } } -/// Converts a specific GenericBound from the AST into a set of +/// Converts a specific `GenericBound` from the AST into a set of /// predicates that apply to the self-type. A vector is returned -/// because this can be anywhere from 0 predicates (`T:?Sized` adds no -/// predicates) to 1 (`T:Foo`) to many (`T:Bar` adds `T:Bar` +/// because this can be anywhere from zero predicates (`T : ?Sized` adds no +/// predicates) to one (`T : Foo`) to many (`T : Bar` adds `T : Bar` /// and `::X == i32`). fn predicates_from_bound<'tcx>( astconv: &dyn AstConv<'tcx, 'tcx>, diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6018744215b7d..d3416d6923cb0 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1295,7 +1295,7 @@ impl<'a> Parser<'a> { self.check_keyword(keywords::Extern) && self.is_extern_non_path() } - /// parse a TyKind::BareFn type: + /// parse a `TyKind::BareFn` type: fn parse_ty_bare_fn(&mut self, generic_params: Vec) -> PResult<'a, TyKind> { /* @@ -5779,7 +5779,7 @@ impl<'a> Parser<'a> { ast::ImplItemKind)> { // code copied from parse_macro_use_or_failure... abstraction! if let Some(mac) = self.parse_assoc_macro_invoc("impl", Some(vis), at_end)? { - // Method macro. + // method macro Ok((keywords::Invalid.ident(), vec![], ast::Generics::default(), ast::ImplItemKind::Macro(mac))) } else { @@ -6792,11 +6792,11 @@ impl<'a> Parser<'a> { Ok(self.mk_item(lo.to(prev_span), invalid, ItemKind::ForeignMod(m), visibility, attrs)) } - /// Parse type Foo = Bar; + /// Parse `type Foo = Bar;` /// or - /// existential type Foo: Bar; + /// `existential type Foo: Bar;` /// or - /// return None without modifying the parser state + /// `return None` without modifying the parser state fn eat_type(&mut self) -> Option> { // This parses the grammar: // Ident ["<"...">"] ["where" ...] ("=" | ":") Ty ";" diff --git a/src/test/ui/traits/trait-alias-fail1.rs b/src/test/ui/traits/trait-alias-fail1.rs index 135fdf93c2986..25c850db6ce41 100644 --- a/src/test/ui/traits/trait-alias-fail1.rs +++ b/src/test/ui/traits/trait-alias-fail1.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// gate-test-trait_alias +#![feature(trait_alias)] trait CloneDefault = Default where T: Clone; trait BoundedAlias = Default; -trait A {} -trait B = A; // FIXME: parameter T should need a bound here, or semantics should be changed +trait Foo {} +trait A {} +trait B = A; // T cannot be unbounded impl CloneDefault for () {} diff --git a/src/test/ui/traits/trait-alias-fail1.stderr b/src/test/ui/traits/trait-alias-fail1.stderr index 565409be782ed..447f4b1b9de98 100644 --- a/src/test/ui/traits/trait-alias-fail1.stderr +++ b/src/test/ui/traits/trait-alias-fail1.stderr @@ -35,7 +35,7 @@ LL | trait BoundedAlias = Default; error[E0658]: trait aliases are experimental (see issue #41517) --> $DIR/trait-alias-fail1.rs:17:1 | -LL | trait B = A; // FIXME: this should not work... or should it? +LL | trait B = A; // FIXME: parameter T should need a bound here, or semantics should be changed | ^^^^^^^^^^^^^^^^^^ | = help: add #![feature(trait_alias)] to the crate attributes to enable diff --git a/src/test/ui/traits/trait-alias-fail2.rs b/src/test/ui/traits/trait-alias-fail2.rs index 3d32cf6d29b6b..3adcd8436d8a1 100644 --- a/src/test/ui/traits/trait-alias-fail2.rs +++ b/src/test/ui/traits/trait-alias-fail2.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// gate-test-trait_alias +#![feature(trait_alias)] trait EqAlias = Eq; trait IteratorAlias = Iterator; From 469c3bf75b5768611f65c65c3bbafab3c315dcdf Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Thu, 1 Nov 2018 02:00:32 +0000 Subject: [PATCH 07/10] Resolve nits brought up in review. --- src/librustc_typeck/collect.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 21a1abd97a5a3..9ffbe1a68b874 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -58,6 +58,8 @@ use rustc::hir::{self, CodegenFnAttrFlags, CodegenFnAttrs, Unsafety}; use std::iter; +struct OnlySelfBounds(bool); + /////////////////////////////////////////////////////////////////////////// // Main entry point @@ -331,7 +333,7 @@ impl<'a, 'tcx> ItemCtxt<'a, 'tcx> { ast_generics: &hir::Generics, param_id: ast::NodeId, ty: Ty<'tcx>, - only_self_bounds: bool, + only_self_bounds: OnlySelfBounds, ) -> Vec<(ty::Predicate<'tcx>, Span)> { let from_ty_params = ast_generics .params @@ -354,12 +356,10 @@ impl<'a, 'tcx> ItemCtxt<'a, 'tcx> { .flat_map(|bp| { let bt = if is_param(self.tcx, &bp.bounded_ty, param_id) { Some(ty) + } else if only_self_bounds.0 { + None } else { - if only_self_bounds { - None - } else { - Some(self.to_ty(&bp.bounded_ty)) - } + Some(self.to_ty(&bp.bounded_ty)) }; bp.bounds.iter().filter_map(move |b| { if let Some(bt) = bt { Some((bt, b)) } else { None } @@ -710,7 +710,10 @@ fn super_predicates_of<'a, 'tcx>( let superbounds1 = superbounds1.predicates(tcx, self_param_ty); // Convert any explicit superbounds in the where clause, - // e.g. `trait Foo where Self : Bar`: + // e.g. `trait Foo where Self : Bar`. + // In the case of trait aliases, however, we include all bounds in the where clause, + // so e.g. `trait Foo = where u32: PartialEq` would include `u32: PartialEq` + // as one of its "superpredicates". let is_trait_alias = ty::is_trait_alias(tcx, trait_def_id); let superbounds2 = icx.type_parameter_bounds_in_generics( generics, item.id, self_param_ty, !is_trait_alias); From a62d0785a6b0770f2241a3e91853d842609d4d7c Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Thu, 1 Nov 2018 03:08:04 +0000 Subject: [PATCH 08/10] Fixed unsoundness hole. --- src/librustc/ty/sty.rs | 2 +- src/librustc_typeck/astconv.rs | 11 ++++++----- src/librustc_typeck/collect.rs | 10 ++++++++-- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 62e38ad9bfa66..49cd87e2dc54e 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -636,7 +636,7 @@ impl<'tcx> TraitRef<'tcx> { TraitRef { def_id: def_id, substs: substs } } - /// Returns a TraitRef of the form `P0: Foo` where `Pi` + /// Returns a `TraitRef` of the form `P0: Foo` where `Pi` /// are the parameters defined on trait. pub fn identity<'a, 'gcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, def_id: DefId) -> TraitRef<'tcx> { TraitRef { diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 9556be6ebfc1c..e44cfec82ad64 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -974,9 +974,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { let principal = self.instantiate_poly_trait_ref(&trait_bounds[0], dummy_self, &mut projection_bounds); + debug!("principal: {:?}", principal); for trait_bound in trait_bounds[1..].iter() { - // Sanity check for non-principal trait bounds + // sanity check for non-principal trait bounds self.instantiate_poly_trait_ref(trait_bound, dummy_self, &mut vec![]); @@ -1008,9 +1009,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { }) }); - // check that there are no gross object safety violations, + // Check that there are no gross object safety violations; // most importantly, that the supertraits don't contain Self, - // to avoid ICE-s. + // to avoid ICEs. let object_safety_violations = tcx.astconv_object_safety_violations(principal.def_id()); if !object_safety_violations.is_empty() { @@ -1020,7 +1021,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { return tcx.types.err; } - // use a BTreeSet to keep output in a more consistent order + // Use a BTreeSet to keep output in a more consistent order. let mut associated_types = BTreeSet::default(); for tr in traits::supertraits(tcx, principal) { @@ -1059,7 +1060,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { v.sort_by(|a, b| a.stable_cmp(tcx, b)); let existential_predicates = ty::Binder::bind(tcx.mk_existential_predicates(v.into_iter())); - // Explicitly specified region bound. Use that. + // Use explicitly-specified region bound. let region_bound = if !lifetime.is_elided() { self.ast_region_to_region(lifetime, None) } else { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 9ffbe1a68b874..917fb887e0b89 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -319,7 +319,8 @@ fn type_param_predicates<'a, 'tcx>( let icx = ItemCtxt::new(tcx, item_def_id); result .predicates - .extend(icx.type_parameter_bounds_in_generics(ast_generics, param_id, ty, true)); + .extend(icx.type_parameter_bounds_in_generics(ast_generics, param_id, ty, + OnlySelfBounds(true))); result } @@ -716,7 +717,7 @@ fn super_predicates_of<'a, 'tcx>( // as one of its "superpredicates". let is_trait_alias = ty::is_trait_alias(tcx, trait_def_id); let superbounds2 = icx.type_parameter_bounds_in_generics( - generics, item.id, self_param_ty, !is_trait_alias); + generics, item.id, self_param_ty, OnlySelfBounds(!is_trait_alias)); // Combine the two lists to form the complete set of superbounds: let superbounds: Vec<_> = superbounds1.into_iter().chain(superbounds2).collect(); @@ -1694,6 +1695,7 @@ fn explicit_predicates_of<'a, 'tcx>( let icx = ItemCtxt::new(tcx, def_id); let no_generics = hir::Generics::empty(); + let empty_trait_items = HirVec::new(); let mut predicates = UniquePredicates::new(); @@ -1738,6 +1740,10 @@ fn explicit_predicates_of<'a, 'tcx>( is_trait = Some((ty::TraitRef::identity(tcx, def_id), items)); generics } + ItemKind::TraitAlias(ref generics, _) => { + is_trait = Some((ty::TraitRef::identity(tcx, def_id), &empty_trait_items)); + generics + } ItemKind::Existential(ExistTy { ref bounds, impl_trait_fn, From c04559fe9eb14e59cfe35c2676cd5d93a5eab326 Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Thu, 1 Nov 2018 18:17:58 +0000 Subject: [PATCH 09/10] Added WF checking for trait alias definitions. --- src/librustc_typeck/check/wfcheck.rs | 3 ++ src/test/ui/traits/trait-alias-fail1.stderr | 46 ------------------- src/test/ui/traits/trait-alias-fail2.stderr | 19 -------- src/test/ui/traits/trait-alias-impl.rs | 17 +++++++ src/test/ui/traits/trait-alias-impl.stderr | 9 ++++ ...-alias-fail2.rs => trait-alias-objects.rs} | 0 src/test/ui/traits/trait-alias-objects.stderr | 18 ++++++++ ...trait-alias-fail1.rs => trait-alias-wf.rs} | 7 +-- src/test/ui/traits/trait-alias-wf.stderr | 16 +++++++ 9 files changed, 64 insertions(+), 71 deletions(-) delete mode 100644 src/test/ui/traits/trait-alias-fail1.stderr delete mode 100644 src/test/ui/traits/trait-alias-fail2.stderr create mode 100644 src/test/ui/traits/trait-alias-impl.rs create mode 100644 src/test/ui/traits/trait-alias-impl.stderr rename src/test/ui/traits/{trait-alias-fail2.rs => trait-alias-objects.rs} (100%) create mode 100644 src/test/ui/traits/trait-alias-objects.stderr rename src/test/ui/traits/{trait-alias-fail1.rs => trait-alias-wf.rs} (72%) create mode 100644 src/test/ui/traits/trait-alias-wf.stderr diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index ea84e874b1a5b..527ba276de273 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -153,6 +153,9 @@ pub fn check_item_well_formed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: Def hir::ItemKind::Trait(..) => { check_trait(tcx, item); } + hir::ItemKind::TraitAlias(..) => { + check_trait(tcx, item); + } _ => {} } } diff --git a/src/test/ui/traits/trait-alias-fail1.stderr b/src/test/ui/traits/trait-alias-fail1.stderr deleted file mode 100644 index 447f4b1b9de98..0000000000000 --- a/src/test/ui/traits/trait-alias-fail1.stderr +++ /dev/null @@ -1,46 +0,0 @@ -error: type parameters on the left side of a trait alias cannot be bounded - --> $DIR/trait-alias-fail1.rs:14:20 - | -LL | trait BoundedAlias = Default; - | ^ - -error: type parameters on the left side of a trait alias cannot have defaults - --> $DIR/trait-alias-fail1.rs:14:20 - | -LL | trait BoundedAlias = Default; - | ^ - -error[E0404]: expected trait, found trait alias `CloneDefault` - --> $DIR/trait-alias-fail1.rs:19:6 - | -LL | impl CloneDefault for () {} - | ^^^^^^^^^^^^ not a trait - -error[E0658]: trait aliases are experimental (see issue #41517) - --> $DIR/trait-alias-fail1.rs:13:1 - | -LL | trait CloneDefault = Default where T: Clone; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(trait_alias)] to the crate attributes to enable - -error[E0658]: trait aliases are experimental (see issue #41517) - --> $DIR/trait-alias-fail1.rs:14:1 - | -LL | trait BoundedAlias = Default; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(trait_alias)] to the crate attributes to enable - -error[E0658]: trait aliases are experimental (see issue #41517) - --> $DIR/trait-alias-fail1.rs:17:1 - | -LL | trait B = A; // FIXME: parameter T should need a bound here, or semantics should be changed - | ^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(trait_alias)] to the crate attributes to enable - -error: aborting due to 6 previous errors - -Some errors occurred: E0404, E0658. -For more information about an error, try `rustc --explain E0404`. diff --git a/src/test/ui/traits/trait-alias-fail2.stderr b/src/test/ui/traits/trait-alias-fail2.stderr deleted file mode 100644 index 6ebd8b5e73174..0000000000000 --- a/src/test/ui/traits/trait-alias-fail2.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0658]: trait aliases are experimental (see issue #41517) - --> $DIR/trait-alias-fail2.rs:13:1 - | -LL | trait EqAlias = Eq; - | ^^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(trait_alias)] to the crate attributes to enable - -error[E0658]: trait aliases are experimental (see issue #41517) - --> $DIR/trait-alias-fail2.rs:14:1 - | -LL | trait IteratorAlias = Iterator; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(trait_alias)] to the crate attributes to enable - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/traits/trait-alias-impl.rs b/src/test/ui/traits/trait-alias-impl.rs new file mode 100644 index 0000000000000..bf3483000e3bc --- /dev/null +++ b/src/test/ui/traits/trait-alias-impl.rs @@ -0,0 +1,17 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(trait_alias)] + +trait DefaultAlias = Default; + +impl DefaultAlias for () {} + +fn main() {} diff --git a/src/test/ui/traits/trait-alias-impl.stderr b/src/test/ui/traits/trait-alias-impl.stderr new file mode 100644 index 0000000000000..9ad625176b148 --- /dev/null +++ b/src/test/ui/traits/trait-alias-impl.stderr @@ -0,0 +1,9 @@ +error[E0404]: expected trait, found trait alias `DefaultAlias` + --> $DIR/trait-alias-impl.rs:15:6 + | +LL | impl DefaultAlias for () {} + | ^^^^^^^^^^^^ not a trait + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0404`. diff --git a/src/test/ui/traits/trait-alias-fail2.rs b/src/test/ui/traits/trait-alias-objects.rs similarity index 100% rename from src/test/ui/traits/trait-alias-fail2.rs rename to src/test/ui/traits/trait-alias-objects.rs diff --git a/src/test/ui/traits/trait-alias-objects.stderr b/src/test/ui/traits/trait-alias-objects.stderr new file mode 100644 index 0000000000000..8f9681e898fe8 --- /dev/null +++ b/src/test/ui/traits/trait-alias-objects.stderr @@ -0,0 +1,18 @@ +error[E0038]: the trait `EqAlias` cannot be made into an object + --> $DIR/trait-alias-objects.rs:17:13 + | +LL | let _: &dyn EqAlias = &123; + | ^^^^^^^^^^^ the trait `EqAlias` cannot be made into an object + | + = note: the trait cannot use `Self` as a type parameter in the supertraits or where-clauses + +error[E0191]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified + --> $DIR/trait-alias-objects.rs:18:13 + | +LL | let _: &dyn IteratorAlias = &vec![123].into_iter(); + | ^^^^^^^^^^^^^^^^^ missing associated type `Item` value + +error: aborting due to 2 previous errors + +Some errors occurred: E0038, E0191. +For more information about an error, try `rustc --explain E0038`. diff --git a/src/test/ui/traits/trait-alias-fail1.rs b/src/test/ui/traits/trait-alias-wf.rs similarity index 72% rename from src/test/ui/traits/trait-alias-fail1.rs rename to src/test/ui/traits/trait-alias-wf.rs index 25c850db6ce41..8c8ce1221ba35 100644 --- a/src/test/ui/traits/trait-alias-fail1.rs +++ b/src/test/ui/traits/trait-alias-wf.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 The Rust Project Developers. See the COPYRIGHT +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -10,13 +10,8 @@ #![feature(trait_alias)] -trait CloneDefault = Default where T: Clone; -trait BoundedAlias = Default; - trait Foo {} trait A {} trait B = A; // T cannot be unbounded -impl CloneDefault for () {} - fn main() {} diff --git a/src/test/ui/traits/trait-alias-wf.stderr b/src/test/ui/traits/trait-alias-wf.stderr new file mode 100644 index 0000000000000..e8c81c87796f3 --- /dev/null +++ b/src/test/ui/traits/trait-alias-wf.stderr @@ -0,0 +1,16 @@ +error[E0277]: the trait bound `T: Foo` is not satisfied + --> $DIR/trait-alias-wf.rs:15:1 + | +LL | trait B = A; // T cannot be unbounded + | ^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `T` + | + = help: consider adding a `where T: Foo` bound +note: required by `A` + --> $DIR/trait-alias-wf.rs:14:1 + | +LL | trait A {} + | ^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. From 417168587beda80b97e9de83b61cbb8517a61dbc Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Thu, 1 Nov 2018 21:52:56 +0000 Subject: [PATCH 10/10] Fixed bug with Self type param coming before lifetimes. --- src/librustc/middle/resolve_lifetime.rs | 19 ++++++++--- src/librustc_typeck/collect.rs | 10 +++--- .../run-pass/traits/trait-alias-bounds.rs | 21 +----------- .../run-pass/traits/trait-alias-syntax.rs | 32 +++++++++++++++++++ 4 files changed, 52 insertions(+), 30 deletions(-) create mode 100644 src/test/run-pass/traits/trait-alias-syntax.rs diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 361abb1689619..a387765085a29 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -447,6 +447,17 @@ fn krate<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>) -> NamedRegionMap { map } +/// In traits, there is an implicit `Self` type parameter which comes before the generics. +/// We have to account for this when computing the index of the other generic parameters. +/// This function returns whether there is such an implicit parameter defined on the given item. +fn sub_items_have_self_param(node: &hir::ItemKind) -> bool { + match *node { + hir::ItemKind::Trait(..) | + hir::ItemKind::TraitAlias(..) => true, + _ => false, + } +} + impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { NestedVisitorMap::All(&self.tcx.hir) @@ -522,8 +533,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { hir::ItemKind::Impl(..) => true, _ => false, }; - // These kinds of items have only early bound lifetime parameters. - let mut index = if let hir::ItemKind::Trait(..) = item.node { + // These kinds of items have only early-bound lifetime parameters. + let mut index = if sub_items_have_self_param(&item.node) { 1 // Self comes before lifetimes } else { 0 @@ -1602,8 +1613,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let mut index = 0; if let Some(parent_id) = parent_id { let parent = self.tcx.hir.expect_item(parent_id); - if let hir::ItemKind::Trait(..) = parent.node { - index += 1; // Self comes first. + if sub_items_have_self_param(&parent.node) { + index += 1; // Self comes before lifetimes } match parent.node { hir::ItemKind::Trait(_, _, ref generics, ..) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 917fb887e0b89..c136d76e358d3 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -357,14 +357,12 @@ impl<'a, 'tcx> ItemCtxt<'a, 'tcx> { .flat_map(|bp| { let bt = if is_param(self.tcx, &bp.bounded_ty, param_id) { Some(ty) - } else if only_self_bounds.0 { - None - } else { + } else if !only_self_bounds.0 { Some(self.to_ty(&bp.bounded_ty)) + } else { + None }; - bp.bounds.iter().filter_map(move |b| { - if let Some(bt) = bt { Some((bt, b)) } else { None } - }) + bp.bounds.iter().filter_map(move |b| bt.map(|bt| (bt, b))) }) .flat_map(|(bt, b)| predicates_from_bound(self, bt, b)); diff --git a/src/test/run-pass/traits/trait-alias-bounds.rs b/src/test/run-pass/traits/trait-alias-bounds.rs index c1c3989107b28..d8ac1a8c63464 100644 --- a/src/test/run-pass/traits/trait-alias-bounds.rs +++ b/src/test/run-pass/traits/trait-alias-bounds.rs @@ -1,4 +1,4 @@ -// Copyright 2017-2018 The Rust Project Developers. See the COPYRIGHT +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -12,25 +12,6 @@ use std::marker::PhantomData; -trait SimpleAlias = Default; -trait GenericAlias = Iterator; -trait Partial = IntoIterator; -trait SpecificAlias = GenericAlias; -trait PartialEqRef<'a, T> = PartialEq<&'a T>; -trait StaticAlias = 'static; - -trait Things {} -trait Romeo {} -#[allow(dead_code)] -struct The(T); -#[allow(dead_code)] -struct Fore(T); -impl Things for The {} -impl Romeo for Fore {} - -trait WithWhere = Romeo + Romeo where Fore<(Art, Thou)>: Romeo; -trait BareWhere = where The: Things; - trait Empty {} trait EmptyAlias = Empty; trait CloneDefault = Clone + Default; diff --git a/src/test/run-pass/traits/trait-alias-syntax.rs b/src/test/run-pass/traits/trait-alias-syntax.rs new file mode 100644 index 0000000000000..a9b7afb0ea343 --- /dev/null +++ b/src/test/run-pass/traits/trait-alias-syntax.rs @@ -0,0 +1,32 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(trait_alias)] + +trait SimpleAlias = Default; +trait GenericAlias = Iterator; +trait Partial = IntoIterator; +trait SpecificAlias = GenericAlias; +trait PartialEqRef<'a, T: 'a> = PartialEq<&'a T>; +trait StaticAlias = 'static; + +trait Things {} +trait Romeo {} +#[allow(dead_code)] +struct The(T); +#[allow(dead_code)] +struct Fore(T); +impl Things for The {} +impl Romeo for Fore {} + +trait WithWhere = Romeo + Romeo where Fore<(Art, Thou)>: Romeo; +trait BareWhere = where The: Things; + +fn main() {}