Skip to content

Commit

Permalink
Auto merge of #45047 - durka:trait-alias, r=petrochenkov
Browse files Browse the repository at this point in the history
trait alias infrastructure

This will be an implementation of trait aliases (RFC 1733, #41517).

Progress so far:

- [x] Feature gate
- [x] Add to parser
  - [x] `where` clauses
    - [x] prohibit LHS type parameter bounds via AST validation #45047 (comment)
- [x] Add to AST and HIR
  - [x] make a separate PathSource for trait alias contexts #45047 (comment)
- [x] Stub out enough of typeck and resolve to just barely not ICE

Postponed:

- [ ] Actually implement the alias part
- [ ] #21903
- [ ] #24010

I need some pointers on where to start with that last one. The test currently does this:

```
error[E0283]: type annotations required: cannot resolve `_: CD`
  --> src/test/run-pass/trait-alias.rs:34:16
   |
34 |     let both = foo();
   |                ^^^
   |
   = note: required by `foo`
```
  • Loading branch information
bors committed Dec 14, 2017
2 parents 3fc7f85 + 834674f commit 0077d12
Show file tree
Hide file tree
Showing 35 changed files with 323 additions and 35 deletions.
5 changes: 4 additions & 1 deletion src/librustc/hir/def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ pub enum Def {
Trait(DefId),
TyAlias(DefId),
TyForeign(DefId),
TraitAlias(DefId),
AssociatedTy(DefId),
PrimTy(hir::PrimTy),
TyParam(DefId),
Expand Down Expand Up @@ -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, ..) |
Expand Down Expand Up @@ -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",
Expand Down
5 changes: 5 additions & 0 deletions src/librustc/hir/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
6 changes: 4 additions & 2 deletions src/librustc/hir/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion src/librustc/hir/map/def_collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() => {
Expand Down
1 change: 1 addition & 0 deletions src/librustc/hir/map/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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",
};
Expand Down
3 changes: 3 additions & 0 deletions src/librustc/hir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1888,6 +1888,8 @@ pub enum Item_ {
ItemUnion(VariantData, Generics),
/// Represents a Trait Declaration
ItemTrait(IsAuto, Unsafety, Generics, TyParamBounds, HirVec<TraitItemRef>),
/// Represents a Trait Alias Declaration
ItemTraitAlias(Generics, TyParamBounds),

/// Auto trait implementations
///
Expand Down Expand Up @@ -1919,6 +1921,7 @@ impl Item_ {
ItemStruct(..) => "struct",
ItemUnion(..) => "union",
ItemTrait(..) => "trait",
ItemTraitAlias(..) => "trait alias",
ItemImpl(..) |
ItemAutoImpl(..) => "item",
}
Expand Down
21 changes: 21 additions & 0 deletions src/librustc/hir/print.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))
}
Expand Down
2 changes: 2 additions & 0 deletions src/librustc/ich/impls_hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
});
Expand Down Expand Up @@ -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),
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/reachable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(..) => {}
Expand Down
1 change: 1 addition & 0 deletions src/librustc/middle/resolve_lifetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
1 change: 1 addition & 0 deletions src/librustc/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions src/librustc_driver/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,

Expand Down
4 changes: 3 additions & 1 deletion src/librustc_metadata/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
};

Expand Down Expand Up @@ -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(..) => {
Expand Down
14 changes: 14 additions & 0 deletions src/librustc_passes/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
13 changes: 11 additions & 2 deletions src/librustc_privacy/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
}
Expand Down Expand Up @@ -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(..) => {}
}

Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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();

Expand Down
6 changes: 6 additions & 0 deletions src/librustc_resolve/build_reduced_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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!(),
}
}
Expand Down
44 changes: 33 additions & 11 deletions src/librustc_resolve/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand All @@ -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,
Expand All @@ -427,23 +433,23 @@ 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,
}
}

fn defer_to_typeck(self) -> bool {
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,
}
}

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",
Expand Down Expand Up @@ -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) |
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -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);
}
Expand Down
Loading

0 comments on commit 0077d12

Please sign in to comment.