Skip to content

Commit 925e66e

Browse files
committed
Auto merge of rust-lang#119825 - compiler-errors:elaborate-dyn, r=<try>
Eagerly elaborate auto-trait supertraits into `dyn Trait` When we have a trait like: ``` trait Foo: Send {} ``` Then the `dyn Foo` type is elaborated to include `Send` as part of its auto-traits list. That means it is the *same* type as `dyn Foo + Send`. ## Why? When a auto trait is implied as part of the supertraits of the trait object's principal, the user should *never* care about whether they explicitly write `+ AutoTrait` or have it implied from the supertrait bounds. This PR removes this subtle distinction. IMO, It *never* makes sense for `dyn Foo` to be a distinct type from `dyn Foo + Send`, since both implement `Send`, just via different code paths in the trait solver. --- Alternative approach to rust-lang#119338. r? lcnr
2 parents e927184 + dca631c commit 925e66e

10 files changed

+102
-33
lines changed

compiler/rustc_hir_analysis/src/astconv/object_safety.rs

+13-13
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::astconv::{GenericArgCountMismatch, GenericArgCountResult, OnlySelfBounds};
22
use crate::bounds::Bounds;
33
use crate::errors::TraitObjectDeclaredWithNoTraits;
4-
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
4+
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
55
use rustc_errors::struct_span_err;
66
use rustc_hir as hir;
77
use rustc_hir::def::{DefKind, Res};
@@ -83,7 +83,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
8383
let expanded_traits =
8484
traits::expand_trait_aliases(tcx, trait_bounds.iter().map(|&(a, b)| (a, b)));
8585

86-
let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) = expanded_traits
86+
let (auto_traits, regular_traits): (Vec<_>, Vec<_>) = expanded_traits
8787
.filter(|i| i.trait_ref().self_ty().skip_binder() == dummy_self)
8888
.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
8989
if regular_traits.len() > 1 {
@@ -238,14 +238,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
238238
hir_trait_bounds,
239239
);
240240

241-
// De-duplicate auto traits so that, e.g., `dyn Trait + Send + Send` is the same as
242-
// `dyn Trait + Send`.
243-
// We remove duplicates by inserting into a `FxHashSet` to avoid re-ordering
244-
// the bounds
245-
let mut duplicates = FxHashSet::default();
246-
auto_traits.retain(|i| duplicates.insert(i.trait_ref().def_id()));
247-
debug!("regular_traits: {:?}", regular_traits);
248-
debug!("auto_traits: {:?}", auto_traits);
241+
let auto_traits: FxIndexSet<DefId> = auto_traits
242+
.into_iter()
243+
.map(|info| info.trait_ref().def_id())
244+
.chain(regular_traits.iter().flat_map(|info| {
245+
traits::supertrait_def_ids(tcx, info.trait_ref().def_id())
246+
.filter(|def_id| tcx.trait_is_auto(*def_id))
247+
}))
248+
.collect();
249249

