Extended elaboration for trait aliases to include arbitrary bounds.

This commit is contained in:
Alexander Regueiro 2018-10-26 23:13:12 +01:00
parent a8fcfcef30
commit 4bdc3d833a
11 changed files with 57 additions and 59 deletions

View File

@ -1635,7 +1635,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
ambiguous: false,
};
self.assemble_candidates_for_alias(obligation, &mut candidates)?;
self.assemble_candidates_for_trait_alias(obligation, &mut candidates)?;
// Other bounds. Consider both in-scope bounds from fn decl
// and applicable impls. There is a certain set of precedence rules here.
@ -2255,14 +2255,14 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
}
}
fn assemble_candidates_for_alias(
fn assemble_candidates_for_trait_alias(
&mut self,
obligation: &TraitObligation<'tcx>,
candidates: &mut SelectionCandidateSet<'tcx>,
) -> Result<(), SelectionError<'tcx>> {
// OK to skip binder here because the tests we do below do not involve bound regions
let self_ty = *obligation.self_ty().skip_binder();
debug!("assemble_candidates_for_alias(self_ty={:?})", self_ty);
debug!("assemble_candidates_for_trait_alias(self_ty={:?})", self_ty);
let def_id = obligation.predicate.def_id();
@ -2907,7 +2907,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
self.vtable_auto_impl(obligation, trait_def_id, types)
}
/// See `confirm_auto_impl_candidate`
/// See `confirm_auto_impl_candidate`.
fn vtable_auto_impl(
&mut self,
obligation: &TraitObligation<'tcx>,
@ -2964,7 +2964,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
// this time not in a probe.
self.in_snapshot(|this, snapshot| {
let (substs, placeholder_map) = this.rematch_impl(impl_def_id, obligation, snapshot);
debug!("confirm_impl_candidate substs={:?}", substs);
debug!("confirm_impl_candidate: substs={:?}", substs);
let cause = obligation.derived_cause(ImplDerivedObligation);
this.vtable_impl(
impl_def_id,

View File

@ -333,7 +333,7 @@ impl<I> FilterToTraits<I> {
}
}
impl<'tcx,I:Iterator<Item=ty::Predicate<'tcx>>> Iterator for FilterToTraits<I> {
impl<'tcx,I:Iterator<Item = ty::Predicate<'tcx>>> Iterator for FilterToTraits<I> {
type Item = ty::PolyTraitRef<'tcx>;
fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> {

View File

@ -1051,24 +1051,24 @@ pub enum Predicate<'tcx> {
/// would be the type parameters.
Trait(PolyTraitPredicate<'tcx>),
/// where 'a : 'b
/// where `'a : 'b`
RegionOutlives(PolyRegionOutlivesPredicate<'tcx>),
/// where T : 'a
/// where `T : 'a`
TypeOutlives(PolyTypeOutlivesPredicate<'tcx>),
/// where <T as TraitRef>::Name == X, approximately.
/// See `ProjectionPredicate` struct for details.
/// where `<T as TraitRef>::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),

View File

@ -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

View File

@ -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");

View File

@ -544,7 +544,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
}
/// Given the type/region arguments provided to some path (along with
/// an implicit Self, if this is a trait reference) returns the complete
/// an implicit `Self`, if this is a trait reference) returns the complete
/// set of substitutions. This may involve applying defaulted type parameters.
///
/// Note that the type listing given here is *exactly* what the user provided.
@ -721,7 +721,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
{
let trait_def_id = self.trait_def_id(trait_ref);
debug!("ast_path_to_poly_trait_ref({:?}, def_id={:?})", trait_ref, trait_def_id);
debug!("instantiate_poly_trait_ref({:?}, def_id={:?})", trait_ref, trait_def_id);
self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1);
@ -738,11 +738,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
let predicate: Result<_, ErrorReported> =
self.ast_type_binding_to_poly_projection_predicate(
trait_ref.ref_id, poly_trait_ref, binding, speculative, &mut dup_bindings);
// ok to ignore Err() because ErrorReported (see above)
// ok to ignore Err because ErrorReported (see above)
Some((predicate.ok()?, binding.span))
}));
debug!("ast_path_to_poly_trait_ref({:?}, projections={:?}) -> {:?}",
debug!("instantiate_poly_trait_ref({:?}, projections={:?}) -> {:?}",
trait_ref, poly_projections, poly_trait_ref);
poly_trait_ref
}
@ -1020,7 +1020,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
return tcx.types.err;
}
// use a btreeset to keep output in a more consistent order
// use a BTreeSet to keep output in a more consistent order
let mut associated_types = BTreeSet::default();
for tr in traits::supertraits(tcx, principal) {

View File

@ -245,8 +245,8 @@ fn type_param_predicates<'a, 'tcx>(
use rustc::hir::*;
// In the AST, bounds can derive from two places. Either
// written inline like `<T:Foo>` or in a where clause like
// `where T:Foo`.
// written inline like `<T : Foo>` or in a where clause like
// `where T : Foo`.
let param_id = tcx.hir.as_local_node_id(def_id).unwrap();
let param_owner = tcx.hir.ty_param_owner(param_id);
@ -317,12 +317,12 @@ fn type_param_predicates<'a, 'tcx>(
let icx = ItemCtxt::new(tcx, item_def_id);
result
.predicates
.extend(icx.type_parameter_bounds_in_generics(ast_generics, param_id, ty));
.extend(icx.type_parameter_bounds_in_generics(ast_generics, param_id, ty, true));
result
}
impl<'a, 'tcx> ItemCtxt<'a, 'tcx> {
/// Find bounds from hir::Generics. This requires scanning through the
/// Find bounds from `hir::Generics`. This requires scanning through the
/// AST. We do this to avoid having to convert *all* the bounds, which
/// would create artificial cycles. Instead we can only convert the
/// bounds for a type parameter `X` if `X::Foo` is used.
@ -331,6 +331,7 @@ impl<'a, 'tcx> ItemCtxt<'a, 'tcx> {
ast_generics: &hir::Generics,
param_id: ast::NodeId,
ty: Ty<'tcx>,
only_self_bounds: bool,
) -> Vec<(ty::Predicate<'tcx>, Span)> {
let from_ty_params = ast_generics
.params
@ -350,9 +351,21 @@ impl<'a, 'tcx> ItemCtxt<'a, 'tcx> {
hir::WherePredicate::BoundPredicate(ref bp) => Some(bp),
_ => None,
})
.filter(|bp| is_param(self.tcx, &bp.bounded_ty, param_id))
.flat_map(|bp| bp.bounds.iter())
.flat_map(|b| predicates_from_bound(self, ty, b));
.flat_map(|bp| {
let bt = if is_param(self.tcx, &bp.bounded_ty, param_id) {
Some(ty)
} else {
if only_self_bounds {
None
} else {
Some(self.to_ty(&bp.bounded_ty))
}
};
bp.bounds.iter().filter_map(move |b| {
if let Some(bt) = bt { Some((bt, b)) } else { None }
})
})
.flat_map(|(bt, b)| predicates_from_bound(self, bt, b));
from_ty_params.chain(from_where_clauses).collect()
}
@ -690,7 +703,7 @@ fn super_predicates_of<'a, 'tcx>(
let icx = ItemCtxt::new(tcx, trait_def_id);
// Convert the bounds that follow the colon, e.g. `Bar+Zed` in `trait Foo : Bar+Zed`.
// Convert the bounds that follow the colon, e.g. `Bar + Zed` in `trait Foo : Bar + Zed`.
let self_param_ty = tcx.mk_self_type();
let superbounds1 = compute_bounds(&icx, self_param_ty, bounds, SizedByDefault::No, item.span);
@ -698,7 +711,9 @@ fn super_predicates_of<'a, 'tcx>(
// Convert any explicit superbounds in the where clause,
// e.g. `trait Foo where Self : Bar`:
let superbounds2 = icx.type_parameter_bounds_in_generics(generics, item.id, self_param_ty);
let is_trait_alias = ty::is_trait_alias(tcx, trait_def_id);
let superbounds2 = icx.type_parameter_bounds_in_generics(
generics, item.id, self_param_ty, !is_trait_alias);
// Combine the two lists to form the complete set of superbounds:
let superbounds: Vec<_> = superbounds1.into_iter().chain(superbounds2).collect();
@ -706,6 +721,7 @@ fn super_predicates_of<'a, 'tcx>(
// Now require that immediate supertraits are converted,
// which will, in turn, reach indirect supertraits.
for &(pred, span) in &superbounds {
debug!("superbound: {:?}", pred);
if let ty::Predicate::Trait(bound) = pred {
tcx.at(span).super_predicates_of(bound.def_id());
}
@ -2007,10 +2023,10 @@ pub fn compute_bounds<'gcx: 'tcx, 'tcx>(
}
}
/// Converts a specific GenericBound from the AST into a set of
/// Converts a specific `GenericBound` from the AST into a set of
/// predicates that apply to the self-type. A vector is returned
/// because this can be anywhere from 0 predicates (`T:?Sized` adds no
/// predicates) to 1 (`T:Foo`) to many (`T:Bar<X=i32>` adds `T:Bar`
/// because this can be anywhere from zero predicates (`T : ?Sized` adds no
/// predicates) to one (`T : Foo`) to many (`T : Bar<X=i32>` adds `T : Bar`
/// and `<T as Bar>::X == i32`).
fn predicates_from_bound<'tcx>(
astconv: &dyn AstConv<'tcx, 'tcx>,

View File

@ -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<GenericParam>) -> PResult<'a, TyKind> {
/*
@ -5779,7 +5779,7 @@ impl<'a> Parser<'a> {
ast::ImplItemKind)> {
// code copied from parse_macro_use_or_failure... abstraction!
if let Some(mac) = self.parse_assoc_macro_invoc("impl", Some(vis), at_end)? {
// Method macro.
// method macro
Ok((keywords::Invalid.ident(), vec![], ast::Generics::default(),
ast::ImplItemKind::Macro(mac)))
} else {
@ -6792,11 +6792,11 @@ impl<'a> Parser<'a> {
Ok(self.mk_item(lo.to(prev_span), invalid, ItemKind::ForeignMod(m), visibility, attrs))
}
/// Parse type Foo = Bar;
/// Parse `type Foo = Bar;`
/// or
/// existential type Foo: Bar;
/// `existential type Foo: Bar;`
/// or
/// return None without modifying the parser state
/// `return None` without modifying the parser state
fn eat_type(&mut self) -> Option<PResult<'a, (Ident, AliasKind, ast::Generics)>> {
// This parses the grammar:
// Ident ["<"...">"] ["where" ...] ("=" | ":") Ty ";"

View File

@ -8,13 +8,14 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// gate-test-trait_alias
#![feature(trait_alias)]
trait CloneDefault<T> = Default where T: Clone;
trait BoundedAlias<T: Clone = ()> = Default;
trait A<T: Send> {}
trait B<T> = A<T>; // FIXME: parameter T should need a bound here, or semantics should be changed
trait Foo {}
trait A<T: Foo> {}
trait B<T> = A<T>; // T cannot be unbounded
impl CloneDefault for () {}

View File

@ -35,7 +35,7 @@ LL | trait BoundedAlias<T: Clone = ()> = Default;
error[E0658]: trait aliases are experimental (see issue #41517)
--> $DIR/trait-alias-fail1.rs:17:1
|
LL | trait B<T> = A<T>; // FIXME: this should not work... or should it?
LL | trait B<T> = A<T>; // FIXME: parameter T should need a bound here, or semantics should be changed
| ^^^^^^^^^^^^^^^^^^
|
= help: add #![feature(trait_alias)] to the crate attributes to enable

View File

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// gate-test-trait_alias
#![feature(trait_alias)]
trait EqAlias = Eq;
trait IteratorAlias = Iterator;