Skip to content

Commit aea954b

Browse files
author
Alexander Regueiro
committed
Fixed detection of multiple non-auto traits.
1 parent 5f6c212 commit aea954b

File tree

4 files changed

+208
-152
lines changed

4 files changed

+208
-152
lines changed

src/librustc/traits/mod.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,12 @@ pub use self::specialize::specialization_graph::FutureCompatOverlapError;
6060
pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind;
6161
pub use self::engine::{TraitEngine, TraitEngineExt};
6262
pub use self::util::{elaborate_predicates, elaborate_trait_ref, elaborate_trait_refs};
63-
pub use self::util::{supertraits, supertrait_def_ids, transitive_bounds,
64-
Supertraits, SupertraitDefIds};
65-
pub use self::util::{expand_trait_refs, TraitRefExpander};
63+
pub use self::util::{
64+
supertraits, supertrait_def_ids, transitive_bounds, Supertraits, SupertraitDefIds,
65+
};
66+
pub use self::util::{
67+
expand_trait_aliases, TraitAliasExpander, TraitAliasExpansionInfoDignosticBuilder,
68+
};
6669

6770
pub use self::chalk_fulfill::{
6871
CanonicalGoal as ChalkCanonicalGoal,

src/librustc/traits/util.rs

Lines changed: 129 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use errors::DiagnosticBuilder;
2+
use smallvec::SmallVec;
13
use syntax_pos::Span;
24

35
use crate::hir;
@@ -43,7 +45,7 @@ fn anonymize_predicate<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
4345
}
4446
}
4547

46-
struct PredicateSet<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
48+
struct PredicateSet<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
4749
tcx: TyCtxt<'a, 'gcx, 'tcx>,
4850
set: FxHashSet<ty::Predicate<'tcx>>,
4951
}
@@ -53,6 +55,10 @@ impl<'a, 'gcx, 'tcx> PredicateSet<'a, 'gcx, 'tcx> {
5355
PredicateSet { tcx: tcx, set: Default::default() }
5456
}
5557

58+
fn contains(&mut self, pred: &ty::Predicate<'tcx>) -> bool {
59+
self.set.contains(&anonymize_predicate(self.tcx, pred))
60+
}
61+
5662
fn insert(&mut self, pred: &ty::Predicate<'tcx>) -> bool {
5763
// We have to be careful here because we want
5864
//
@@ -66,6 +72,18 @@ impl<'a, 'gcx, 'tcx> PredicateSet<'a, 'gcx, 'tcx> {
6672
// regions before we throw things into the underlying set.
6773
self.set.insert(anonymize_predicate(self.tcx, pred))
6874
}
75+
76+
fn remove(&mut self, pred: &ty::Predicate<'tcx>) -> bool {
77+
self.set.remove(&anonymize_predicate(self.tcx, pred))
78+
}
79+
}
80+
81+
impl<'a, 'gcx, 'tcx, T: AsRef<ty::Predicate<'tcx>>> Extend<T> for PredicateSet<'a, 'gcx, 'tcx> {
82+
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
83+
for pred in iter.into_iter() {
84+
self.insert(pred.as_ref());
85+
}
86+
}
6987
}
7088

7189
///////////////////////////////////////////////////////////////////////////
@@ -230,10 +248,16 @@ impl<'cx, 'gcx, 'tcx> Iterator for Elaborator<'cx, 'gcx, 'tcx> {
230248
}
231249

232250
fn next(&mut self) -> Option<ty::Predicate<'tcx>> {
233-
self.stack.pop().map(|item| {
234-
self.push(&item);
235-
item
236-
})
251+
// Extract next item from top-most stack frame, if any.
252+
let next_predicate = match self.stack.pop() {
253+
Some(predicate) => predicate,
254+
None => {
255+
// No more stack frames. Done.
256+
return None;
257+
}
258+
};
259+
self.push(&next_predicate);
260+
return Some(next_predicate);
237261
}
238262
}
239263

@@ -256,96 +280,140 @@ pub fn transitive_bounds<'cx, 'gcx, 'tcx>(tcx: TyCtxt<'cx, 'gcx, 'tcx>,
256280
}
257281

258282
///////////////////////////////////////////////////////////////////////////
259-
// `TraitRefExpander` iterator
283+
// `TraitAliasExpander` iterator
260284
///////////////////////////////////////////////////////////////////////////
261285

262-
/// "Trait reference expansion" is the process of expanding a sequence of trait
286+
/// "Trait alias expansion" is the process of expanding a sequence of trait
263287
/// references into another sequence by transitively following all trait
264288
/// aliases. e.g. If you have bounds like `Foo + Send`, a trait alias
265289
/// `trait Foo = Bar + Sync;`, and another trait alias
266290
/// `trait Bar = Read + Write`, then the bounds would expand to
267291
/// `Read + Write + Sync + Send`.
268-
pub struct TraitRefExpander<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
269-
stack: Vec<TraitRefExpansionInfo<'tcx>>,
292+
pub struct TraitAliasExpander<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
293+
stack: Vec<TraitAliasExpansionInfo<'tcx>>,
294+
/// The set of predicates visited from the root directly to the current point in the
295+
/// expansion tree.
270296
visited: PredicateSet<'a, 'gcx, 'tcx>,
271297
}
272298

