mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-14 21:16:50 +00:00
Ban multi-trait objects via trait aliases.
This commit is contained in:
parent
16ef295770
commit
9f800457dd
@ -123,12 +123,12 @@ pub use core::slice::{RChunks, RChunksMut, RChunksExact, RChunksExactMut};
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// HACK(japaric) needed for the implementation of `vec!` macro during testing
|
||||
// NB see the hack module in this file for more details
|
||||
// N.B., see the `hack` module in this file for more details.
|
||||
#[cfg(test)]
|
||||
pub use hack::into_vec;
|
||||
|
||||
// HACK(japaric) needed for the implementation of `Vec::clone` during testing
|
||||
// NB see the hack module in this file for more details
|
||||
// N.B., see the `hack` module in this file for more details.
|
||||
#[cfg(test)]
|
||||
pub use hack::to_vec;
|
||||
|
||||
@ -376,7 +376,7 @@ impl<T> [T] {
|
||||
pub fn to_vec(&self) -> Vec<T>
|
||||
where T: Clone
|
||||
{
|
||||
// NB see hack module in this file
|
||||
// N.B., see the `hack` module in this file for more details.
|
||||
hack::to_vec(self)
|
||||
}
|
||||
|
||||
@ -397,7 +397,7 @@ impl<T> [T] {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[inline]
|
||||
pub fn into_vec(self: Box<Self>) -> Vec<T> {
|
||||
// NB see hack module in this file
|
||||
// N.B., see the `hack` module in this file for more details.
|
||||
hack::into_vec(self)
|
||||
}
|
||||
|
||||
|
@ -957,7 +957,7 @@ impl<'hir> Map<'hir> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the name associated with the given NodeId's AST.
|
||||
/// Returns the name associated with the given `NodeId`'s AST.
|
||||
pub fn name(&self, id: NodeId) -> Name {
|
||||
let hir_id = self.node_to_hir_id(id);
|
||||
self.name_by_hir_id(hir_id)
|
||||
|
@ -2143,11 +2143,11 @@ pub enum UseKind {
|
||||
ListStem,
|
||||
}
|
||||
|
||||
/// TraitRef's appear in impls.
|
||||
/// `TraitRef` are references to traits in impls.
|
||||
///
|
||||
/// resolve maps each TraitRef's ref_id to its defining trait; that's all
|
||||
/// that the ref_id is for. Note that ref_id's value is not the NodeId of the
|
||||
/// trait being referred to but just a unique NodeId that serves as a key
|
||||
/// `resolve` maps each `TraitRef`'s `ref_id` to its defining trait; that's all
|
||||
/// that the `ref_id` is for. Note that `ref_id`'s value is not the `NodeId` of the
|
||||
/// trait being referred to but just a unique `NodeId` that serves as a key
|
||||
/// within the resolution map.
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
|
||||
pub struct TraitRef {
|
||||
|
@ -141,9 +141,9 @@ impl<'cx, 'gcx, 'tcx> VerifyBoundCx<'cx, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
fn recursive_type_bound(&self, ty: Ty<'tcx>) -> VerifyBound<'tcx> {
|
||||
let mut bounds = ty.walk_shallow()
|
||||
let mut bounds: Vec<_> = ty.walk_shallow()
|
||||
.map(|subty| self.type_bound(subty))
|
||||
.collect::<Vec<_>>();
|
||||
.collect();
|
||||
|
||||
let mut regions = smallvec![];
|
||||
ty.push_regions(&mut regions);
|
||||
|
@ -62,6 +62,7 @@ pub use self::engine::{TraitEngine, TraitEngineExt};
|
||||
pub use self::util::{elaborate_predicates, elaborate_trait_ref, elaborate_trait_refs};
|
||||
pub use self::util::{supertraits, supertrait_def_ids, transitive_bounds,
|
||||
Supertraits, SupertraitDefIds};
|
||||
pub use self::util::{expand_trait_refs, TraitRefExpander};
|
||||
|
||||
pub use self::chalk_fulfill::{
|
||||
CanonicalGoal as ChalkCanonicalGoal,
|
||||
@ -1043,7 +1044,7 @@ fn vtable_methods<'a, 'tcx>(
|
||||
)
|
||||
}
|
||||
|
||||
impl<'tcx,O> Obligation<'tcx,O> {
|
||||
impl<'tcx, O> Obligation<'tcx,O> {
|
||||
pub fn new(cause: ObligationCause<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
predicate: O)
|
||||
|
@ -1772,7 +1772,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
bounds
|
||||
);
|
||||
|
||||
let matching_bound = util::elaborate_predicates(self.tcx(), bounds.predicates)
|
||||
let elaborated_predicates = util::elaborate_predicates(self.tcx(), bounds.predicates);
|
||||
let matching_bound = elaborated_predicates
|
||||
.filter_to_traits()
|
||||
.find(|bound| {
|
||||
self.infcx.probe(|_| {
|
||||
|
@ -1,3 +1,5 @@
|
||||
use syntax_pos::Span;
|
||||
|
||||
use crate::hir;
|
||||
use crate::hir::def_id::DefId;
|
||||
use crate::traits::specialize::specialization_graph::NodeItem;
|
||||
@ -41,7 +43,6 @@ fn anonymize_predicate<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct PredicateSet<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
set: FxHashSet<ty::Predicate<'tcx>>,
|
||||
@ -73,12 +74,11 @@ impl<'a, 'gcx, 'tcx> PredicateSet<'a, 'gcx, 'tcx> {
|
||||
|
||||
/// "Elaboration" is the process of identifying all the predicates that
|
||||
/// are implied by a source predicate. Currently this basically means
|
||||
/// walking the "supertraits" and other similar assumptions. For
|
||||
/// example, if we know that `T : Ord`, the elaborator would deduce
|
||||
/// that `T : PartialOrd` holds as well. Similarly, if we have `trait
|
||||
/// Foo : 'static`, and we know that `T : Foo`, then we know that `T :
|
||||
/// 'static`.
|
||||
pub struct Elaborator<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
||||
/// walking the "supertraits" and other similar assumptions. For example,
|
||||
/// if we know that `T: Ord`, the elaborator would deduce that `T: PartialOrd`
|
||||
/// holds as well. Similarly, if we have `trait Foo: 'static`, and we know that
|
||||
/// `T: Foo`, then we know that `T: 'static`.
|
||||
pub struct Elaborator<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
|
||||
stack: Vec<ty::Predicate<'tcx>>,
|
||||
visited: PredicateSet<'a, 'gcx, 'tcx>,
|
||||
}
|
||||
@ -96,8 +96,7 @@ pub fn elaborate_trait_refs<'cx, 'gcx, 'tcx>(
|
||||
trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>)
|
||||
-> Elaborator<'cx, 'gcx, 'tcx>
|
||||
{
|
||||
let predicates = trait_refs.map(|trait_ref| trait_ref.to_predicate())
|
||||
.collect();
|
||||
let predicates = trait_refs.map(|trait_ref| trait_ref.to_predicate()).collect();
|
||||
elaborate_predicates(tcx, predicates)
|
||||
}
|
||||
|
||||
@ -120,7 +119,7 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> {
|
||||
let tcx = self.visited.tcx;
|
||||
match *predicate {
|
||||
ty::Predicate::Trait(ref data) => {
|
||||
// Predicates declared on the trait.
|
||||
// Get predicates declared on the trait.
|
||||
let predicates = tcx.super_predicates_of(data.def_id());
|
||||
|
||||
let mut predicates: Vec<_> = predicates.predicates
|
||||
@ -130,12 +129,11 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> {
|
||||
debug!("super_predicates: data={:?} predicates={:?}",
|
||||
data, predicates);
|
||||
|
||||
// Only keep those bounds that we haven't already
|
||||
// seen. This is necessary to prevent infinite
|
||||
// recursion in some cases. One common case is when
|
||||
// people define `trait Sized: Sized { }` rather than `trait
|
||||
// Sized { }`.
|
||||
predicates.retain(|r| self.visited.insert(r));
|
||||
// Only keep those bounds that we haven't already seen.
|
||||
// This is necessary to prevent infinite recursion in some
|
||||
// cases. One common case is when people define
|
||||
// `trait Sized: Sized { }` rather than `trait Sized { }`.
|
||||
predicates.retain(|p| self.visited.insert(p));
|
||||
|
||||
self.stack.extend(predicates);
|
||||
}
|
||||
@ -161,11 +159,9 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> {
|
||||
// Currently, we do not elaborate const-evaluatable
|
||||
// predicates.
|
||||
}
|
||||
|
||||
ty::Predicate::RegionOutlives(..) => {
|
||||
// Nothing to elaborate from `'a: 'b`.
|
||||
}
|
||||
|
||||
ty::Predicate::TypeOutlives(ref data) => {
|
||||
// We know that `T: 'a` for some type `T`. We can
|
||||
// often elaborate this. For example, if we know that
|
||||
@ -192,34 +188,35 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> {
|
||||
tcx.push_outlives_components(ty_max, &mut components);
|
||||
self.stack.extend(
|
||||
components
|
||||
.into_iter()
|
||||
.filter_map(|component| match component {
|
||||
Component::Region(r) => if r.is_late_bound() {
|
||||
None
|
||||
} else {
|
||||
Some(ty::Predicate::RegionOutlives(
|
||||
ty::Binder::dummy(ty::OutlivesPredicate(r, r_min))))
|
||||
},
|
||||
.into_iter()
|
||||
.filter_map(|component| match component {
|
||||
Component::Region(r) => if r.is_late_bound() {
|
||||
None
|
||||
} else {
|
||||
Some(ty::Predicate::RegionOutlives(
|
||||
ty::Binder::dummy(ty::OutlivesPredicate(r, r_min))))
|
||||
}
|
||||
|
||||
Component::Param(p) => {
|
||||
let ty = tcx.mk_ty_param(p.index, p.name);
|
||||
Some(ty::Predicate::TypeOutlives(
|
||||
ty::Binder::dummy(ty::OutlivesPredicate(ty, r_min))))
|
||||
},
|
||||
Component::Param(p) => {
|
||||
let ty = tcx.mk_ty_param(p.index, p.name);
|
||||
Some(ty::Predicate::TypeOutlives(
|
||||
ty::Binder::dummy(ty::OutlivesPredicate(ty, r_min))))
|
||||
}
|
||||
|
||||
Component::UnresolvedInferenceVariable(_) => {
|
||||
None
|
||||
},
|
||||
Component::UnresolvedInferenceVariable(_) => {
|
||||
None
|
||||
}
|
||||
|
||||
Component::Projection(_) |
|
||||
Component::EscapingProjection(_) => {
|
||||
// We can probably do more here. This
|
||||
// corresponds to a case like `<T as
|
||||
// Foo<'a>>::U: 'b`.
|
||||
None
|
||||
},
|
||||
})
|
||||
.filter(|p| visited.insert(p)));
|
||||
Component::Projection(_) |
|
||||
Component::EscapingProjection(_) => {
|
||||
// We can probably do more here. This
|
||||
// corresponds to a case like `<T as
|
||||
// Foo<'a>>::U: 'b`.
|
||||
None
|
||||
}
|
||||
})
|
||||
.filter(|p| visited.insert(p))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -233,16 +230,10 @@ impl<'cx, 'gcx, 'tcx> Iterator for Elaborator<'cx, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
fn next(&mut self) -> Option<ty::Predicate<'tcx>> {
|
||||
// Extract next item from top-most stack frame, if any.
|
||||
let next_predicate = match self.stack.pop() {
|
||||
Some(predicate) => predicate,
|
||||
None => {
|
||||
// No more stack frames. Done.
|
||||
return None;
|
||||
}
|
||||
};
|
||||
self.push(&next_predicate);
|
||||
return Some(next_predicate);
|
||||
self.stack.pop().map(|item| {
|
||||
self.push(&item);
|
||||
item
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -254,20 +245,124 @@ pub type Supertraits<'cx, 'gcx, 'tcx> = FilterToTraits<Elaborator<'cx, 'gcx, 'tc
|
||||
|
||||
pub fn supertraits<'cx, 'gcx, 'tcx>(tcx: TyCtxt<'cx, 'gcx, 'tcx>,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>)
|
||||
-> Supertraits<'cx, 'gcx, 'tcx>
|
||||
{
|
||||
-> Supertraits<'cx, 'gcx, 'tcx> {
|
||||
elaborate_trait_ref(tcx, trait_ref).filter_to_traits()
|
||||
}
|
||||
|
||||
pub fn transitive_bounds<'cx, 'gcx, 'tcx>(tcx: TyCtxt<'cx, 'gcx, 'tcx>,
|
||||
bounds: impl Iterator<Item = ty::PolyTraitRef<'tcx>>)
|
||||
-> Supertraits<'cx, 'gcx, 'tcx>
|
||||
{
|
||||
-> Supertraits<'cx, 'gcx, 'tcx> {
|
||||
elaborate_trait_refs(tcx, bounds).filter_to_traits()
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// `TraitRefExpander` iterator
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// "Trait reference expansion" is the process of expanding a sequence of trait
|
||||
/// references into another sequence by transitively following all trait
|
||||
/// aliases. e.g. If you have bounds like `Foo + Send`, a trait alias
|
||||
/// `trait Foo = Bar + Sync;`, and another trait alias
|
||||
/// `trait Bar = Read + Write`, then the bounds would expand to
|
||||
/// `Read + Write + Sync + Send`.
|
||||
pub struct TraitRefExpander<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
|
||||
stack: Vec<TraitRefExpansionInfo<'tcx>>,
|
||||
visited: PredicateSet<'a, 'gcx, 'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TraitRefExpansionInfo<'tcx> {
|
||||
pub top_level_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
pub top_level_span: Span,
|
||||
pub trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
pub fn expand_trait_refs<'cx, 'gcx, 'tcx>(
|
||||
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
|
||||
trait_refs: impl IntoIterator<Item = (ty::PolyTraitRef<'tcx>, Span)>
|
||||
) -> TraitRefExpander<'cx, 'gcx, 'tcx> {
|
||||
let mut visited = PredicateSet::new(tcx);
|
||||
let mut items: Vec<_> =
|
||||
trait_refs
|
||||
.into_iter()
|
||||
.map(|(tr, sp)| TraitRefExpansionInfo {
|
||||
top_level_trait_ref: tr.clone(),
|
||||
top_level_span: sp,
|
||||
trait_ref: tr,
|
||||
span: sp,
|
||||
})
|
||||
.collect();
|
||||
items.retain(|item| visited.insert(&item.trait_ref.to_predicate()));
|
||||
TraitRefExpander { stack: items, visited: visited, }
|
||||
}
|
||||
|
||||
impl<'cx, 'gcx, 'tcx> TraitRefExpander<'cx, 'gcx, 'tcx> {
|
||||
// Returns `true` if `item` refers to a trait.
|
||||
fn push(&mut self, item: &TraitRefExpansionInfo<'tcx>) -> bool {
|
||||
let tcx = self.visited.tcx;
|
||||
|
||||
if !tcx.is_trait_alias(item.trait_ref.def_id()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get predicates declared on the trait.
|
||||
let predicates = tcx.super_predicates_of(item.trait_ref.def_id());
|
||||
|
||||
let mut items: Vec<_> = predicates.predicates
|
||||
.iter()
|
||||
.rev()
|
||||
.filter_map(|(pred, sp)| {
|
||||
pred.subst_supertrait(tcx, &item.trait_ref)
|
||||
.to_opt_poly_trait_ref()
|
||||
.map(|trait_ref|
|
||||
TraitRefExpansionInfo {
|
||||
trait_ref,
|
||||
span: *sp,
|
||||
..*item
|
||||
}
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
debug!("expand_trait_refs: trait_ref={:?} items={:?}",
|
||||
item.trait_ref, items);
|
||||
|
||||
// Only keep those items that we haven't already seen.
|
||||
items.retain(|i| self.visited.insert(&i.trait_ref.to_predicate()));
|
||||
|
||||
self.stack.extend(items);
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl<'cx, 'gcx, 'tcx> Iterator for TraitRefExpander<'cx, 'gcx, 'tcx> {
|
||||
type Item = TraitRefExpansionInfo<'tcx>;
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
(self.stack.len(), None)
|
||||
}
|
||||
|
||||
fn next(&mut self) -> Option<TraitRefExpansionInfo<'tcx>> {
|
||||
loop {
|
||||
let item = self.stack.pop();
|
||||
match item {
|
||||
Some(item) => {
|
||||
if self.push(&item) {
|
||||
return Some(item);
|
||||
}
|
||||
}
|
||||
None => {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Iterator over def-ids of supertraits
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
pub struct SupertraitDefIds<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
|
@ -1234,7 +1234,7 @@ impl<'tcx> TraitPredicate<'tcx> {
|
||||
self.trait_ref.def_id
|
||||
}
|
||||
|
||||
pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a {
|
||||
pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item = Ty<'tcx>> + 'a {
|
||||
self.trait_ref.input_types()
|
||||
}
|
||||
|
||||
@ -2400,7 +2400,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
|
||||
pub fn discriminants(
|
||||
&'a self,
|
||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
) -> impl Iterator<Item=(VariantIdx, Discr<'tcx>)> + Captures<'gcx> + 'a {
|
||||
) -> impl Iterator<Item = (VariantIdx, Discr<'tcx>)> + Captures<'gcx> + 'a {
|
||||
let repr_type = self.repr.discr_type();
|
||||
let initial = repr_type.initial_discriminant(tcx.global_tcx());
|
||||
let mut prev_discr = None::<Discr<'tcx>>;
|
||||
|
@ -1177,13 +1177,13 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
|
||||
);
|
||||
}
|
||||
ast::ImplItemKind::Type(ref ty) => {
|
||||
// FIXME uses of the assoc type should ideally point to this
|
||||
// FIXME: uses of the assoc type should ideally point to this
|
||||
// 'def' and the name here should be a ref to the def in the
|
||||
// trait.
|
||||
self.visit_ty(ty)
|
||||
}
|
||||
ast::ImplItemKind::Existential(ref bounds) => {
|
||||
// FIXME uses of the assoc type should ideally point to this
|
||||
// FIXME: uses of the assoc type should ideally point to this
|
||||
// 'def' and the name here should be a ref to the def in the
|
||||
// trait.
|
||||
for bound in bounds.iter() {
|
||||
@ -1216,7 +1216,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
|
||||
let hir_id = self.tcx.hir().node_to_hir_id(id);
|
||||
let access = access_from!(self.save_ctxt, root_item, hir_id);
|
||||
|
||||
// The parent def id of a given use tree is always the enclosing item.
|
||||
// The parent def-ID of a given use tree is always the enclosing item.
|
||||
let parent = self.save_ctxt.tcx.hir().opt_local_def_id(id)
|
||||
.and_then(|id| self.save_ctxt.tcx.parent(id))
|
||||
.map(id_from_def_id);
|
||||
|
@ -975,12 +975,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
|
||||
|
||||
if trait_bounds.is_empty() {
|
||||
span_err!(tcx.sess, span, E0224,
|
||||
"at least one non-builtin trait is required for an object type");
|
||||
"at least one non-builtin trait is required for an object type");
|
||||
return tcx.types.err;
|
||||
}
|
||||
|
||||
let mut projection_bounds = Vec::new();
|
||||
let dummy_self = self.tcx().types.trait_object_dummy_self;
|
||||
let mut bound_trait_refs = Vec::with_capacity(trait_bounds.len());
|
||||
let (principal, potential_assoc_types) = self.instantiate_poly_trait_ref(
|
||||
&trait_bounds[0],
|
||||
dummy_self,
|
||||
@ -988,22 +989,29 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
|
||||
);
|
||||
debug!("principal: {:?}", principal);
|
||||
|
||||
for trait_bound in trait_bounds[1..].iter() {
|
||||
// sanity check for non-principal trait bounds
|
||||
self.instantiate_poly_trait_ref(trait_bound,
|
||||
dummy_self,
|
||||
&mut vec![]);
|
||||
for trait_bound in trait_bounds[1..].iter().rev() {
|
||||
// Sanity check for non-principal trait bounds.
|
||||
let (tr, _) = self.instantiate_poly_trait_ref(
|
||||
trait_bound,
|
||||
dummy_self,
|
||||
&mut Vec::new()
|
||||
);
|
||||
bound_trait_refs.push((tr, trait_bound.span));
|
||||
}
|
||||
bound_trait_refs.push((principal, trait_bounds[0].span));
|
||||
|
||||
let (mut auto_traits, trait_bounds) = split_auto_traits(tcx, &trait_bounds[1..]);
|
||||
|
||||
if !trait_bounds.is_empty() {
|
||||
let b = &trait_bounds[0];
|
||||
let span = b.trait_ref.path.span;
|
||||
struct_span_err!(self.tcx().sess, span, E0225,
|
||||
"only auto traits can be used as additional traits in a trait object")
|
||||
.span_label(span, "non-auto additional trait")
|
||||
.emit();
|
||||
let expanded_traits = traits::expand_trait_refs(tcx, bound_trait_refs);
|
||||
let (auto_traits, regular_traits): (Vec<_>, Vec<_>) =
|
||||
expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref.def_id()));
|
||||
if regular_traits.len() > 1 {
|
||||
let extra_trait = ®ular_traits[1];
|
||||
let mut err = struct_span_err!(tcx.sess, extra_trait.top_level_span, E0225,
|
||||
"only auto traits can be used as additional traits in a trait object");
|
||||
err.span_label(extra_trait.span, "non-auto additional trait");
|
||||
if extra_trait.span != extra_trait.top_level_span {
|
||||
err.span_label(extra_trait.top_level_span, "expanded from this alias");
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
|
||||
// Check that there are no gross object safety violations;
|
||||
@ -1024,9 +1032,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
|
||||
debug!("conv_object_ty_poly_trait_ref: observing object predicate `{:?}`", tr);
|
||||
match tr {
|
||||
ty::Predicate::Trait(pred) => {
|
||||
associated_types.extend(tcx.associated_items(pred.def_id())
|
||||
.filter(|item| item.kind == ty::AssociatedKind::Type)
|
||||
.map(|item| item.def_id));
|
||||
associated_types
|
||||
.extend(tcx.associated_items(pred.def_id())
|
||||
.filter(|item| item.kind == ty::AssociatedKind::Type)
|
||||
.map(|item| item.def_id));
|
||||
}
|
||||
ty::Predicate::Projection(pred) => {
|
||||
// A `Self` within the original bound will be substituted with a
|
||||
@ -1145,11 +1154,15 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
|
||||
})
|
||||
});
|
||||
|
||||
// Dedup auto traits so that `dyn Trait + Send + Send` is the same as `dyn Trait + Send`.
|
||||
// De-duplicate auto traits so that, e.g., `dyn Trait + Send + Send` is the same as
|
||||
// `dyn Trait + Send`.
|
||||
let mut auto_traits: Vec<_> =
|
||||
auto_traits.into_iter().map(|i| i.trait_ref.def_id()).collect();
|
||||
auto_traits.sort();
|
||||
auto_traits.dedup();
|
||||
debug!("auto_traits: {:?}", auto_traits);
|
||||
|
||||
// Calling `skip_binder` is okay, because the predicates are re-bound.
|
||||
// Calling `skip_binder` is okay because the predicates are re-bound.
|
||||
let principal = if tcx.trait_is_auto(existential_principal.def_id()) {
|
||||
ty::ExistentialPredicate::AutoTrait(existential_principal.def_id())
|
||||
} else {
|
||||
@ -1175,14 +1188,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
|
||||
} else {
|
||||
self.re_infer(span, None).unwrap_or_else(|| {
|
||||
span_err!(tcx.sess, span, E0228,
|
||||
"the lifetime bound for this object type cannot be deduced \
|
||||
from context; please supply an explicit bound");
|
||||
"the lifetime bound for this object type cannot be deduced \
|
||||
from context; please supply an explicit bound");
|
||||
tcx.lifetimes.re_static
|
||||
})
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
debug!("region_bound: {:?}", region_bound);
|
||||
|
||||
let ty = tcx.mk_dynamic(existential_predicates, region_bound);
|
||||
@ -2097,33 +2109,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
|
||||
}
|
||||
}
|
||||
|
||||
/// Divides a list of general trait bounds into two groups: auto traits (e.g., Sync and Send) and
|
||||
/// the remaining general trait bounds.
|
||||
fn split_auto_traits<'a, 'b, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
trait_bounds: &'b [hir::PolyTraitRef])
|
||||
-> (Vec<DefId>, Vec<&'b hir::PolyTraitRef>)
|
||||
{
|
||||
let (auto_traits, trait_bounds): (Vec<_>, _) = trait_bounds.iter().partition(|bound| {
|
||||
// Checks whether `trait_did` is an auto trait and adds it to `auto_traits` if so.
|
||||
match bound.trait_ref.path.res {
|
||||
Res::Def(DefKind::Trait, trait_did) if tcx.trait_is_auto(trait_did) => {
|
||||
true
|
||||
}
|
||||
_ => false
|
||||
}
|
||||
});
|
||||
|
||||
let auto_traits = auto_traits.into_iter().map(|tr| {
|
||||
if let Res::Def(DefKind::Trait, trait_did) = tr.trait_ref.path.res {
|
||||
trait_did
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}).collect::<Vec<_>>();
|
||||
|
||||
(auto_traits, trait_bounds)
|
||||
}
|
||||
|
||||
// A helper struct for conveniently grouping a set of bounds which we pass to
|
||||
// and return from functions in multiple places.
|
||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||
|
@ -758,7 +758,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
fn assemble_inherent_candidates_from_param(&mut self, param_ty: ty::ParamTy) {
|
||||
// FIXME -- Do we want to commit to this behavior for param bounds?
|
||||
// FIXME: do we want to commit to this behavior for param bounds?
|
||||
|
||||
let bounds = self.param_env
|
||||
.caller_bounds
|
||||
|
@ -1019,7 +1019,7 @@ fn check_false_global_bounds<'a, 'gcx, 'tcx>(
|
||||
.iter()
|
||||
.map(|(p, _)| *p)
|
||||
.collect();
|
||||
// Check elaborated bounds
|
||||
// Check elaborated bounds.
|
||||
let implied_obligations = traits::elaborate_predicates(fcx.tcx, predicates);
|
||||
|
||||
for pred in implied_obligations {
|
||||
|
@ -2133,10 +2133,10 @@ pub struct TraitRef {
|
||||
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
|
||||
pub struct PolyTraitRef {
|
||||
/// The `'a` in `<'a> Foo<&'a T>`
|
||||
/// The `'a` in `<'a> Foo<&'a T>`.
|
||||
pub bound_generic_params: Vec<GenericParam>,
|
||||
|
||||
/// The `Foo<&'a T>` in `<'a> Foo<&'a T>`
|
||||
/// The `Foo<&'a T>` in `<'a> Foo<&'a T>`.
|
||||
pub trait_ref: TraitRef,
|
||||
|
||||
pub span: Span,
|
||||
|
Loading…
Reference in New Issue
Block a user