Skip to content

Commit 961e2ec

Browse files
author
Alexander Regueiro
committed
Report all intermediate expansions of trait aliases.
1 parent d3789c4 commit 961e2ec

File tree

4 files changed

+62
-38
lines changed

4 files changed

+62
-38
lines changed

src/librustc/traits/util.rs

Lines changed: 43 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
use smallvec::SmallVec;
12+
1113
use hir::{self};
1214
use hir::def_id::DefId;
1315
use syntax_pos::Span;
@@ -282,63 +284,79 @@ pub struct TraitRefExpander<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
282284

283285
#[derive(Debug, Clone)]
284286
pub struct TraitRefExpansionInfo<'tcx> {
285-
pub top_level_trait_ref: ty::PolyTraitRef<'tcx>,
286-
pub top_level_span: Span,
287-
pub trait_ref: ty::PolyTraitRef<'tcx>,
288-
pub span: Span,
287+
pub items: SmallVec<[(ty::PolyTraitRef<'tcx>, Span); 4]>,
288+
}
289+
290+
impl<'tcx> TraitRefExpansionInfo<'tcx> {
291+
fn new(trait_ref: ty::PolyTraitRef<'tcx>, span: Span) -> TraitRefExpansionInfo<'tcx> {
292+
TraitRefExpansionInfo {
293+
items: smallvec![(trait_ref, span)]
294+
}
295+
}
296+
297+
fn push(&self, trait_ref: ty::PolyTraitRef<'tcx>, span: Span) -> TraitRefExpansionInfo<'tcx> {
298+
let mut items = self.items.clone();
299+
items.push((trait_ref, span));
300+
301+
TraitRefExpansionInfo {
302+
items
303+
}
304+
}
305+
306+
pub fn trait_ref(&self) -> &ty::PolyTraitRef<'tcx> {
307+
&self.top().0
308+
}
309+
310+
pub fn top(&self) -> &(ty::PolyTraitRef<'tcx>, Span) {
311+
self.items.last().unwrap()
312+
}
313+
314+
pub fn bottom(&self) -> &(ty::PolyTraitRef<'tcx>, Span) {
315+
self.items.first().unwrap()
316+
}
289317
}
290318

291319
pub fn expand_trait_refs<'cx, 'gcx, 'tcx>(
292320
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
293321
trait_refs: impl IntoIterator<Item = (ty::PolyTraitRef<'tcx>, Span)>
294322
) -> TraitRefExpander<'cx, 'gcx, 'tcx> {
295323
let mut visited = PredicateSet::new(tcx);
296-
let mut items: Vec<_> =
297-
trait_refs.into_iter()
298-
.map(|(tr, sp)| TraitRefExpansionInfo {
299-
top_level_trait_ref: tr.clone(),
300-
top_level_span: sp,
301-
trait_ref: tr,
302-
span: sp,
303-
})
324+
let mut items: Vec<_> = trait_refs
325+
.into_iter()
326+
.map(|(tr, sp)| TraitRefExpansionInfo::new(tr, sp))
304327
.collect();
305-
items.retain(|item| visited.insert(&item.trait_ref.to_predicate()));
328+
items.retain(|i| visited.insert(&i.trait_ref().to_predicate()));
306329
TraitRefExpander { stack: items, visited: visited, }
307330
}
308331

309332
impl<'cx, 'gcx, 'tcx> TraitRefExpander<'cx, 'gcx, 'tcx> {
310333
// Returns `true` if `item` refers to a trait.
311334
fn push(&mut self, item: &TraitRefExpansionInfo<'tcx>) -> bool {
312335
let tcx = self.visited.tcx;
336+
let trait_ref = item.trait_ref();
313337

314-
if !ty::is_trait_alias(tcx, item.trait_ref.def_id()) {
338+
if !ty::is_trait_alias(tcx, trait_ref.def_id()) {
315339
return true;
316340
}
317341

318342
// Get predicates declared on the trait.
319-
let predicates = tcx.super_predicates_of(item.trait_ref.def_id());
343+
let predicates = tcx.super_predicates_of(trait_ref.def_id());
320344

321345
let mut items: Vec<_> = predicates.predicates
322346
.iter()
323347
.rev()
324348
.filter_map(|(pred, sp)| {
325-
pred.subst_supertrait(tcx, &item.trait_ref)
349+
pred.subst_supertrait(tcx, &trait_ref)
326350
.to_opt_poly_trait_ref()
327-
.map(|trait_ref|
328-
TraitRefExpansionInfo {
329-
trait_ref,
330-
span: *sp,
331-
..*item
332-
}
333-
)
351+
.map(|tr| item.push(tr, *sp))
334352
})
335353
.collect();
336354

337355
debug!("expand_trait_refs: trait_ref={:?} items={:?}",
338-
item.trait_ref, items);
356+
trait_ref, items);
339357

340358
// Only keep those items that we haven't already seen.
341-
items.retain(|i| self.visited.insert(&i.trait_ref.to_predicate()));
359+
items.retain(|i| self.visited.insert(&i.trait_ref().to_predicate()));
342360

343361
self.stack.extend(items);
344362
false

src/librustc_typeck/astconv.rs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -949,7 +949,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
949949
/// Transform a `PolyTraitRef` into a `PolyExistentialTraitRef` by
950950
/// removing the dummy `Self` type (`TRAIT_OBJECT_DUMMY_SELF`).
951951
fn trait_ref_to_existential(&self, trait_ref: ty::TraitRef<'tcx>)
952-
-> ty::ExistentialTraitRef<'tcx> {
952+
-> ty::ExistentialTraitRef<'tcx>
953+
{
953954
assert_eq!(trait_ref.self_ty().sty, TRAIT_OBJECT_DUMMY_SELF);
954955
ty::ExistentialTraitRef::erase_self_ty(self.tcx(), trait_ref)
955956
}
@@ -989,14 +990,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
989990

990991
let expanded_traits = traits::expand_trait_refs(tcx, bound_trait_refs);
991992
let (auto_traits, regular_traits): (Vec<_>, Vec<_>) =
992-
expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref.def_id()));
993+
expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
993994
if regular_traits.len() > 1 {
994995
let extra_trait = &regular_traits[1];
995-
let mut err = struct_span_err!(tcx.sess, extra_trait.top_level_span, E0225,
996+
let mut err = struct_span_err!(tcx.sess, extra_trait.bottom().1, E0225,
996997
"only auto traits can be used as additional traits in a trait object");
997-
err.span_label(extra_trait.span, "non-auto additional trait");
998-
if extra_trait.span != extra_trait.top_level_span {
999-
err.span_label(extra_trait.top_level_span, "expanded from this alias");
998+
err.span_label(extra_trait.top().1, "non-auto additional trait");
999+
if extra_trait.items.len() > 2 {
1000+
for (_, sp) in extra_trait.items[1..(extra_trait.items.len() - 1)].iter().rev() {
1001+
err.span_label(*sp, "referenced by this alias");
1002+
}
10001003
}
10011004
err.emit();
10021005
}
@@ -1123,14 +1126,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
11231126
// Dedup auto traits so that e.g. `dyn Trait + Send + Send` is the same as
11241127
// `dyn Trait + Send`. Skip the first auto trait if it is the principal trait.
11251128
let auto_traits_start_index =
1126-
if auto_traits.first().map_or(false, |i| i.trait_ref == principal) {
1129+
if auto_traits.first().map_or(false, |i| i.trait_ref() == &principal) {
11271130
1
11281131
} else {
11291132
0
11301133
};
11311134
let mut auto_traits: Vec<_> =
11321135
auto_traits[auto_traits_start_index..].into_iter()
1133-
.map(|i| i.trait_ref.def_id())
1136+
.map(|i| i.trait_ref().def_id())
11341137
.collect();
11351138
auto_traits.sort();
11361139
auto_traits.dedup();

src/test/ui/error-codes/E0225.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@
1111
#![feature(trait_alias)]
1212

1313
trait Foo = std::io::Read + std::io::Write;
14+
trait Bar = Foo;
1415

1516
fn main() {
1617
let _: Box<std::io::Read + std::io::Write>;
17-
let _: Box<Foo>;
18+
let _: Box<Bar>;
1819
}

src/test/ui/error-codes/E0225.stderr

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
error[E0225]: only auto traits can be used as additional traits in a trait object
2-
--> $DIR/E0225.rs:16:32
2+
--> $DIR/E0225.rs:17:32
33
|
44
LL | let _: Box<std::io::Read + std::io::Write>;
55
| ^^^^^^^^^^^^^^ non-auto additional trait
66

77
error[E0225]: only auto traits can be used as additional traits in a trait object
8-
--> $DIR/E0225.rs:17:16
8+
--> $DIR/E0225.rs:18:16
99
|
1010
LL | trait Foo = std::io::Read + std::io::Write;
1111
| -------------- non-auto additional trait
12+
LL | trait Bar = Foo;
13+
| --- referenced by this alias
1214
...
13-
LL | let _: Box<Foo>;
14-
| ^^^ expanded from this alias
15+
LL | let _: Box<Bar>;
16+
| ^^^
1517

1618
error: aborting due to 2 previous errors
1719

0 commit comments

Comments
 (0)