mirror of
https://github.com/rust-lang/rust.git
synced 2024-10-31 14:31:55 +00:00
Extended elaboration for trait aliases to include arbitrary bounds.
This commit is contained in:
parent
a8fcfcef30
commit
4bdc3d833a
@ -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,
|
||||
|
@ -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>> {
|
||||
|
@ -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),
|
||||
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
|
@ -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) {
|
||||
|
@ -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>,
|
||||
|
@ -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 ";"
|
||||
|
@ -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 () {}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user