Fixed detection of multiple non-auto traits.
This commit is contained in:
parent
5f6c2127d7
commit
aea954b74d
4 changed files with 210 additions and 154 deletions
|
|
@ -60,9 +60,12 @@ pub use self::specialize::specialization_graph::FutureCompatOverlapError;
|
|||
pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind;
|
||||
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::util::{
|
||||
supertraits, supertrait_def_ids, transitive_bounds, Supertraits, SupertraitDefIds,
|
||||
};
|
||||
pub use self::util::{
|
||||
expand_trait_aliases, TraitAliasExpander, TraitAliasExpansionInfoDignosticBuilder,
|
||||
};
|
||||
|
||||
pub use self::chalk_fulfill::{
|
||||
CanonicalGoal as ChalkCanonicalGoal,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
use errors::DiagnosticBuilder;
|
||||
use smallvec::SmallVec;
|
||||
use syntax_pos::Span;
|
||||
|
||||
use crate::hir;
|
||||
|
|
@ -43,7 +45,7 @@ fn anonymize_predicate<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
|||
}
|
||||
}
|
||||
|
||||
struct PredicateSet<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
||||
struct PredicateSet<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
|
||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
set: FxHashSet<ty::Predicate<'tcx>>,
|
||||
}
|
||||
|
|
@ -53,6 +55,10 @@ impl<'a, 'gcx, 'tcx> PredicateSet<'a, 'gcx, 'tcx> {
|
|||
PredicateSet { tcx: tcx, set: Default::default() }
|
||||
}
|
||||
|
||||
fn contains(&mut self, pred: &ty::Predicate<'tcx>) -> bool {
|
||||
self.set.contains(&anonymize_predicate(self.tcx, pred))
|
||||
}
|
||||
|
||||
fn insert(&mut self, pred: &ty::Predicate<'tcx>) -> bool {
|
||||
// We have to be careful here because we want
|
||||
//
|
||||
|
|
@ -66,6 +72,18 @@ impl<'a, 'gcx, 'tcx> PredicateSet<'a, 'gcx, 'tcx> {
|
|||
// regions before we throw things into the underlying set.
|
||||
self.set.insert(anonymize_predicate(self.tcx, pred))
|
||||
}
|
||||
|
||||
fn remove(&mut self, pred: &ty::Predicate<'tcx>) -> bool {
|
||||
self.set.remove(&anonymize_predicate(self.tcx, pred))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx, T: AsRef<ty::Predicate<'tcx>>> Extend<T> for PredicateSet<'a, 'gcx, 'tcx> {
|
||||
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
|
||||
for pred in iter.into_iter() {
|
||||
self.insert(pred.as_ref());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -230,10 +248,16 @@ impl<'cx, 'gcx, 'tcx> Iterator for Elaborator<'cx, 'gcx, 'tcx> {
|
|||
}
|
||||
|
||||
fn next(&mut self) -> Option<ty::Predicate<'tcx>> {
|
||||
self.stack.pop().map(|item| {
|
||||
self.push(&item);
|
||||
item
|
||||
})
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -256,96 +280,140 @@ pub fn transitive_bounds<'cx, 'gcx, 'tcx>(tcx: TyCtxt<'cx, 'gcx, 'tcx>,
|
|||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// `TraitRefExpander` iterator
|
||||
// `TraitAliasExpander` iterator
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// "Trait reference expansion" is the process of expanding a sequence of trait
|
||||
/// "Trait alias 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>>,
|
||||
pub struct TraitAliasExpander<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
|
||||
stack: Vec<TraitAliasExpansionInfo<'tcx>>,
|
||||
/// The set of predicates visited from the root directly to the current point in the
|
||||
/// expansion tree.
|
||||
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 struct TraitAliasExpansionInfo<'tcx> {
|
||||
pub items: SmallVec<[(ty::PolyTraitRef<'tcx>, Span); 4]>,
|
||||
}
|
||||
|
||||
pub fn expand_trait_refs<'cx, 'gcx, 'tcx>(
|
||||
impl<'tcx> TraitAliasExpansionInfo<'tcx> {
|
||||
fn new(trait_ref: ty::PolyTraitRef<'tcx>, span: Span) -> TraitAliasExpansionInfo<'tcx> {
|
||||
TraitAliasExpansionInfo {
|
||||
items: smallvec![(trait_ref, span)]
|
||||
}
|
||||
}
|
||||
|
||||
fn push(&self, trait_ref: ty::PolyTraitRef<'tcx>, span: Span) -> TraitAliasExpansionInfo<'tcx> {
|
||||
let mut items = self.items.clone();
|
||||
items.push((trait_ref, span));
|
||||
|
||||
TraitAliasExpansionInfo {
|
||||
items
|
||||
}
|
||||
}
|
||||
|
||||
pub fn trait_ref(&self) -> &ty::PolyTraitRef<'tcx> {
|
||||
&self.top().0
|
||||
}
|
||||
|
||||
pub fn top(&self) -> &(ty::PolyTraitRef<'tcx>, Span) {
|
||||
self.items.last().unwrap()
|
||||
}
|
||||
|
||||
pub fn bottom(&self) -> &(ty::PolyTraitRef<'tcx>, Span) {
|
||||
self.items.first().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait TraitAliasExpansionInfoDignosticBuilder {
|
||||
fn label_with_exp_info<'tcx>(&mut self,
|
||||
info: &TraitAliasExpansionInfo<'tcx>,
|
||||
top_label: &str
|
||||
) -> &mut Self;
|
||||
}
|
||||
|
||||
impl<'a> TraitAliasExpansionInfoDignosticBuilder for DiagnosticBuilder<'a> {
|
||||
fn label_with_exp_info<'tcx>(&mut self,
|
||||
info: &TraitAliasExpansionInfo<'tcx>,
|
||||
top_label: &str
|
||||
) -> &mut Self {
|
||||
self.span_label(info.top().1, top_label);
|
||||
if info.items.len() > 1 {
|
||||
for (_, sp) in info.items[1..(info.items.len() - 1)].iter().rev() {
|
||||
self.span_label(*sp, "referenced here");
|
||||
}
|
||||
}
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expand_trait_aliases<'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(|(trait_ref, span)| TraitRefExpansionInfo {
|
||||
top_level_trait_ref: trait_ref.clone(),
|
||||
top_level_span: span,
|
||||
trait_ref,
|
||||
span,
|
||||
})
|
||||
.collect();
|
||||
items.retain(|item| visited.insert(&item.trait_ref.to_predicate()));
|
||||
TraitRefExpander { stack: items, visited }
|
||||
) -> TraitAliasExpander<'cx, 'gcx, 'tcx> {
|
||||
let items: Vec<_> = trait_refs
|
||||
.into_iter()
|
||||
.map(|(trait_ref, span)| TraitAliasExpansionInfo::new(trait_ref, span))
|
||||
.collect();
|
||||
TraitAliasExpander { stack: items, visited: PredicateSet::new(tcx) }
|
||||
}
|
||||
|
||||
impl<'cx, 'gcx, 'tcx> TraitRefExpander<'cx, 'gcx, 'tcx> {
|
||||
/// If `item` refers to a trait alias, adds the components of the trait alias to the stack,
|
||||
/// and returns `false`.
|
||||
/// If `item` refers to an ordinary trait, simply returns `true`.
|
||||
fn push(&mut self, item: &TraitRefExpansionInfo<'tcx>) -> bool {
|
||||
impl<'cx, 'gcx, 'tcx> TraitAliasExpander<'cx, 'gcx, 'tcx> {
|
||||
/// If `item` is a trait alias and its predicate has not yet been visited, then expands `item`
|
||||
/// to the definition and pushes the resulting expansion onto `self.stack`, and returns `false`.
|
||||
/// Otherwise, immediately returns `true` if `item` is a regular trait and `false` if it is a
|
||||
/// trait alias.
|
||||
/// The return value indicates whether `item` should not be yielded to the user.
|
||||
fn push(&mut self, item: &TraitAliasExpansionInfo<'tcx>) -> bool {
|
||||
let tcx = self.visited.tcx;
|
||||
let trait_ref = item.trait_ref();
|
||||
let pred = trait_ref.to_predicate();
|
||||
|
||||
if !tcx.is_trait_alias(item.trait_ref.def_id()) {
|
||||
return true;
|
||||
debug!("expand_trait_aliases: trait_ref={:?}", trait_ref);
|
||||
|
||||
self.visited.remove(&pred);
|
||||
|
||||
let is_alias = tcx.is_trait_alias(trait_ref.def_id());
|
||||
if !is_alias || self.visited.contains(&pred) {
|
||||
return !is_alias;
|
||||
}
|
||||
|
||||
// Get components of the trait alias.
|
||||
let predicates = tcx.super_predicates_of(item.trait_ref.def_id());
|
||||
// Get components of trait alias.
|
||||
let predicates = tcx.super_predicates_of(trait_ref.def_id());
|
||||
|
||||
let mut items: Vec<_> = predicates.predicates
|
||||
let items: Vec<_> = predicates.predicates
|
||||
.iter()
|
||||
.rev()
|
||||
.filter_map(|(pred, span)| {
|
||||
pred.subst_supertrait(tcx, &item.trait_ref)
|
||||
pred.subst_supertrait(tcx, &trait_ref)
|
||||
.to_opt_poly_trait_ref()
|
||||
.map(|trait_ref|
|
||||
TraitRefExpansionInfo {
|
||||
trait_ref,
|
||||
span: *span,
|
||||
..*item
|
||||
}
|
||||
)
|
||||
.map(|trait_ref| item.push(trait_ref, *span))
|
||||
})
|
||||
.collect();
|
||||
|
||||
debug!("trait_ref_expander: 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()));
|
||||
debug!("expand_trait_aliases: items={:?}", items);
|
||||
|
||||
self.stack.extend(items);
|
||||
|
||||
// Record predicate into set of already-visited.
|
||||
self.visited.insert(&pred);
|
||||
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl<'cx, 'gcx, 'tcx> Iterator for TraitRefExpander<'cx, 'gcx, 'tcx> {
|
||||
type Item = TraitRefExpansionInfo<'tcx>;
|
||||
impl<'cx, 'gcx, 'tcx> Iterator for TraitAliasExpander<'cx, 'gcx, 'tcx> {
|
||||
type Item = TraitAliasExpansionInfo<'tcx>;
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
(self.stack.len(), None)
|
||||
}
|
||||
|
||||
fn next(&mut self) -> Option<TraitRefExpansionInfo<'tcx>> {
|
||||
fn next(&mut self) -> Option<TraitAliasExpansionInfo<'tcx>> {
|
||||
while let Some(item) = self.stack.pop() {
|
||||
if self.push(&item) {
|
||||
return Some(item);
|
||||
|
|
@ -386,8 +454,8 @@ impl<'cx, 'gcx, 'tcx> Iterator for SupertraitDefIds<'cx, 'gcx, 'tcx> {
|
|||
self.stack.extend(
|
||||
predicates.predicates
|
||||
.iter()
|
||||
.filter_map(|(p, _)| p.to_opt_poly_trait_ref())
|
||||
.map(|t| t.def_id())
|
||||
.filter_map(|(pred, _)| pred.to_opt_poly_trait_ref())
|
||||
.map(|trait_ref| trait_ref.def_id())
|
||||
.filter(|&super_def_id| visited.insert(super_def_id)));
|
||||
Some(def_id)
|
||||
}
|
||||
|
|
@ -413,17 +481,12 @@ impl<'tcx, I: Iterator<Item = ty::Predicate<'tcx>>> Iterator for FilterToTraits<
|
|||
type Item = ty::PolyTraitRef<'tcx>;
|
||||
|
||||
fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> {
|
||||
loop {
|
||||
match self.base_iterator.next() {
|
||||
None => {
|
||||
return None;
|
||||
}
|
||||
Some(ty::Predicate::Trait(data)) => {
|
||||
return Some(data.to_poly_trait_ref());
|
||||
}
|
||||
Some(_) => {}
|
||||
while let Some(pred) = self.base_iterator.next() {
|
||||
if let ty::Predicate::Trait(data) = pred {
|
||||
return Some(data.to_poly_trait_ref());
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
|
|
|
|||
|
|
@ -504,7 +504,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
any_lifetime_bounds = true;
|
||||
}
|
||||
}
|
||||
self.no_questions_in_bounds(bounds, "trait object types", false);
|
||||
}
|
||||
TyKind::ImplTrait(_, ref bounds) => {
|
||||
if self.is_impl_trait_banned {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use crate::lint;
|
|||
use crate::middle::resolve_lifetime as rl;
|
||||
use crate::namespace::Namespace;
|
||||
use rustc::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
|
||||
use rustc::traits;
|
||||
use rustc::traits::{self, TraitAliasExpansionInfoDignosticBuilder};
|
||||
use rustc::ty::{self, DefIdTree, Ty, TyCtxt, ToPredicate, TypeFoldable};
|
||||
use rustc::ty::{GenericParamDef, GenericParamDefKind};
|
||||
use rustc::ty::subst::{Kind, Subst, InternalSubsts, SubstsRef};
|
||||
|
|
@ -965,30 +965,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
|
|||
ty::ExistentialTraitRef::erase_self_ty(self.tcx(), trait_ref)
|
||||
}
|
||||
|
||||
fn expand_trait_refs(&self,
|
||||
trait_refs: impl IntoIterator<Item = (ty::PolyTraitRef<'tcx>, Span)>
|
||||
) -> Vec<DefId> {
|
||||
let tcx = self.tcx();
|
||||
|
||||
// Expand trait aliases recursively and check that only one regular (non-auto) trait
|
||||
// is used.
|
||||
let expanded_traits = traits::expand_trait_refs(tcx, 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 trait alias");
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
|
||||
auto_traits.into_iter().map(|i| i.trait_ref.def_id()).collect()
|
||||
}
|
||||
|
||||
fn conv_object_ty_poly_trait_ref(&self,
|
||||
span: Span,
|
||||
trait_bounds: &[hir::PolyTraitRef],
|
||||
|
|
@ -997,52 +973,69 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
|
|||
{
|
||||
let tcx = self.tcx();
|
||||
|
||||
if trait_bounds.is_empty() {
|
||||
let mut projection_bounds = Vec::new();
|
||||
let mut potential_assoc_types = Vec::new();
|
||||
let dummy_self = self.tcx().types.trait_object_dummy_self;
|
||||
let bound_trait_refs: Vec<_> = trait_bounds
|
||||
.iter()
|
||||
.rev()
|
||||
.map(|trait_bound| {
|
||||
let (trait_ref, cur_potential_assoc_types) = self.instantiate_poly_trait_ref(
|
||||
trait_bound,
|
||||
dummy_self,
|
||||
&mut projection_bounds
|
||||
);
|
||||
potential_assoc_types.extend(cur_potential_assoc_types.into_iter().flatten());
|
||||
(trait_ref, trait_bound.span)
|
||||
}).collect();
|
||||
|
||||
// Expand trait aliases recursively and check that only one regular (non-auto) trait
|
||||
// is used and no 'maybe' bounds are used.
|
||||
let expanded_traits = traits::expand_trait_aliases(tcx, bound_trait_refs.clone());
|
||||
let (mut 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.bottom().1, E0225,
|
||||
"only auto traits can be used as additional traits in a trait object");
|
||||
err.label_with_exp_info(extra_trait, "additional non-auto trait");
|
||||
err.span_label(regular_traits[0].top().1, "first non-auto trait");
|
||||
err.emit();
|
||||
}
|
||||
|
||||
if regular_traits.is_empty() && auto_traits.is_empty() {
|
||||
span_err!(tcx.sess, span, E0224,
|
||||
"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 (principal, potential_assoc_types) = self.instantiate_poly_trait_ref(
|
||||
&trait_bounds[0],
|
||||
dummy_self,
|
||||
&mut projection_bounds,
|
||||
);
|
||||
debug!("principal: {:?}", principal);
|
||||
|
||||
let mut bound_trait_refs = Vec::with_capacity(trait_bounds.len());
|
||||
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 = self.expand_trait_refs(bound_trait_refs);
|
||||
|
||||
// Check that there are no gross object safety violations;
|
||||
// most importantly, that the supertraits don't contain `Self`,
|
||||
// to avoid ICEs.
|
||||
let object_safety_violations =
|
||||
tcx.global_tcx().astconv_object_safety_violations(principal.def_id());
|
||||
if !object_safety_violations.is_empty() {
|
||||
tcx.report_object_safety_error(span, principal.def_id(), object_safety_violations)
|
||||
.map(|mut err| err.emit());
|
||||
return tcx.types.err;
|
||||
for item in ®ular_traits {
|
||||
let object_safety_violations =
|
||||
tcx.global_tcx().astconv_object_safety_violations(item.trait_ref().def_id());
|
||||
if !object_safety_violations.is_empty() {
|
||||
tcx.report_object_safety_error(
|
||||
span,
|
||||
item.trait_ref().def_id(),
|
||||
object_safety_violations
|
||||
)
|
||||
.map(|mut err| err.emit());
|
||||
return tcx.types.err;
|
||||
}
|
||||
}
|
||||
|
||||
// Use a `BTreeSet` to keep output in a more consistent order.
|
||||
let mut associated_types = BTreeSet::default();
|
||||
|
||||
for tr in traits::elaborate_trait_ref(tcx, principal) {
|
||||
debug!("conv_object_ty_poly_trait_ref: observing object predicate `{:?}`", tr);
|
||||
match tr {
|
||||
let regular_traits_refs = bound_trait_refs
|
||||
.into_iter()
|
||||
.filter(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id()))
|
||||
.map(|(trait_ref, _)| trait_ref);
|
||||
for trait_ref in traits::elaborate_trait_refs(tcx, regular_traits_refs) {
|
||||
debug!("conv_object_ty_poly_trait_ref: observing object predicate `{:?}`", trait_ref);
|
||||
match trait_ref {
|
||||
ty::Predicate::Trait(pred) => {
|
||||
associated_types
|
||||
.extend(tcx.associated_items(pred.def_id())
|
||||
|
|
@ -1102,20 +1095,18 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
|
|||
if associated_types.len() == 1 { "" } else { "s" },
|
||||
names,
|
||||
);
|
||||
let mut suggest = false;
|
||||
let mut potential_assoc_types_spans = vec![];
|
||||
if let Some(potential_assoc_types) = potential_assoc_types {
|
||||
let (suggest, potential_assoc_types_spans) =
|
||||
if potential_assoc_types.len() == associated_types.len() {
|
||||
// Only suggest when the amount of missing associated types is equals to the
|
||||
// Only suggest when the amount of missing associated types equals the number of
|
||||
// extra type arguments present, as that gives us a relatively high confidence
|
||||
// that the user forgot to give the associtated type's name. The canonical
|
||||
// example would be trying to use `Iterator<isize>` instead of
|
||||
// `Iterator<Item=isize>`.
|
||||
suggest = true;
|
||||
potential_assoc_types_spans = potential_assoc_types;
|
||||
}
|
||||
}
|
||||
let mut suggestions = vec![];
|
||||
// `Iterator<Item = isize>`.
|
||||
(true, potential_assoc_types)
|
||||
} else {
|
||||
(false, Vec::new())
|
||||
};
|
||||
let mut suggestions = Vec::new();
|
||||
for (i, item_def_id) in associated_types.iter().enumerate() {
|
||||
let assoc_item = tcx.associated_item(*item_def_id);
|
||||
err.span_label(
|
||||
|
|
@ -1151,9 +1142,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
|
|||
err.emit();
|
||||
}
|
||||
|
||||
// De-duplicate auto traits so that, e.g., `dyn Trait + Send + Send` is the same as
|
||||
// `dyn Trait + Send`.
|
||||
auto_traits.sort_by_key(|i| i.trait_ref().def_id());
|
||||
auto_traits.dedup_by_key(|i| i.trait_ref().def_id());
|
||||
debug!("regular_traits: {:?}", regular_traits);
|
||||
debug!("auto_traits: {:?}", auto_traits);
|
||||
|
||||
// Erase the `dummy_self` (`trait_object_dummy_self`) used above.
|
||||
let existential_principal = principal.map_bound(|trait_ref| {
|
||||
self.trait_ref_to_existential(trait_ref)
|
||||
let existential_trait_refs = regular_traits.iter().map(|i| {
|
||||
i.trait_ref().map_bound(|trait_ref| self.trait_ref_to_existential(trait_ref))
|
||||
});
|
||||
let existential_projections = projection_bounds.iter().map(|(bound, _)| {
|
||||
bound.map_bound(|b| {
|
||||
|
|
@ -1166,21 +1164,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
|
|||
})
|
||||
});
|
||||
|
||||
// De-duplicate auto traits so that, e.g., `dyn Trait + Send + Send` is the same as
|
||||
// `dyn Trait + Send`.
|
||||
auto_traits.sort();
|
||||
auto_traits.dedup();
|
||||
debug!("auto_traits: {:?}", auto_traits);
|
||||
|
||||
// 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 {
|
||||
ty::ExistentialPredicate::Trait(*existential_principal.skip_binder())
|
||||
};
|
||||
let regular_trait_predicates = existential_trait_refs.map(
|
||||
|trait_ref| ty::ExistentialPredicate::Trait(*trait_ref.skip_binder()));
|
||||
let auto_trait_predicates = auto_traits.into_iter().map(
|
||||
|trait_ref| ty::ExistentialPredicate::AutoTrait(trait_ref.trait_ref().def_id()));
|
||||
let mut v =
|
||||
iter::once(principal)
|
||||
.chain(auto_traits.into_iter().map(ty::ExistentialPredicate::AutoTrait))
|
||||
regular_trait_predicates
|
||||
.chain(auto_trait_predicates)
|
||||
.chain(existential_projections
|
||||
.map(|x| ty::ExistentialPredicate::Projection(*x.skip_binder())))
|
||||
.collect::<SmallVec<[_; 8]>>();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue