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); +} +``` 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/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 a93e31480f3bb..7d25ecedb4e04 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -1118,6 +1118,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), } } } @@ -1226,6 +1227,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/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/traits/mod.rs b/src/librustc/traits/mod.rs index 5e2f1fe08b90e..b7512790bfb69 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 80358294d056c..a388c7eeb7e49 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 45dad508af560..312cd66dcc75c 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_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. 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(_)) => { @@ -2238,6 +2243,24 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } } + 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_trait_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 // @@ -2288,7 +2311,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. @@ -2318,7 +2342,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. @@ -2712,15 +2737,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)?; @@ -2732,13 +2762,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 => { @@ -2746,13 +2777,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())) } @@ -2865,7 +2895,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>, @@ -2922,7 +2952,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, @@ -2986,10 +3016,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 { @@ -3041,7 +3071,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()); @@ -3077,11 +3107,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 @@ -3139,7 +3209,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/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/instance.rs b/src/librustc/ty/instance.rs index 2fc8ef548fa04..b6691df39c120 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 7d693cd5523df..c7c197d11c03b 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1046,24 +1046,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), @@ -2797,7 +2797,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) } @@ -2811,14 +2811,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) { @@ -2983,7 +2983,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) { @@ -2995,7 +2995,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/ty/sty.rs b/src/librustc/ty/sty.rs index 6929cb988d051..28b58d62175bc 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -650,7 +650,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/ty/util.rs b/src/librustc/ty/util.rs index 1b1bbfd4deb8b..9ba5bf9add110 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_resolve/lib.rs b/src/librustc_resolve/lib.rs index 7b5e704f60f6e..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 { @@ -3888,7 +3891,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 +3899,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/astconv.rs b/src/librustc_typeck/astconv.rs index 46f2c0c76a0c7..18f8473b5b56d 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, @@ -545,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. @@ -722,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); @@ -739,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 } @@ -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); @@ -975,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![]); @@ -1009,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.global_tcx().astconv_object_safety_violations(principal.def_id()); if !object_safety_violations.is_empty() { @@ -1021,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) { @@ -1060,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 { @@ -1347,7 +1347,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 +1442,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/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/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index bf3887ee8fcdd..74dea7fe411ad 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 @@ -245,8 +247,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 +319,13 @@ 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, + OnlySelfBounds(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 +334,7 @@ impl<'a, 'tcx> ItemCtxt<'a, 'tcx> { ast_generics: &hir::Generics, param_id: ast::NodeId, ty: Ty<'tcx>, + only_self_bounds: OnlySelfBounds, ) -> Vec<(ty::Predicate<'tcx>, Span)> { let from_ty_params = ast_generics .params @@ -350,9 +354,17 @@ 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.0 { + Some(self.to_ty(&bp.bounded_ty)) + } else { + None + }; + bp.bounds.iter().filter_map(move |b| bt.map(|bt| (bt, b))) + }) + .flat_map(|(bt, b)| predicates_from_bound(self, bt, b)); from_ty_params.chain(from_where_clauses).collect() } @@ -419,12 +431,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); @@ -693,15 +702,20 @@ 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); let superbounds1 = superbounds1.predicates(tcx, self_param_ty); // 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); + // 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, OnlySelfBounds(!is_trait_alias)); // Combine the two lists to form the complete set of superbounds: let superbounds: Vec<_> = superbounds1.into_iter().chain(superbounds2).collect(); @@ -709,6 +723,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()); } @@ -1678,6 +1693,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(); @@ -1722,6 +1738,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, @@ -2010,10 +2030,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/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/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/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index be448f960df3f..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> { /* @@ -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)? } @@ -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/run-pass/traits/trait-alias-bounds.rs b/src/test/run-pass/traits/trait-alias-bounds.rs new file mode 100644 index 0000000000000..d8ac1a8c63464 --- /dev/null +++ b/src/test/run-pass/traits/trait-alias-bounds.rs @@ -0,0 +1,65 @@ +// 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)] + +use std::marker::PhantomData; + +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 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 = a::(); + assert_eq!(both.0, 0); + assert_eq!(both.1, 0); + 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 new file mode 100644 index 0000000000000..17e30922b2cb8 --- /dev/null +++ b/src/test/run-pass/traits/trait-alias-object-type.rs @@ -0,0 +1,27 @@ +// 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 = PartialEq + Send; +trait Bar = Foo + Sync; + +trait I32Iterator = Iterator; + +pub fn main() { + 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/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() {} 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/trait-alias-fail.stderr b/src/test/ui/trait-alias-fail.stderr deleted file mode 100644 index f7b144c06f80a..0000000000000 --- a/src/test/ui/trait-alias-fail.stderr +++ /dev/null @@ -1,44 +0,0 @@ -error: type parameters on the left side of a trait alias cannot be bounded - --> $DIR/trait-alias-fail.rs:15: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 - | -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 - | -LL | impl Alias1 for () { //~ERROR expected trait, found trait alias - | ^^^^^^ not a trait - -error[E0658]: trait aliases are not yet fully implemented (see issue #41517) - --> $DIR/trait-alias-fail.rs:13:1 - | -LL | trait Alias1 = Default where T: Clone; // ok - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 - | -LL | trait Alias2 = Default; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(trait_alias)] to the crate attributes to enable - -error: aborting due to 6 previous errors - -Some errors occurred: E0404, E0573, E0658. -For more information about an error, try `rustc --explain E0404`. 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-objects.rs b/src/test/ui/traits/trait-alias-objects.rs new file mode 100644 index 0000000000000..3adcd8436d8a1 --- /dev/null +++ b/src/test/ui/traits/trait-alias-objects.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. + +#![feature(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-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-wf.rs b/src/test/ui/traits/trait-alias-wf.rs new file mode 100644 index 0000000000000..8c8ce1221ba35 --- /dev/null +++ b/src/test/ui/traits/trait-alias-wf.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 Foo {} +trait A {} +trait B = A; // T cannot be unbounded + +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`. diff --git a/src/test/ui/traits/trait-alias.rs b/src/test/ui/traits/trait-alias.rs deleted file mode 100644 index 9ea211b4d7d69..0000000000000 --- a/src/test/ui/traits/trait-alias.rs +++ /dev/null @@ -1,43 +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. - -#![feature(trait_alias)] - -trait SimpleAlias = Default; //~ERROR E0645 -trait GenericAlias = Iterator; //~ERROR E0645 -trait Partial = IntoIterator; //~ERROR E0645 - -trait Things {} -trait Romeo {} -struct The(T); -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 CD = Clone + Default; //~ERROR E0645 - -fn foo() -> (T, T) { - let one = T::default(); - let two = one.clone(); - (one, two) -} - -fn main() { - 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/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`.