Addressed more points raised in review.

This commit is contained in:
Alexander Regueiro 2019-05-13 19:51:33 +01:00
parent 783b713b5d
commit a0a61904f4
3 changed files with 38 additions and 50 deletions

View File

@ -63,9 +63,7 @@ pub use self::util::{elaborate_predicates, elaborate_trait_ref, elaborate_trait_
pub use self::util::{ pub use self::util::{
supertraits, supertrait_def_ids, transitive_bounds, Supertraits, SupertraitDefIds, supertraits, supertrait_def_ids, transitive_bounds, Supertraits, SupertraitDefIds,
}; };
pub use self::util::{ pub use self::util::{expand_trait_aliases, TraitAliasExpander};
expand_trait_aliases, TraitAliasExpander, TraitAliasExpansionInfoDignosticBuilder,
};
pub use self::chalk_fulfill::{ pub use self::chalk_fulfill::{
CanonicalGoal as ChalkCanonicalGoal, CanonicalGoal as ChalkCanonicalGoal,

View File

@ -132,18 +132,18 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> {
// Get predicates declared on the trait. // Get predicates declared on the trait.
let predicates = tcx.super_predicates_of(data.def_id()); let predicates = tcx.super_predicates_of(data.def_id());
let mut predicates: Vec<_> = predicates.predicates let predicates = predicates.predicates
.iter() .iter()
.map(|(pred, _)| pred.subst_supertrait(tcx, &data.to_poly_trait_ref())) .map(|(pred, _)| pred.subst_supertrait(tcx, &data.to_poly_trait_ref()));
.collect();
debug!("super_predicates: data={:?} predicates={:?}", debug!("super_predicates: data={:?} predicates={:?}",
data, predicates); data, predicates.clone());
// Only keep those bounds that we haven't already seen. // Only keep those bounds that we haven't already seen.
// This is necessary to prevent infinite recursion in some // This is necessary to prevent infinite recursion in some
// cases. One common case is when people define // cases. One common case is when people define
// `trait Sized: Sized { }` rather than `trait Sized { }`. // `trait Sized: Sized { }` rather than `trait Sized { }`.
predicates.retain(|pred| self.visited.insert(pred)); let visited = &mut self.visited;
let predicates = predicates.filter(|pred| visited.insert(pred));
self.stack.extend(predicates); self.stack.extend(predicates);
} }
@ -298,14 +298,22 @@ impl<'tcx> TraitAliasExpansionInfo<'tcx> {
} }
} }
fn clone_and_push(&self, trait_ref: ty::PolyTraitRef<'tcx>, span: Span) -> Self { /// Adds diagnostic labels to `diag` for the expansion path of a trait through all intermediate
let mut path = self.path.clone(); /// trait aliases.
path.push((trait_ref, span)); pub fn label_with_exp_info(&self,
diag: &mut DiagnosticBuilder<'_>,
Self { top_label: &str,
path use_desc: &str
) {
diag.span_label(self.top().1, top_label);
if self.path.len() > 1 {
for (_, sp) in self.path.iter().rev().skip(1).take(self.path.len() - 2) {
diag.span_label(*sp, format!("referenced here ({})", use_desc));
} }
} }
diag.span_label(self.bottom().1,
format!("trait alias used in trait object type ({})", use_desc));
}
pub fn trait_ref(&self) -> &ty::PolyTraitRef<'tcx> { pub fn trait_ref(&self) -> &ty::PolyTraitRef<'tcx> {
&self.top().0 &self.top().0
@ -318,34 +326,15 @@ impl<'tcx> TraitAliasExpansionInfo<'tcx> {
pub fn bottom(&self) -> &(ty::PolyTraitRef<'tcx>, Span) { pub fn bottom(&self) -> &(ty::PolyTraitRef<'tcx>, Span) {
self.path.first().unwrap() self.path.first().unwrap()
} }
}
/// Emits diagnostic information relating to the expansion of a trait via trait aliases fn clone_and_push(&self, trait_ref: ty::PolyTraitRef<'tcx>, span: Span) -> Self {
/// (see [`TraitAliasExpansionInfo`]). let mut path = self.path.clone();
pub trait TraitAliasExpansionInfoDignosticBuilder { path.push((trait_ref, span));
fn label_with_exp_info<'tcx>(&mut self,
info: &TraitAliasExpansionInfo<'tcx>,
top_label: &str,
use_desc: &str
) -> &mut Self;
}
impl<'a> TraitAliasExpansionInfoDignosticBuilder for DiagnosticBuilder<'a> { Self {
fn label_with_exp_info<'tcx>(&mut self, path
info: &TraitAliasExpansionInfo<'tcx>,
top_label: &str,
use_desc: &str
) -> &mut Self {
self.span_label(info.top().1, top_label);
if info.path.len() > 1 {
for (_, sp) in info.path.iter().rev().skip(1).take(info.path.len() - 2) {
self.span_label(*sp, format!("referenced here ({})", use_desc));
} }
} }
self.span_label(info.bottom().1,
format!("trait alias used in trait object type ({})", use_desc));
self
}
} }
pub fn expand_trait_aliases<'cx, 'gcx, 'tcx>( pub fn expand_trait_aliases<'cx, 'gcx, 'tcx>(
@ -388,16 +377,15 @@ impl<'cx, 'gcx, 'tcx> TraitAliasExpander<'cx, 'gcx, 'tcx> {
// Get components of trait alias. // Get components of trait alias.
let predicates = tcx.super_predicates_of(trait_ref.def_id()); let predicates = tcx.super_predicates_of(trait_ref.def_id());
let items: Vec<_> = predicates.predicates let items = predicates.predicates
.iter() .iter()
.rev() .rev()
.filter_map(|(pred, span)| { .filter_map(|(pred, span)| {
pred.subst_supertrait(tcx, &trait_ref) pred.subst_supertrait(tcx, &trait_ref)
.to_opt_poly_trait_ref() .to_opt_poly_trait_ref()
.map(|trait_ref| item.clone_and_push(trait_ref, *span)) .map(|trait_ref| item.clone_and_push(trait_ref, *span))
}) });
.collect(); debug!("expand_trait_aliases: items={:?}", items.clone());
debug!("expand_trait_aliases: items={:?}", items);
self.stack.extend(items); self.stack.extend(items);

View File

@ -11,7 +11,7 @@ use crate::lint;
use crate::middle::resolve_lifetime as rl; use crate::middle::resolve_lifetime as rl;
use crate::namespace::Namespace; use crate::namespace::Namespace;
use rustc::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS; use rustc::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
use rustc::traits::{self, TraitAliasExpansionInfoDignosticBuilder}; use rustc::traits;
use rustc::ty::{self, DefIdTree, Ty, TyCtxt, ToPredicate, TypeFoldable}; use rustc::ty::{self, DefIdTree, Ty, TyCtxt, ToPredicate, TypeFoldable};
use rustc::ty::{GenericParamDef, GenericParamDefKind}; use rustc::ty::{GenericParamDef, GenericParamDefKind};
use rustc::ty::subst::{Kind, Subst, InternalSubsts, SubstsRef}; use rustc::ty::subst::{Kind, Subst, InternalSubsts, SubstsRef};
@ -976,6 +976,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
let mut projection_bounds = Vec::new(); let mut projection_bounds = Vec::new();
let mut potential_assoc_types = Vec::new(); let mut potential_assoc_types = Vec::new();
let dummy_self = self.tcx().types.trait_object_dummy_self; let dummy_self = self.tcx().types.trait_object_dummy_self;
// FIXME: we want to avoid collecting into a `Vec` here, but simply cloning the iterator is
// not straightforward due to the borrow checker.
let bound_trait_refs: Vec<_> = trait_bounds let bound_trait_refs: Vec<_> = trait_bounds
.iter() .iter()
.rev() .rev()
@ -998,14 +1000,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
if regular_traits.len() > 1 { if regular_traits.len() > 1 {
let first_trait = &regular_traits[0]; let first_trait = &regular_traits[0];
let additional_trait = &regular_traits[1]; let additional_trait = &regular_traits[1];
struct_span_err!(tcx.sess, additional_trait.bottom().1, E0225, let mut err = struct_span_err!(tcx.sess, additional_trait.bottom().1, E0225,
"only auto traits can be used as additional traits in a trait object" "only auto traits can be used as additional traits in a trait object"
) );
.label_with_exp_info(additional_trait, "additional non-auto trait", additional_trait.label_with_exp_info(&mut err,
"additional use") "additional non-auto trait", "additional use");
.label_with_exp_info(first_trait, "first non-auto trait", first_trait.label_with_exp_info(&mut err,
"first use") "first non-auto trait", "first use");
.emit(); err.emit();
} }
if regular_traits.is_empty() && auto_traits.is_empty() { if regular_traits.is_empty() && auto_traits.is_empty() {