diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs index 3ef0633e7f4..19a37b693db 100644 --- a/src/librustc/hir/def.rs +++ b/src/librustc/hir/def.rs @@ -37,6 +37,7 @@ pub enum Def { Trait(DefId), TyAlias(DefId), TyForeign(DefId), + TraitAlias(DefId), AssociatedTy(DefId), PrimTy(hir::PrimTy), TyParam(DefId), @@ -155,7 +156,8 @@ impl Def { pub fn def_id(&self) -> DefId { match *self { Def::Fn(id) | Def::Mod(id) | Def::Static(id, _) | - Def::Variant(id) | Def::VariantCtor(id, ..) | Def::Enum(id) | Def::TyAlias(id) | + Def::Variant(id) | Def::VariantCtor(id, ..) | Def::Enum(id) | + Def::TyAlias(id) | Def::TraitAlias(id) | Def::AssociatedTy(id) | Def::TyParam(id) | Def::Struct(id) | Def::StructCtor(id, ..) | Def::Union(id) | Def::Trait(id) | Def::Method(id) | Def::Const(id) | Def::AssociatedConst(id) | Def::Macro(id, ..) | @@ -186,6 +188,7 @@ impl Def { Def::VariantCtor(.., CtorKind::Fictive) => "struct variant", Def::Enum(..) => "enum", Def::TyAlias(..) => "type alias", + Def::TraitAlias(..) => "trait alias", Def::AssociatedTy(..) => "associated type", Def::Struct(..) => "struct", Def::StructCtor(.., CtorKind::Fn) => "tuple struct", diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index c9d35158ed0..eacad100f10 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -526,6 +526,11 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { walk_list!(visitor, visit_ty_param_bound, bounds); walk_list!(visitor, visit_trait_item_ref, trait_item_refs); } + ItemTraitAlias(ref generics, ref bounds) => { + visitor.visit_id(item.id); + visitor.visit_generics(generics); + walk_list!(visitor, visit_ty_param_bound, bounds); + } } walk_list!(visitor, visit_attribute, &item.attrs); } diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index e3a5e835bb9..b544ea820c0 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1924,9 +1924,11 @@ impl<'a> LoweringContext<'a> { bounds, items) } - ItemKind::MacroDef(..) | ItemKind::Mac(..) => { - panic!("Shouldn't still be around") + ItemKind::TraitAlias(ref generics, ref bounds) => { + hir::ItemTraitAlias(self.lower_generics(generics), + self.lower_bounds(bounds, ImplTraitContext::Disallowed)) } + ItemKind::MacroDef(..) | ItemKind::Mac(..) => panic!("Shouldn't still be around"), } // [1] `defaultness.has_value()` is never called for an `impl`, always `true` in order to diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index 17a4c66edb9..2978f1eb409 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -106,7 +106,8 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { let def_data = match i.node { ItemKind::AutoImpl(..) | ItemKind::Impl(..) => DefPathData::Impl, - ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) | ItemKind::Trait(..) | + ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) | + ItemKind::Trait(..) | ItemKind::TraitAlias(..) | ItemKind::ExternCrate(..) | ItemKind::ForeignMod(..) | ItemKind::Ty(..) => DefPathData::TypeNs(i.ident.name.as_str()), ItemKind::Mod(..) if i.ident == keywords::Invalid.ident() => { diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 8969528dd19..014e5771656 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -1185,6 +1185,7 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String { ItemStruct(..) => "struct", ItemUnion(..) => "union", ItemTrait(..) => "trait", + ItemTraitAlias(..) => "trait alias", ItemImpl(..) => "impl", ItemAutoImpl(..) => "default impl", }; diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index d6107a8f551..dc44a943e4c 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1888,6 +1888,8 @@ pub enum Item_ { ItemUnion(VariantData, Generics), /// Represents a Trait Declaration ItemTrait(IsAuto, Unsafety, Generics, TyParamBounds, HirVec), + /// Represents a Trait Alias Declaration + ItemTraitAlias(Generics, TyParamBounds), /// Auto trait implementations /// @@ -1919,6 +1921,7 @@ impl Item_ { ItemStruct(..) => "struct", ItemUnion(..) => "union", ItemTrait(..) => "trait", + ItemTraitAlias(..) => "trait alias", ItemImpl(..) | ItemAutoImpl(..) => "item", } diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index fb502ecb996..c7bb121e901 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -747,6 +747,27 @@ impl<'a> State<'a> { } self.bclose(item.span)?; } + hir::ItemTraitAlias(ref generics, ref bounds) => { + self.head("")?; + self.print_visibility(&item.vis)?; + self.word_nbsp("trait")?; + self.print_name(item.name)?; + self.print_generics(generics)?; + let mut real_bounds = Vec::with_capacity(bounds.len()); + // FIXME(durka) this seems to be some quite outdated syntax + for b in bounds.iter() { + if let TraitTyParamBound(ref ptr, hir::TraitBoundModifier::Maybe) = *b { + self.s.space()?; + self.word_space("for ?")?; + self.print_trait_ref(&ptr.trait_ref)?; + } else { + real_bounds.push(b.clone()); + } + } + self.print_bounds(" = ", &real_bounds[..])?; + self.print_where_clause(&generics.where_clause)?; + self.s.word(";")?; + } } self.ann.post(self, NodeItem(item)) } diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 6fc49e5189d..ff5327ced8b 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -848,6 +848,7 @@ impl_stable_hash_for!(enum hir::Item_ { ItemStruct(variant_data, generics), ItemUnion(variant_data, generics), ItemTrait(is_auto, unsafety, generics, bounds, item_refs), + ItemTraitAlias(generics, bounds), ItemAutoImpl(unsafety, trait_ref), ItemImpl(unsafety, impl_polarity, impl_defaultness, generics, trait_ref, ty, impl_item_refs) }); @@ -1004,6 +1005,7 @@ impl_stable_hash_for!(enum hir::def::Def { Variant(def_id), Trait(def_id), TyAlias(def_id), + TraitAlias(def_id), AssociatedTy(def_id), PrimTy(prim_ty), TyParam(def_id), diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index d5f26d1117c..27f12c2c158 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -268,7 +268,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { hir::ItemExternCrate(_) | hir::ItemUse(..) | hir::ItemTy(..) | hir::ItemStatic(..) | hir::ItemMod(..) | hir::ItemForeignMod(..) | - hir::ItemImpl(..) | hir::ItemTrait(..) | + hir::ItemImpl(..) | hir::ItemTrait(..) | hir::ItemTraitAlias(..) | hir::ItemStruct(..) | hir::ItemEnum(..) | hir::ItemUnion(..) | hir::ItemAutoImpl(..) | hir::ItemGlobalAsm(..) => {} diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index d9b2bf62841..e75762cbacb 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -469,6 +469,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { | hir::ItemStruct(_, ref generics) | hir::ItemUnion(_, ref generics) | hir::ItemTrait(_, _, ref generics, ..) + | hir::ItemTraitAlias(ref generics, ..) | hir::ItemImpl(_, _, _, ref generics, ..) => { // These kinds of items have only early bound lifetime parameters. let mut index = if let hir::ItemTrait(..) = item.node { diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 93ef29855ce..4e1a79d4613 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2577,6 +2577,7 @@ fn associated_item_def_ids<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, .map(|id| tcx.hir.local_def_id(id.node_id)) .collect() } + hir::ItemTraitAlias(..) => vec![], _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait") }; Rc::new(vec) diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index f04e01f3f96..ded2fa01e59 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -248,6 +248,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { hir::ItemStruct(..) | hir::ItemUnion(..) | hir::ItemTrait(..) | + hir::ItemTraitAlias(..) | hir::ItemImpl(..) | hir::ItemAutoImpl(..) => None, diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index caeee989283..5e8bbabee4a 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -979,6 +979,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { EntryKind::Trait(self.lazy(&data)) } hir::ItemExternCrate(_) | + hir::ItemTraitAlias(..) | hir::ItemUse(..) => bug!("cannot encode info for item {:?}", item), }; @@ -1526,7 +1527,8 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { hir::ItemExternCrate(..) | hir::ItemUse(..) | hir::ItemAutoImpl(..) | - hir::ItemTy(..) => { + hir::ItemTy(..) | + hir::ItemTraitAlias(..) => { // no sub-item recording needed in these cases } hir::ItemEnum(..) => { diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 05ad1643619..96c9323e7dc 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -283,6 +283,20 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } } } + ItemKind::TraitAlias(Generics { ref ty_params, .. }, ..) => { + for &TyParam { ref bounds, ref default, span, .. } in ty_params { + if !bounds.is_empty() { + self.err_handler().span_err(span, + "type parameters on the left side of a \ + trait alias cannot be bounded"); + } + if !default.is_none() { + self.err_handler().span_err(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_privacy/lib.rs b/src/librustc_privacy/lib.rs index 27898b5dd64..d4188121812 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -158,7 +158,8 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { // Other `pub` items inherit levels from parents hir::ItemConst(..) | hir::ItemEnum(..) | hir::ItemExternCrate(..) | hir::ItemGlobalAsm(..) | hir::ItemFn(..) | hir::ItemMod(..) | - hir::ItemStatic(..) | hir::ItemStruct(..) | hir::ItemTrait(..) | + hir::ItemStatic(..) | hir::ItemStruct(..) | + hir::ItemTrait(..) | hir::ItemTraitAlias(..) | hir::ItemTy(..) | hir::ItemUnion(..) | hir::ItemUse(..) => { if item.vis == hir::Public { self.prev_level } else { None } } @@ -212,7 +213,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { } } hir::ItemUse(..) | hir::ItemStatic(..) | hir::ItemConst(..) | - hir::ItemGlobalAsm(..) | hir::ItemTy(..) | hir::ItemMod(..) | + hir::ItemGlobalAsm(..) | hir::ItemTy(..) | hir::ItemMod(..) | hir::ItemTraitAlias(..) | hir::ItemFn(..) | hir::ItemExternCrate(..) | hir::ItemAutoImpl(..) => {} } @@ -252,6 +253,11 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { } } } + hir::ItemTraitAlias(..) => { + if item_level.is_some() { + self.reach(item.id).generics().predicates(); + } + } // Visit everything except for private impl items hir::ItemImpl(.., ref trait_ref, _, ref impl_item_refs) => { if item_level.is_some() { @@ -1498,6 +1504,9 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> } } } + hir::ItemTraitAlias(..) => { + self.check(item.id, item_visibility).generics().predicates(); + } hir::ItemEnum(ref def, _) => { self.check(item.id, item_visibility).generics().predicates(); diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 8df6458b72e..3b20c1e74cd 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -344,6 +344,11 @@ impl<'a> Resolver<'a> { } } + ItemKind::TraitAlias(..) => { + let def = Def::TraitAlias(self.definitions.local_def_id(item.id)); + self.define(parent, ident, TypeNS, (def, vis, sp, expansion)); + } + // These items live in both the type and value namespaces. ItemKind::Struct(ref struct_def, _) => { // Define a name in the type namespace. @@ -411,6 +416,7 @@ impl<'a> Resolver<'a> { self.define(parent, ident, TypeNS, (module, vis, sp, expansion)); self.current_module = module; } + ItemKind::MacroDef(..) | ItemKind::Mac(_) => unreachable!(), } } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 33e57b2d180..c42ac7aaa93 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -390,12 +390,18 @@ impl PatternSource { } } +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +enum AliasPossibility { + No, + Maybe, +} + #[derive(Copy, Clone, PartialEq, Eq, Debug)] enum PathSource<'a> { // Type paths `Path`. Type, // Trait paths in bounds or impls. - Trait, + Trait(AliasPossibility), // Expression paths `path`, with optional parent context. Expr(Option<&'a Expr>), // Paths in path patterns `Path`. @@ -415,7 +421,7 @@ enum PathSource<'a> { impl<'a> PathSource<'a> { fn namespace(self) -> Namespace { match self { - PathSource::Type | PathSource::Trait | PathSource::Struct | + PathSource::Type | PathSource::Trait(_) | PathSource::Struct | PathSource::Visibility | PathSource::ImportPrefix => TypeNS, PathSource::Expr(..) | PathSource::Pat | PathSource::TupleStruct => ValueNS, PathSource::TraitItem(ns) => ns, @@ -427,7 +433,7 @@ impl<'a> PathSource<'a> { PathSource::Visibility | PathSource::ImportPrefix => true, PathSource::Type | PathSource::Expr(..) | PathSource::Pat | PathSource::Struct | PathSource::TupleStruct | - PathSource::Trait | PathSource::TraitItem(..) => false, + PathSource::Trait(_) | PathSource::TraitItem(..) => false, } } @@ -435,7 +441,7 @@ impl<'a> PathSource<'a> { match self { PathSource::Type | PathSource::Expr(..) | PathSource::Pat | PathSource::Struct | PathSource::TupleStruct => true, - PathSource::Trait | PathSource::TraitItem(..) | + PathSource::Trait(_) | PathSource::TraitItem(..) | PathSource::Visibility | PathSource::ImportPrefix => false, } } @@ -443,7 +449,7 @@ impl<'a> PathSource<'a> { fn descr_expected(self) -> &'static str { match self { PathSource::Type => "type", - PathSource::Trait => "trait", + PathSource::Trait(_) => "trait", PathSource::Pat => "unit struct/variant or constant", PathSource::Struct => "struct, variant or union type", PathSource::TupleStruct => "tuple struct/variant", @@ -472,10 +478,15 @@ impl<'a> PathSource<'a> { Def::TyForeign(..) => true, _ => false, }, - PathSource::Trait => match def { + PathSource::Trait(AliasPossibility::No) => match def { Def::Trait(..) => true, _ => false, }, + PathSource::Trait(AliasPossibility::Maybe) => match def { + Def::Trait(..) => true, + Def::TraitAlias(..) => true, + _ => false, + }, PathSource::Expr(..) => match def { Def::StructCtor(_, CtorKind::Const) | Def::StructCtor(_, CtorKind::Fn) | Def::VariantCtor(_, CtorKind::Const) | Def::VariantCtor(_, CtorKind::Fn) | @@ -530,8 +541,8 @@ impl<'a> PathSource<'a> { __diagnostic_used!(E0577); __diagnostic_used!(E0578); match (self, has_unexpected_resolution) { - (PathSource::Trait, true) => "E0404", - (PathSource::Trait, false) => "E0405", + (PathSource::Trait(_), true) => "E0404", + (PathSource::Trait(_), false) => "E0405", (PathSource::Type, true) => "E0573", (PathSource::Type, false) => "E0412", (PathSource::Struct, true) => "E0574", @@ -693,7 +704,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> { tref: &'tcx ast::PolyTraitRef, m: &'tcx ast::TraitBoundModifier) { self.smart_resolve_path(tref.trait_ref.ref_id, None, - &tref.trait_ref.path, PathSource::Trait); + &tref.trait_ref.path, PathSource::Trait(AliasPossibility::Maybe)); visit::walk_poly_trait_ref(self, tref, m); } fn visit_variant(&mut self, @@ -1935,6 +1946,17 @@ impl<'a> Resolver<'a> { }); } + ItemKind::TraitAlias(ref generics, ref bounds) => { + // Create a new rib for the trait-wide type parameters. + self.with_type_parameter_rib(HasTypeParameters(generics, ItemRibKind), |this| { + let local_def_id = this.definitions.local_def_id(item.id); + this.with_self_rib(Def::SelfTy(Some(local_def_id), None), |this| { + this.visit_generics(generics); + walk_list!(this, visit_ty_param_bound, bounds); + }); + }); + } + ItemKind::Mod(_) | ItemKind::ForeignMod(_) => { self.with_scope(item.id, |this| { visit::walk_item(this, item); @@ -2083,7 +2105,7 @@ impl<'a> Resolver<'a> { &path, trait_ref.path.span, trait_ref.path.segments.last().unwrap().span, - PathSource::Trait) + PathSource::Trait(AliasPossibility::No)) .base_def(); if def != Def::Err { new_id = Some(def.def_id()); @@ -2635,7 +2657,7 @@ impl<'a> Resolver<'a> { err.span_label(span, format!("did you mean `{}!(...)`?", path_str)); return (err, candidates); } - (Def::TyAlias(..), PathSource::Trait) => { + (Def::TyAlias(..), PathSource::Trait(_)) => { err.span_label(span, "type aliases cannot be used for traits"); return (err, candidates); } diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 7989dba11f7..fe6ad92ad00 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -285,6 +285,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { HirDef::Enum(..) | HirDef::TyAlias(..) | HirDef::TyForeign(..) | + HirDef::TraitAlias(..) | HirDef::Trait(_) => { let span = self.span_from_span(sub_span.expect("No span found for type ref")); self.dumper.dump_ref(Ref { diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index a815c81a6fe..97f77b20f81 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -721,6 +721,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { HirDef::Enum(def_id) | HirDef::TyAlias(def_id) | HirDef::TyForeign(def_id) | + HirDef::TraitAlias(def_id) | HirDef::AssociatedTy(def_id) | HirDef::Trait(def_id) | HirDef::TyParam(def_id) => { diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs index b244876226c..11d17e0227f 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/src/librustc_save_analysis/sig.rs @@ -487,6 +487,25 @@ impl Sig for ast::Item { Ok(sig) } + ast::ItemKind::TraitAlias(ref generics, ref bounds) => { + let mut text = String::new(); + text.push_str("trait "); + let mut sig = name_and_generics(text, + offset, + generics, + self.id, + self.ident, + scx)?; + + if !bounds.is_empty() { + sig.text.push_str(" = "); + sig.text.push_str(&pprust::bounds_to_string(bounds)); + } + // FIXME where clause + sig.text.push_str(";"); + + Ok(sig) + } ast::ItemKind::AutoImpl(unsafety, ref trait_ref) => { let mut text = String::new(); if unsafety == ast::Unsafety::Unsafe { diff --git a/src/librustc_trans_utils/collector.rs b/src/librustc_trans_utils/collector.rs index e5a97966723..56b1a0238a1 100644 --- a/src/librustc_trans_utils/collector.rs +++ b/src/librustc_trans_utils/collector.rs @@ -894,6 +894,7 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> { hir::ItemTy(..) | hir::ItemAutoImpl(..) | hir::ItemTrait(..) | + hir::ItemTraitAlias(..) | hir::ItemMod(..) => { // Nothing to do, just keep recursing... } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 83aec27c153..6b37a30cb82 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -336,6 +336,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let path = &trait_ref.path; match path.def { Def::Trait(trait_def_id) => trait_def_id, + Def::TraitAlias(alias_def_id) => alias_def_id, Def::Err => { self.tcx().sess.fatal("cannot continue compilation due to previous error"); } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 85b926a707d..3d4d8e65f69 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -441,6 +441,10 @@ fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: ast::NodeId) { tcx.at(it.span).super_predicates_of(def_id); tcx.predicates_of(def_id); }, + hir::ItemTraitAlias(..) => { + span_err!(tcx.sess, it.span, E0645, + "trait aliases are not yet implemented (see issue #41517)"); + }, hir::ItemStruct(ref struct_def, _) | hir::ItemUnion(ref struct_def, _) => { tcx.generics_of(def_id); @@ -672,6 +676,7 @@ fn super_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let (generics, bounds) = match item.node { hir::ItemTrait(.., ref generics, ref supertraits, _) => (generics, supertraits), + hir::ItemTraitAlias(ref generics, ref supertraits) => (generics, supertraits), _ => span_bug!(item.span, "super_predicates invoked on non-trait"), }; @@ -715,6 +720,7 @@ fn trait_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let unsafety = match item.node { hir::ItemTrait(_, unsafety, ..) => unsafety, + hir::ItemTraitAlias(..) => hir::Unsafety::Normal, _ => span_bug!(item.span, "trait_def_of_item invoked on non-trait"), }; @@ -902,7 +908,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (generics, None) } - ItemTrait(_, _, ref generics, ..) => { + ItemTrait(_, _, ref generics, ..) | ItemTraitAlias(ref generics, ..) => { // Add in the self type parameter. // // Something of a hack: use the node id for the trait, also as @@ -1132,7 +1138,7 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.mk_adt(def, substs) } ItemAutoImpl(..) | - ItemTrait(..) | + ItemTrait(..) | ItemTraitAlias(..) | ItemMod(..) | ItemForeignMod(..) | ItemGlobalAsm(..) | diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 328b7f9fdef..770d0cd4f1f 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4721,4 +4721,5 @@ register_diagnostics! { E0632, // cannot provide explicit type parameters when `impl Trait` is used in // argument position. E0641, // cannot cast to/from a pointer with an unknown kind + E0645, // trait aliases not finished } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index fe1dac36be1..be78935cadf 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -512,6 +512,9 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { }; om.traits.push(t); }, + hir::ItemTraitAlias(..) => { + unimplemented!("trait objects are not yet implemented") + }, hir::ItemImpl(unsafety, polarity, diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 3c1d6ea18f7..0d289dbd46b 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1929,6 +1929,10 @@ pub enum ItemKind { /// /// E.g. `trait Foo { .. }`, `trait Foo { .. }` or `auto trait Foo {}` Trait(IsAuto, Unsafety, Generics, TyParamBounds, Vec), + /// Trait alias + /// + /// E.g. `trait Foo = Bar + Quux;` + TraitAlias(Generics, TyParamBounds), /// Auto trait implementation. /// /// E.g. `impl Trait for .. {}` or `impl Trait for .. {}` @@ -1968,6 +1972,7 @@ impl ItemKind { ItemKind::Struct(..) => "struct", ItemKind::Union(..) => "union", ItemKind::Trait(..) => "trait", + ItemKind::TraitAlias(..) => "trait alias", ItemKind::Mac(..) | ItemKind::MacroDef(..) | ItemKind::Impl(..) | diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index c7bfb121f80..ba534676324 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -368,6 +368,8 @@ declare_features! ( // Generators (active, generators, "1.21.0", None), + // Trait aliases + (active, trait_alias, "1.24.0", Some(41517)), // global allocators and their internals (active, global_allocator, "1.20.0", None), @@ -1406,6 +1408,12 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } } + ast::ItemKind::TraitAlias(..) => { + gate_feature_post!(&self, trait_alias, + i.span, + "trait aliases are not yet fully implemented"); + } + ast::ItemKind::AutoImpl(..) => { gate_feature_post!(&self, optin_builtin_traits, i.span, diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 1a92f057e5e..6f973e2bcfa 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -921,6 +921,9 @@ pub fn noop_fold_item_kind(i: ItemKind, folder: &mut T) -> ItemKind { folder.fold_bounds(bounds), items.move_flat_map(|item| folder.fold_trait_item(item)), ), + ItemKind::TraitAlias(generics, bounds) => ItemKind::TraitAlias( + folder.fold_generics(generics), + folder.fold_bounds(bounds)), ItemKind::Mac(m) => ItemKind::Mac(folder.fold_mac(m)), ItemKind::MacroDef(def) => ItemKind::MacroDef(folder.fold_macro_def(def)), } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index b3ef70fd18e..ec77d85f030 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5182,7 +5182,7 @@ impl<'a> Parser<'a> { } } - /// Parse trait Foo { ... } + /// Parse `trait Foo { ... }` or `trait Foo = Bar;` fn parse_item_trait(&mut self, is_auto: IsAuto, unsafety: Unsafety) -> PResult<'a, ItemInfo> { let ident = self.parse_ident()?; let mut tps = self.parse_generics()?; @@ -5194,23 +5194,34 @@ impl<'a> Parser<'a> { Vec::new() }; - tps.where_clause = self.parse_where_clause()?; - - self.expect(&token::OpenDelim(token::Brace))?; - let mut trait_items = vec![]; - while !self.eat(&token::CloseDelim(token::Brace)) { - let mut at_end = false; - match self.parse_trait_item(&mut at_end) { - Ok(item) => trait_items.push(item), - Err(mut e) => { - e.emit(); - if !at_end { - self.recover_stmt_(SemiColonMode::Break, BlockMode::Break); + if self.eat(&token::Eq) { + // it's a trait alias + let bounds = self.parse_ty_param_bounds()?; + tps.where_clause = self.parse_where_clause()?; + self.expect(&token::Semi)?; + if unsafety != Unsafety::Normal { + self.span_err(self.prev_span, "trait aliases cannot be unsafe"); + } + Ok((ident, ItemKind::TraitAlias(tps, bounds), None)) + } else { + // it's a normal trait + tps.where_clause = self.parse_where_clause()?; + self.expect(&token::OpenDelim(token::Brace))?; + let mut trait_items = vec![]; + while !self.eat(&token::CloseDelim(token::Brace)) { + let mut at_end = false; + match self.parse_trait_item(&mut at_end) { + Ok(item) => trait_items.push(item), + Err(mut e) => { + e.emit(); + if !at_end { + self.recover_stmt_(SemiColonMode::Break, BlockMode::Break); + } } } } + Ok((ident, ItemKind::Trait(is_auto, unsafety, tps, bounds, trait_items), None)) } - Ok((ident, ItemKind::Trait(is_auto, unsafety, tps, bounds, trait_items), None)) } /// Parses items implementations variants diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index e4b7dc26d32..e9386e5187f 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1381,6 +1381,27 @@ impl<'a> State<'a> { } self.bclose(item.span)?; } + ast::ItemKind::TraitAlias(ref generics, ref bounds) => { + self.head("")?; + self.print_visibility(&item.vis)?; + self.word_nbsp("trait")?; + self.print_ident(item.ident)?; + self.print_generics(generics)?; + let mut real_bounds = Vec::with_capacity(bounds.len()); + // FIXME(durka) this seems to be some quite outdated syntax + for b in bounds.iter() { + if let TraitTyParamBound(ref ptr, ast::TraitBoundModifier::Maybe) = *b { + self.s.space()?; + self.word_space("for ?")?; + self.print_trait_ref(&ptr.trait_ref)?; + } else { + real_bounds.push(b.clone()); + } + } + self.print_bounds(" = ", &real_bounds[..])?; + self.print_where_clause(&generics.where_clause)?; + self.s.word(";")?; + } ast::ItemKind::Mac(codemap::Spanned { ref node, .. }) => { self.print_path(&node.path, false, 0, false)?; self.s.word("! ")?; diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 9a06ed0ba02..9266cc28097 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -291,6 +291,10 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { walk_list!(visitor, visit_ty_param_bound, bounds); walk_list!(visitor, visit_trait_item, methods); } + ItemKind::TraitAlias(ref generics, ref bounds) => { + visitor.visit_generics(generics); + walk_list!(visitor, visit_ty_param_bound, bounds); + } ItemKind::Mac(ref mac) => visitor.visit_mac(mac), ItemKind::MacroDef(ref ts) => visitor.visit_mac_def(ts, item.id), } diff --git a/src/test/compile-fail/trait-alias.rs b/src/test/compile-fail/trait-alias.rs new file mode 100644 index 00000000000..7aca227a76c --- /dev/null +++ b/src/test/compile-fail/trait-alias.rs @@ -0,0 +1,27 @@ +// 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.rs b/src/test/ui/trait-alias.rs new file mode 100644 index 00000000000..9ea211b4d7d --- /dev/null +++ b/src/test/ui/trait-alias.rs @@ -0,0 +1,43 @@ +// 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/trait-alias.stderr b/src/test/ui/trait-alias.stderr new file mode 100644 index 00000000000..ad299dc8414 --- /dev/null +++ b/src/test/ui/trait-alias.stderr @@ -0,0 +1,38 @@ +error[E0645]: trait aliases are not yet implemented (see issue #41517) + --> $DIR/trait-alias.rs:13:1 + | +13 | trait SimpleAlias = Default; //~ERROR E0645 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0645]: trait aliases are not yet implemented (see issue #41517) + --> $DIR/trait-alias.rs:14:1 + | +14 | trait GenericAlias = Iterator; //~ERROR E0645 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0645]: trait aliases are not yet implemented (see issue #41517) + --> $DIR/trait-alias.rs:15:1 + | +15 | trait Partial = IntoIterator; //~ERROR E0645 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0645]: trait aliases are not yet implemented (see issue #41517) + --> $DIR/trait-alias.rs:24:1 + | +24 | 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 + | +25 | trait BareWhere = where The: Things; //~ERROR E0645 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0645]: trait aliases are not yet implemented (see issue #41517) + --> $DIR/trait-alias.rs:27:1 + | +27 | trait CD = Clone + Default; //~ERROR E0645 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors + diff --git a/src/tools/toolstate.toml b/src/tools/toolstate.toml index 13295ef3ee7..c7a279e9477 100644 --- a/src/tools/toolstate.toml +++ b/src/tools/toolstate.toml @@ -32,4 +32,5 @@ clippy = "Testing" rls = "Broken" # ping @nrc +# when breaking rustfmt, always break rls as well rustfmt = "Broken"