250250
// Erase the `dummy_self` (`trait_object_dummy_self`) used above.
251251
let existential_trait_refs = regular_traits.iter().map(|i| {
@@ -351,9 +351,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
351351

352352
let regular_trait_predicates = existential_trait_refs
353353
.map(|trait_ref| trait_ref.map_bound(ty::ExistentialPredicate::Trait));
354-
let auto_trait_predicates = auto_traits.into_iter().map(|trait_ref| {
355-
ty::Binder::dummy(ty::ExistentialPredicate::AutoTrait(trait_ref.trait_ref().def_id()))
356-
});
354+
let auto_trait_predicates = auto_traits
355+
.into_iter()
356+
.map(|def_id| ty::Binder::dummy(ty::ExistentialPredicate::AutoTrait(def_id)));
357357
// N.b. principal, projections, auto traits
358358
// FIXME: This is actually wrong with multiple principals in regards to symbol mangling
359359
let mut v = regular_trait_predicates

compiler/rustc_middle/src/ty/print/pretty.rs

+13
Original file line numberDiff line numberDiff line change
@@ -1293,6 +1293,19 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
12931293
// FIXME(eddyb) avoid printing twice (needed to ensure
12941294
// that the auto traits are sorted *and* printed via cx).
12951295
let mut auto_traits: Vec<_> = predicates.auto_traits().collect();
1296+
let principal_super_traits: FxHashSet<_> = predicates
1297+
.principal()
1298+
.into_iter()
1299+
.flat_map(|principal| {
1300+
supertraits_for_pretty_printing(
1301+
self.tcx(),
1302+
principal.with_self_ty(self.tcx(), self.tcx().types.trait_object_dummy_self),
1303+
)
1304+
.map(|trait_ref| trait_ref.def_id())
1305+
})
1306+
.collect();
1307+
1308+
auto_traits.retain(|def_id| !principal_super_traits.contains(def_id));
12961309

12971310
// The auto traits come ordered by `DefPathHash`. While
12981311
// `DefPathHash` is *stable* in the sense that it depends on

compiler/rustc_trait_selection/src/solve/assembly/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -853,6 +853,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
853853
let principal_trait_ref = principal.with_self_ty(tcx, self_ty);
854854
self.walk_vtable(principal_trait_ref, |ecx, assumption, vtable_base, _| {
855855
match G::consider_object_bound_candidate(ecx, goal, assumption.to_predicate(tcx)) {
856+
// FIXME: We could skip auto traits here, since they're eagerly elaborated in
857+
// <https://github.com/rust-lang/rust/pull/119825>.
856858
Ok(result) => candidates.push(Candidate {
857859
source: CandidateSource::BuiltinImpl(BuiltinImplSource::Object {
858860
vtable_base,

tests/ui/coherence/coherence-impl-trait-for-marker-trait-negative.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,11 @@ auto trait Marker2 {}
1212
trait Object: Marker1 {}
1313

1414
// A supertrait marker is illegal...
15-
impl !Marker1 for dyn Object + Marker2 {} //~ ERROR E0371
16-
//~^ ERROR 0321
15+
impl !Marker1 for dyn Object + Marker2 {}
16+
//~^ ERROR E0371
17+
//~| ERROR E0321
18+
//~| ERROR E0371
19+
1720
// ...and also a direct component.
1821
impl !Marker2 for dyn Object + Marker2 {} //~ ERROR E0371
1922
//~^ ERROR 0321

tests/ui/coherence/coherence-impl-trait-for-marker-trait-negative.stderr

+16-8
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@ error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically i
44
LL | impl !Marker1 for dyn Object + Marker2 {}
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker1`
66

7+
error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker1`
8+
--> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:15:1
9+
|
10+
LL | impl !Marker1 for dyn Object + Marker2 {}
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker1`
12+
|
13+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
14+
715
error[E0321]: traits with a default impl, like `Marker1`, cannot be implemented for trait object `(dyn Object + Marker2 + 'static)`
816
--> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:15:1
917
|
@@ -13,29 +21,29 @@ LL | impl !Marker1 for dyn Object + Marker2 {}
1321
= note: a trait object implements `Marker1` if and only if `Marker1` is one of the trait object's trait bounds
1422

1523
error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker2`
16-
--> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:18:1
24+
--> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:21:1
1725
|
1826
LL | impl !Marker2 for dyn Object + Marker2 {}
1927
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker2`
2028

2129
error[E0321]: traits with a default impl, like `Marker2`, cannot be implemented for trait object `(dyn Object + Marker2 + 'static)`
22-
--> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:18:1
30+
--> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:21:1
2331
|
2432
LL | impl !Marker2 for dyn Object + Marker2 {}
2533
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2634
|
2735
= note: a trait object implements `Marker2` if and only if `Marker2` is one of the trait object's trait bounds
2836

2937
error[E0321]: traits with a default impl, like `Marker2`, cannot be implemented for trait object `(dyn Object + 'static)`
30-
--> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:26:1
38+
--> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:29:1
3139
|
3240
LL | impl !Marker2 for dyn Object {}
3341
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3442
|
3543
= note: a trait object implements `Marker2` if and only if `Marker2` is one of the trait object's trait bounds
3644

3745
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
38-
--> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:22:1
46+
--> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:25:1
3947
|
4048
LL | impl !Send for dyn Marker2 {}
4149
| ^^^^^^^^^^^^^^^-----------
@@ -46,26 +54,26 @@ LL | impl !Send for dyn Marker2 {}
4654
= note: define and implement a trait or new type instead
4755

4856
error[E0321]: cross-crate traits with a default impl, like `Send`, can only be implemented for a struct/enum type, not `(dyn Object + 'static)`
49-
--> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:27:1
57+
--> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:30:1
5058
|
5159
LL | impl !Send for dyn Object {}
5260
| ^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type
5361

5462
error[E0321]: cross-crate traits with a default impl, like `Send`, can only be implemented for a struct/enum type, not `(dyn Object + Marker2 + 'static)`
55-
--> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:28:1
63+
--> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:31:1
5664
|
5765
LL | impl !Send for dyn Object + Marker2 {}
5866
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type
5967

6068
error[E0321]: traits with a default impl, like `Marker3`, cannot be implemented for generic type `T`
61-
--> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:32:1
69+
--> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:35:1
6270
|
6371
LL | impl<T: ?Sized> !Marker3 for T {}
6472
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6573
|
6674
= note: a trait object implements `Marker3` if and only if `Marker3` is one of the trait object's trait bounds
6775

68-
error: aborting due to 9 previous errors
76+
error: aborting due to 10 previous errors
6977

7078
Some errors have detailed explanations: E0117, E0321, E0371.
7179
For more information about an error, try `rustc --explain E0117`.

tests/ui/coherence/coherence-impl-trait-for-marker-trait-positive.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@ auto trait Marker2 {}
1212
trait Object: Marker1 {}
1313

1414
// A supertrait marker is illegal...
15-
impl Marker1 for dyn Object + Marker2 {} //~ ERROR E0371
16-
//~^ ERROR E0321
15+
impl Marker1 for dyn Object + Marker2 {}
16+
//~^ ERROR E0371
17+
//~| ERROR E0321
18+
//~| ERROR E0371
1719
// ...and also a direct component.
1820
impl Marker2 for dyn Object + Marker2 {} //~ ERROR E0371
1921
//~^ ERROR E0321

tests/ui/coherence/coherence-impl-trait-for-marker-trait-positive.stderr

+16-8
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@ error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically i
44
LL | impl Marker1 for dyn Object + Marker2 {}
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker1`
66

7+
error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker1`
8+
--> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:15:1
9+
|
10+
LL | impl Marker1 for dyn Object + Marker2 {}
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker1`
12+
|
13+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
14+
715
error[E0321]: traits with a default impl, like `Marker1`, cannot be implemented for trait object `(dyn Object + Marker2 + 'static)`
816
--> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:15:1
917
|
@@ -13,29 +21,29 @@ LL | impl Marker1 for dyn Object + Marker2 {}
1321
= note: a trait object implements `Marker1` if and only if `Marker1` is one of the trait object's trait bounds
1422

1523
error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker2`
16-
--> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:18:1
24+
--> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:20:1
1725
|
1826
LL | impl Marker2 for dyn Object + Marker2 {}
1927
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker2`
2028

2129
error[E0321]: traits with a default impl, like `Marker2`, cannot be implemented for trait object `(dyn Object + Marker2 + 'static)`
22-
--> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:18:1
30+
--> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:20:1
2331
|
2432
LL | impl Marker2 for dyn Object + Marker2 {}
2533
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2634
|
2735
= note: a trait object implements `Marker2` if and only if `Marker2` is one of the trait object's trait bounds
2836

2937
error[E0321]: traits with a default impl, like `Marker2`, cannot be implemented for trait object `(dyn Object + 'static)`
30-
--> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:26:1
38+
--> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:28:1
3139
|
3240
LL | impl Marker2 for dyn Object {}
3341
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
3442
|
3543
= note: a trait object implements `Marker2` if and only if `Marker2` is one of the trait object's trait bounds
3644

3745
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
38-
--> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:22:1
46+
--> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:24:1
3947
|
4048
LL | unsafe impl Send for dyn Marker2 {}
4149
| ^^^^^^^^^^^^^^^^^^^^^-----------
@@ -46,26 +54,26 @@ LL | unsafe impl Send for dyn Marker2 {}
4654
= note: define and implement a trait or new type instead
4755

4856
error[E0321]: cross-crate traits with a default impl, like `Send`, can only be implemented for a struct/enum type, not `(dyn Object + 'static)`
49-
--> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:27:1
57+
--> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:29:1
5058
|
5159
LL | unsafe impl Send for dyn Object {}
5260
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type
5361

5462
error[E0321]: cross-crate traits with a default impl, like `Send`, can only be implemented for a struct/enum type, not `(dyn Object + Marker2 + 'static)`
55-
--> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:28:1
63+
--> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:30:1
5664
|
5765
LL | unsafe impl Send for dyn Object + Marker2 {}
5866
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type
5967

6068
error[E0321]: traits with a default impl, like `Marker3`, cannot be implemented for generic type `T`
61-
--> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:32:1
69+
--> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:34:1
6270
|
6371
LL | impl<T: ?Sized> Marker3 for T {}
6472
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6573
|
6674
= note: a trait object implements `Marker3` if and only if `Marker3` is one of the trait object's trait bounds
6775

68-
error: aborting due to 9 previous errors
76+
error: aborting due to 10 previous errors
6977

7078
Some errors have detailed explanations: E0117, E0321, E0371.
7179
For more information about an error, try `rustc --explain E0117`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
trait Foo: Send {}
2+
3+
trait Bar {}
4+
5+
impl Bar for dyn Foo {}
6+
impl Bar for dyn Foo + Send {}
7+
//~^ ERROR conflicting implementations of trait `Bar` for type `(dyn Foo + 'static)`
8+
9+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0119]: conflicting implementations of trait `Bar` for type `(dyn Foo + 'static)`
2+
--> $DIR/coherence-with-implied-auto-traits.rs:6:1
3+
|
4+
LL | impl Bar for dyn Foo {}
5+
| -------------------- first implementation here
6+
LL | impl Bar for dyn Foo + Send {}
7+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Foo + 'static)`
8+
9+
error: aborting due to 1 previous error
10+
11+
For more information about this error, try `rustc --explain E0119`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// check-pass
2+
// revisions: current next
3+
//[next] compile-flags: -Znext-solver
4+
5+
trait Target {}
6+
trait Source: Send + Target {}
7+
8+
fn upcast(x: &dyn Source) -> &(dyn Target + Send) { x }
9+
10+
fn same(x: &dyn Source) -> &(dyn Source + Send) { x }
11+
// ^ This isn't upcasting, just passing dyn through unchanged.
12+
13+
fn main() {}

0 commit comments

Comments
 (0)