273299
#[derive(Debug, Clone)]
274-
pub struct TraitRefExpansionInfo<'tcx> {
275-
pub top_level_trait_ref: ty::PolyTraitRef<'tcx>,
276-
pub top_level_span: Span,
277-
pub trait_ref: ty::PolyTraitRef<'tcx>,
278-
pub span: Span,
300+
pub struct TraitAliasExpansionInfo<'tcx> {
301+
pub items: SmallVec<[(ty::PolyTraitRef<'tcx>, Span); 4]>,
279302
}
280303

281-
pub fn expand_trait_refs<'cx, 'gcx, 'tcx>(
304+
impl<'tcx> TraitAliasExpansionInfo<'tcx> {
305+
fn new(trait_ref: ty::PolyTraitRef<'tcx>, span: Span) -> TraitAliasExpansionInfo<'tcx> {
306+
TraitAliasExpansionInfo {
307+
items: smallvec![(trait_ref, span)]
308+
}
309+
}
310+
311+
fn push(&self, trait_ref: ty::PolyTraitRef<'tcx>, span: Span) -> TraitAliasExpansionInfo<'tcx> {
312+
let mut items = self.items.clone();
313+
items.push((trait_ref, span));
314+
315+
TraitAliasExpansionInfo {
316+
items
317+
}
318+
}
319+
320+
pub fn trait_ref(&self) -> &ty::PolyTraitRef<'tcx> {
321+
&self.top().0
322+
}
323+
324+
pub fn top(&self) -> &(ty::PolyTraitRef<'tcx>, Span) {
325+
self.items.last().unwrap()
326+
}
327+
328+
pub fn bottom(&self) -> &(ty::PolyTraitRef<'tcx>, Span) {
329+
self.items.first().unwrap()
330+
}
331+
}
332+
333+
pub trait TraitAliasExpansionInfoDignosticBuilder {
334+
fn label_with_exp_info<'tcx>(&mut self,
335+
info: &TraitAliasExpansionInfo<'tcx>,
336+
top_label: &str
337+
) -> &mut Self;
338+
}
339+
340+
impl<'a> TraitAliasExpansionInfoDignosticBuilder for DiagnosticBuilder<'a> {
341+
fn label_with_exp_info<'tcx>(&mut self,
342+
info: &TraitAliasExpansionInfo<'tcx>,
343+
top_label: &str
344+
) -> &mut Self {
345+
self.span_label(info.top().1, top_label);
346+
if info.items.len() > 1 {
347+
for (_, sp) in info.items[1..(info.items.len() - 1)].iter().rev() {
348+
self.span_label(*sp, "referenced here");
349+
}
350+
}
351+
self
352+
}
353+
}
354+
355+
pub fn expand_trait_aliases<'cx, 'gcx, 'tcx>(
282356
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
283357
trait_refs: impl IntoIterator<Item = (ty::PolyTraitRef<'tcx>, Span)>
284-
) -> TraitRefExpander<'cx, 'gcx, 'tcx> {
285-
let mut visited = PredicateSet::new(tcx);
286-
let mut items: Vec<_> =
287-
trait_refs
288-
.into_iter()
289-
.map(|(trait_ref, span)| TraitRefExpansionInfo {
290-
top_level_trait_ref: trait_ref.clone(),
291-
top_level_span: span,
292-
trait_ref,
293-
span,
294-
})
295-
.collect();
296-
items.retain(|item| visited.insert(&item.trait_ref.to_predicate()));
297-
TraitRefExpander { stack: items, visited }
358+
) -> TraitAliasExpander<'cx, 'gcx, 'tcx> {
359+
let items: Vec<_> = trait_refs
360+
.into_iter()
361+
.map(|(trait_ref, span)| TraitAliasExpansionInfo::new(trait_ref, span))
362+
.collect();
363+
TraitAliasExpander { stack: items, visited: PredicateSet::new(tcx) }
298364
}
299365

