Skip to content

Commit 2009662

Browse files
author
Alexander Regueiro
committed
Addressed points raised in review.
1 parent fd7c253 commit 2009662

15 files changed

+119
-61
lines changed

src/librustc/traits/util.rs

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ impl<'a, 'gcx, 'tcx> PredicateSet<'a, 'gcx, 'tcx> {
5656
}
5757

5858
fn contains(&mut self, pred: &ty::Predicate<'tcx>) -> bool {
59+
// See the `insert` method for why we use `anonymize_predicate` here.
5960
self.set.contains(&anonymize_predicate(self.tcx, pred))
6061
}
6162

@@ -74,13 +75,14 @@ impl<'a, 'gcx, 'tcx> PredicateSet<'a, 'gcx, 'tcx> {
7475
}
7576

7677
fn remove(&mut self, pred: &ty::Predicate<'tcx>) -> bool {
78+
// See the `insert` method for why we use `anonymize_predicate` here.
7779
self.set.remove(&anonymize_predicate(self.tcx, pred))
7880
}
7981
}
8082

8183
impl<'a, 'gcx, 'tcx, T: AsRef<ty::Predicate<'tcx>>> Extend<T> for PredicateSet<'a, 'gcx, 'tcx> {
8284
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
83-
for pred in iter.into_iter() {
85+
for pred in iter {
8486
self.insert(pred.as_ref());
8587
}
8688
}
@@ -289,30 +291,33 @@ pub fn transitive_bounds<'cx, 'gcx, 'tcx>(tcx: TyCtxt<'cx, 'gcx, 'tcx>,
289291
/// `trait Foo = Bar + Sync;`, and another trait alias
290292
/// `trait Bar = Read + Write`, then the bounds would expand to
291293
/// `Read + Write + Sync + Send`.
294+
/// Expansion is done via a DFS (depth-first search), and the `visited` field
295+
/// is used to avoid cycles.
292296
pub struct TraitAliasExpander<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
293297
stack: Vec<TraitAliasExpansionInfo<'tcx>>,
294298
/// The set of predicates visited from the root directly to the current point in the
295-
/// expansion tree.
299+
/// expansion tree (only containing trait aliases).
296300
visited: PredicateSet<'a, 'gcx, 'tcx>,
297301
}
298302

