Skip to content

Commit

Permalink
Auto merge of #55101 - alexreg:trait-aliases, r=nikomatsakis
Browse files Browse the repository at this point in the history
Implement trait aliases (RFC 1733)

Extends groundwork done in #45047, and fully implements rust-lang/rfcs#1733.

CC @durka @nikomatsakis
  • Loading branch information
bors committed Nov 3, 2018
2 parents 3d28ee3 + 4171685 commit a3f0f51
Show file tree
Hide file tree
Showing 42 changed files with 631 additions and 332 deletions.
34 changes: 34 additions & 0 deletions src/doc/unstable-book/src/language-features/trait-alias.md
Original file line number Diff line number Diff line change
@@ -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<T: 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<dyn Foo>;
println!("{:?}", b);
}
```
33 changes: 17 additions & 16 deletions src/librustc/hir/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
4 changes: 1 addition & 3 deletions src/librustc/hir/map/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(..) |
Expand Down
17 changes: 17 additions & 0 deletions src/librustc/ich/impls_ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1118,6 +1118,7 @@ for traits::Vtable<'gcx, N> where N: HashStable<StableHashingContext<'a>> {
&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),
}
}
}
Expand Down Expand Up @@ -1226,6 +1227,22 @@ for traits::VtableGeneratorData<'gcx, N> where N: HashStable<StableHashingContex
}
}

impl<'a, 'gcx, N> HashStable<StableHashingContext<'a>>
for traits::VtableTraitAliasData<'gcx, N> where N: HashStable<StableHashingContext<'a>> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) {
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
Expand Down
19 changes: 15 additions & 4 deletions src/librustc/middle/resolve_lifetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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, ..)
Expand Down
34 changes: 25 additions & 9 deletions src/librustc/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -605,6 +608,13 @@ pub struct VtableFnPointerData<'tcx, N> {
pub nested: Vec<N>
}

#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable)]
pub struct VtableTraitAliasData<'tcx, N> {
pub alias_def_id: DefId,
pub substs: &'tcx Substs<'tcx>,
pub nested: Vec<N>,
}

/// Creates predicate obligations from the generic bounds.
pub fn predicates_for_generics<'tcx>(cause: ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
Expand Down Expand Up @@ -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,
}
}

Expand All @@ -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(),
}),
}
}
}
Expand Down
13 changes: 6 additions & 7 deletions src/librustc/traits/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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;
Expand Down
Loading

0 comments on commit a3f0f51

Please sign in to comment.