300-
impl<'cx, 'gcx, 'tcx> TraitRefExpander<'cx, 'gcx, 'tcx> {
301-
/// If `item` refers to a trait alias, adds the components of the trait alias to the stack,
302-
/// and returns `false`.
303-
/// If `item` refers to an ordinary trait, simply returns `true`.
304-
fn push(&mut self, item: &TraitRefExpansionInfo<'tcx>) -> bool {
366+
impl<'cx, 'gcx, 'tcx> TraitAliasExpander<'cx, 'gcx, 'tcx> {
367+
/// If `item` is a trait alias and its predicate has not yet been visited, then expands `item`
368+
/// to the definition and pushes the resulting expansion onto `self.stack`, and returns `false`.
369+
/// Otherwise, immediately returns `true` if `item` is a regular trait and `false` if it is a
370+
/// trait alias.
371+
/// The return value indicates whether `item` should not be yielded to the user.
372+
fn push(&mut self, item: &TraitAliasExpansionInfo<'tcx>) -> bool {
305373
let tcx = self.visited.tcx;
374+
let trait_ref = item.trait_ref();
375+
let pred = trait_ref.to_predicate();
376+
377+
debug!("expand_trait_aliases: trait_ref={:?}", trait_ref);
378+
379+
self.visited.remove(&pred);
306380

307-
if !tcx.is_trait_alias(item.trait_ref.def_id()) {
308-
return true;
381+
let is_alias = tcx.is_trait_alias(trait_ref.def_id());
382+
if !is_alias || self.visited.contains(&pred) {
383+
return !is_alias;
309384
}
310385

311-
// Get components of the trait alias.
312-
let predicates = tcx.super_predicates_of(item.trait_ref.def_id());
386+
// Get components of trait alias.
387+
let predicates = tcx.super_predicates_of(trait_ref.def_id());
313388

314-
let mut items: Vec<_> = predicates.predicates
389+
let items: Vec<_> = predicates.predicates
315390
.iter()
316391
.rev()
317392
.filter_map(|(pred, span)| {
318-
pred.subst_supertrait(tcx, &item.trait_ref)
393+
pred.subst_supertrait(tcx, &trait_ref)
319394
.to_opt_poly_trait_ref()
320-
.map(|trait_ref|
321-
TraitRefExpansionInfo {
322-
trait_ref,
323-
span: *span,
324-
..*item
325-
}
326-
)
395+
.map(|trait_ref| item.push(trait_ref, *span))
327396
})
328397
.collect();
398+
debug!("expand_trait_aliases: items={:?}", items);
329399

330-
debug!("trait_ref_expander: trait_ref={:?} items={:?}",
331-
item.trait_ref, items);
400+
self.stack.extend(items);
332401

333-
// Only keep those items that we haven't already seen.
334-
items.retain(|i| self.visited.insert(&i.trait_ref.to_predicate()));
402+
// Record predicate into set of already-visited.
403+
self.visited.insert(&pred);
335404

336-
self.stack.extend(items);
337405
false
338406
}
339407
}
340408

341-
impl<'cx, 'gcx, 'tcx> Iterator for TraitRefExpander<'cx, 'gcx, 'tcx> {
342-
type Item = TraitRefExpansionInfo<'tcx>;
409+
impl<'cx, 'gcx, 'tcx> Iterator for TraitAliasExpander<'cx, 'gcx, 'tcx> {
410+
type Item = TraitAliasExpansionInfo<'tcx>;
343411

344412
fn size_hint(&self) -> (usize, Option<usize>) {
345413
(self.stack.len(), None)
346414
}
347415

348-
fn next(&mut self) -> Option<TraitRefExpansionInfo<'tcx>> {
416+
fn next(&mut self) -> Option<TraitAliasExpansionInfo<'tcx>> {
349417
while let Some(item) = self.stack.pop() {
350418
if self.push(&item) {
351419
return Some(item);
@@ -386,8 +454,8 @@ impl<'cx, 'gcx, 'tcx> Iterator for SupertraitDefIds<'cx, 'gcx, 'tcx> {
386454
self.stack.extend(
387455
predicates.predicates
388456
.iter()
389-
.filter_map(|(p, _)| p.to_opt_poly_trait_ref())
390-
.map(|t| t.def_id())
457+
.filter_map(|(pred, _)| pred.to_opt_poly_trait_ref())
458+
.map(|trait_ref| trait_ref.def_id())
391459
.filter(|&super_def_id| visited.insert(super_def_id)));
392460
Some(def_id)
393461
}
@@ -413,17 +481,12 @@ impl<'tcx, I: Iterator<Item = ty::Predicate<'tcx>>> Iterator for FilterToTraits<
413481
type Item = ty::PolyTraitRef<'tcx>;
414482

415483
fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> {
416-
loop {
417-
match self.base_iterator.next() {
418-
None => {
419-
return None;
420-
}
421-
Some(ty::Predicate::Trait(data)) => {
422-
return Some(data.to_poly_trait_ref());
423-
}
424-
Some(_) => {}
484+
while let Some(pred) = self.base_iterator.next() {
485+
if let ty::Predicate::Trait(data) = pred {
486+
return Some(data.to_poly_trait_ref());
425487
}
426488
}
489+
None
427490
}
428491

429492
fn size_hint(&self) -> (usize, Option<usize>) {

src/librustc_passes/ast_validation.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -504,7 +504,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
504504
any_lifetime_bounds = true;
505505
}
506506
}
507-
self.no_questions_in_bounds(bounds, "trait object types", false);
508507
}
509508
TyKind::ImplTrait(_, ref bounds) => {
510509
if self.is_impl_trait_banned {

0 commit comments

Comments
 (0)