303+
/// Stores information about the expansion of a trait via a path of zero or more trait aliases.
299304
#[derive(Debug, Clone)]
300305
pub struct TraitAliasExpansionInfo<'tcx> {
301306
pub items: SmallVec<[(ty::PolyTraitRef<'tcx>, Span); 4]>,
302307
}
303308

304309
impl<'tcx> TraitAliasExpansionInfo<'tcx> {
305-
fn new(trait_ref: ty::PolyTraitRef<'tcx>, span: Span) -> TraitAliasExpansionInfo<'tcx> {
306-
TraitAliasExpansionInfo {
310+
fn new(trait_ref: ty::PolyTraitRef<'tcx>, span: Span) -> Self {
311+
Self {
307312
items: smallvec![(trait_ref, span)]
308313
}
309314
}
310315

311-
fn push(&self, trait_ref: ty::PolyTraitRef<'tcx>, span: Span) -> TraitAliasExpansionInfo<'tcx> {
316+
fn push(&self, trait_ref: ty::PolyTraitRef<'tcx>, span: Span) -> Self {
312317
let mut items = self.items.clone();
313318
items.push((trait_ref, span));
314319

315-
TraitAliasExpansionInfo {
320+
Self {
316321
items
317322
}
318323
}
@@ -330,6 +335,8 @@ impl<'tcx> TraitAliasExpansionInfo<'tcx> {
330335
}
331336
}
332337

338+
/// Emits diagnostic information relating to the expansion of a trait via trait aliases
339+
/// (see [`TraitAliasExpansionInfo`]).
333340
pub trait TraitAliasExpansionInfoDignosticBuilder {
334341
fn label_with_exp_info<'tcx>(&mut self,
335342
info: &TraitAliasExpansionInfo<'tcx>,
@@ -365,24 +372,28 @@ pub fn expand_trait_aliases<'cx, 'gcx, 'tcx>(
365372

366373
impl<'cx, 'gcx, 'tcx> TraitAliasExpander<'cx, 'gcx, 'tcx> {
367374
/// 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
375+
/// to the definition, pushes the resulting expansion onto `self.stack`, and returns `false`.
376+
/// Otherwise, immediately returns `true` if `item` is a regular trait, or `false` if it is a
370377
/// trait alias.
371-
/// The return value indicates whether `item` should not be yielded to the user.
378+
/// The return value indicates whether `item` should be yielded to the user.
372379
fn push(&mut self, item: &TraitAliasExpansionInfo<'tcx>) -> bool {
373380
let tcx = self.visited.tcx;
374381
let trait_ref = item.trait_ref();
375382
let pred = trait_ref.to_predicate();
376383

377384
debug!("expand_trait_aliases: trait_ref={:?}", trait_ref);
378385

379-
self.visited.remove(&pred);
380-
386+
// Don't recurse unless this bound is a trait alias and isn't currently in the DFS stack of
387+
// already-visited predicates.
381388
let is_alias = tcx.is_trait_alias(trait_ref.def_id());
382389
if !is_alias || self.visited.contains(&pred) {
383390
return !is_alias;
384391
}
385392

393+
// Remove the current predicate from the stack of already-visited ones, since we're doing
394+
// a DFS.
395+
self.visited.remove(&pred);
396+
386397
// Get components of trait alias.
387398
let predicates = tcx.super_predicates_of(trait_ref.def_id());
388399

src/librustc_typeck/astconv.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -996,11 +996,12 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
996996
expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
997997
if regular_traits.len() > 1 {
998998
let extra_trait = &regular_traits[1];
999-
let mut err = struct_span_err!(tcx.sess, extra_trait.bottom().1, E0225,
1000-
"only auto traits can be used as additional traits in a trait object");
1001-
err.label_with_exp_info(extra_trait, "additional non-auto trait");
1002-
err.span_label(regular_traits[0].top().1, "first non-auto trait");
1003-
err.emit();
999+
struct_span_err!(tcx.sess, extra_trait.bottom().1, E0225,
1000+
"only auto traits can be used as additional traits in a trait object"
1001+
)
1002+
.label_with_exp_info(extra_trait, "additional non-auto trait")
1003+
.span_label(regular_traits[0].top().1, "first non-auto trait")
1004+
.emit();
10041005
}
10051006

10061007
if regular_traits.is_empty() && auto_traits.is_empty() {

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
trait Foo = std::io::Read + std::io::Write;
44

55
fn main() {
6-
let _: Box<std::io::Read + std::io::Write>;
6+
let _: Box<dyn std::io::Read + std::io::Write>;
77
//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
8-
let _: Box<Foo>;
8+
let _: Box<dyn Foo>;
99
//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
1010
}

src/test/ui/maybe-bounds.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
trait Tr: ?Sized {} //~ ERROR `?Trait` is not permitted in supertraits
22

3-
type A1 = Tr + (?Sized);
4-
type A2 = for<'a> Tr + (?Sized);
3+
type A1 = dyn Tr + (?Sized);
4+
type A2 = dyn for<'a> Tr + (?Sized);
55

66
fn main() {}
Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,29 @@
1+
// compile-pass
2+
13
// Test that `dyn ... + ?Sized + ...` resulting from the expansion of trait aliases is okay.
24

35
#![feature(trait_alias)]
46

7+
trait Foo {}
8+
59
trait S = ?Sized;
610

711
// Nest a couple of levels deep:
812
trait _0 = S;
913
trait _1 = _0;
1014

1115
// Straight list expansion:
12-
type _T0 = dyn _1;
13-
//~^ ERROR at least one non-builtin trait is required for an object type [E0224]
16+
type _T0 = dyn _1 + Foo;
1417

1518
// In second position:
16-
type _T1 = dyn Copy + _1;
19+
type _T1 = dyn Foo + _1;
1720

1821
// ... and with an auto trait:
19-
type _T2 = dyn Copy + Send + _1;
22+
type _T2 = dyn Foo + Send + _1;
2023

2124
// Twice:
2225
trait _2 = _1 + _1;
2326

24-
type _T3 = dyn _2;
25-
//~^ ERROR at least one non-builtin trait is required for an object type [E0224]
27+
type _T3 = dyn _2 + Foo;
2628

2729
fn main() {}

src/test/ui/traits/trait-alias/trait-alias-no-duplicates.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
use std::marker::Unpin;
88

9-
// Some arbitray object-safe trait:
9+
// Some arbitrary object-safe trait:
1010
trait Obj {}
1111

1212
// Nest a few levels deep:

src/test/ui/traits/trait-alias/trait-alias-no-extra-traits.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
use std::marker::Unpin;
77

8-
// Some arbitray object-safe traits:
8+
// Some arbitrary object-safe traits:
99
trait ObjA {}
1010
trait ObjB {}
1111

Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// run-pass
22

3-
// This test checks that trait objects involving trait aliases are well-formed.
3+
// This test hecks that trait objects involving trait aliases are well-formed.
44

55
#![feature(trait_alias)]
66

@@ -14,49 +14,61 @@ trait _1 = _0 + Send + Sync;
1414

1515
use std::marker::Unpin;
1616

17-
type _T01 = dyn _0;
18-
type _T02 = dyn _1;
19-
type _T03 = dyn Unpin + _1 + Send + Sync;
17+
fn _f0() {
18+
let _: Box<dyn _0>;
19+
let _: Box<dyn _1>;
20+
let _: Box<dyn Unpin + _1 + Send + Sync>;
21+
}
2022

2123
// Include object safe traits:
2224

23-
type _T10 = dyn Obj + _0;
24-
type _T11 = dyn Obj + _1;
25-
type _T12 = dyn Obj + _1 + _0;
25+
fn _f1() {
26+
let _: Box<dyn Obj + _0>;
27+
let _: Box<dyn Obj + _1>;
28+
let _: Box<dyn Obj + _1 + _0>;
29+
}
2630

2731
// And when the object safe trait is in a trait alias:
2832

2933
trait _2 = Obj;
3034

31-
type _T20 = dyn _2 + _0;
32-
type _T21 = dyn _2 + _1;
33-
type _T22 = dyn _2 + _1 + _0;
35+
fn _f2() {
36+
let _: Box<dyn _2 + _0>;
37+
let _: Box<dyn _2 + _1>;
38+
let _: Box<dyn _2 + _1 + _0>;
39+
}
3440

3541
// And it should also work when that trait is has auto traits to the right of it.
3642

3743
trait _3 = Obj + Unpin;
3844

39-
type _T30 = dyn _3 + _0;
40-
type _T31 = dyn _3 + _1;
41-
type _T32 = dyn _3 + _1 + _0;
45+
fn _f3() {
46+
let _: Box<dyn _3 + _0>;
47+
let _: Box<dyn _3 + _1>;
48+
let _: Box<dyn _3 + _1 + _0>;
49+
}
4250

4351
// Nest the trait deeply:
4452

4553
trait _4 = _3;
4654
trait _5 = _4 + Sync + _0 + Send;
4755
trait _6 = _5 + Send + _1 + Sync;
4856

49-
type _T60 = dyn _6 + _0;
50-
type _T61 = dyn _6 + _1;
51-
type _T62 = dyn _6 + _1 + _0;
57+
fn _f4() {
58+
let _: Box<dyn _6 + _0>;
59+
let _: Box<dyn _6 + _1>;
60+
let _: Box<dyn _6 + _1 + _0>;
61+
}
5262

5363
// Just nest the trait alone:
5464

5565
trait _7 = _2;
5666
trait _8 = _7;
5767
trait _9 = _8;
5868

59-
type _T9 = dyn _9;
69+
fn _f5() {
70+
let _: Box<dyn _9>;
71+
}
6072

6173
// First bound is auto trait:
6274

@@ -65,7 +77,9 @@ trait _11 = Obj + Send;
6577
trait _12 = Sync + _11;
6678
trait _13 = Send + _12;
6779

68-
type _T70 = dyn _0;
69-
type _T71 = dyn _3;
80+
fn f6() {
81+
let _: Box<dyn _10>;
82+
let _: Box<dyn _13>;
83+
}
7084

7185
fn main() {}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Test that `dyn ?Sized` (i.e., a trait object with only a maybe buond) is not allowed, when just
2+
// `?Sized` results from trait alias expansion.
3+
4+
#![feature(trait_alias)]
5+
6+
trait S = ?Sized;
7+
8+
// Nest a couple of levels deep:
9+
trait _0 = S;
10+
trait _1 = _0;
11+
12+
// Straight list expansion:
13+
type _T0 = dyn _1;
14+
//~^ ERROR at least one non-builtin trait is required for an object type [E0224]
15+
16+
// Twice:
17+
trait _2 = _1 + _1;
18+
19+
type _T1 = dyn _2;
20+
//~^ ERROR at least one non-builtin trait is required for an object type [E0224]
21+
22+
fn main() {}
Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
1-
// The purpose of this test is to demonstrate that `?Sized` is allowed in trait objects
2-
// (thought it has no effect).
1+
// compile-pass
32

4-
type _0 = dyn ?Sized;
5-
//~^ ERROR at least one non-builtin trait is required for an object type [E0224]
3+
// Test that `dyn ... + ?Sized + ...` is okay (though `?Sized` has no effect in trait objects).
64

7-
type _1 = dyn Clone + ?Sized;
5+
trait Foo {}
86

9-
type _2 = dyn Clone + ?Sized + ?Sized;
7+
type _0 = dyn ?Sized + Foo;
108

11-
type _3 = dyn ?Sized + Clone;
9+
type _1 = dyn Foo + ?Sized;
10+
11+
type _2 = dyn Foo + ?Sized + ?Sized;
12+
13+
type _3 = dyn ?Sized + Foo;
1214

1315
fn main() {}

src/test/ui/traits/wf-trait-object-no-duplicates.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// The purpose of this test is to demonstrate that duplicating object safe traits
22
// that are not auto-traits is rejected even though one could reasonably accept this.
33

4-
// Some arbitray object-safe trait:
4+
// Some arbitrary object-safe trait:
55
trait Obj {}
66

77
// Demonstrate that recursive expansion of trait aliases doesn't affect stable behavior:
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// Test that `dyn ?Sized` (i.e., a trait object with only a maybe buond) is not allowed.
2+
3+
type _0 = dyn ?Sized;
4+
//~^ ERROR at least one non-builtin trait is required for an object type [E0224]
5+
6+
fn main() {}
Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
// run-pass
22

3-
// Ensure that `dyn $($AutoTrait) + ObjSafe` is well-formed.
3+
// Ensure that `dyn $($AutoTrait)+ ObjSafe` is well-formed.
44

55
use std::marker::Unpin;
66

7-
// Some arbitray object-safe trait:
7+
// Some arbitrary object-safe trait:
88
trait Obj {}
99

10-
type _0 = Unpin;
11-
type _1 = Send + Obj;
12-
type _2 = Send + Unpin + Obj;
13-
type _3 = Send + Unpin + Sync + Obj;
10+
type _0 = dyn Unpin;
11+
type _1 = dyn Send + Obj;
12+
type _2 = dyn Send + Unpin + Obj;
13+
type _3 = dyn Send + Unpin + Sync + Obj;
1414

1515
fn main() {}

0 commit comments

Comments
 (0)