diff --git a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs index 703e0bdc40edb..9ccb462e6729a 100644 --- a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs +++ b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs @@ -1,7 +1,7 @@ use crate::astconv::{GenericArgCountMismatch, GenericArgCountResult, OnlySelfBounds}; use crate::bounds::Bounds; use crate::errors::TraitObjectDeclaredWithNoTraits; -use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; +use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; @@ -83,7 +83,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let expanded_traits = traits::expand_trait_aliases(tcx, trait_bounds.iter().map(|&(a, b)| (a, b))); - let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) = expanded_traits + let (auto_traits, regular_traits): (Vec<_>, Vec<_>) = expanded_traits .filter(|i| i.trait_ref().self_ty().skip_binder() == dummy_self) .partition(|i| tcx.trait_is_auto(i.trait_ref().def_id())); if regular_traits.len() > 1 { @@ -238,14 +238,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { hir_trait_bounds, ); - // De-duplicate auto traits so that, e.g., `dyn Trait + Send + Send` is the same as - // `dyn Trait + Send`. - // We remove duplicates by inserting into a `FxHashSet` to avoid re-ordering - // the bounds - let mut duplicates = FxHashSet::default(); - auto_traits.retain(|i| duplicates.insert(i.trait_ref().def_id())); - debug!("regular_traits: {:?}", regular_traits); - debug!("auto_traits: {:?}", auto_traits); + let auto_traits: FxIndexSet = auto_traits + .into_iter() + .map(|info| info.trait_ref().def_id()) + .chain(regular_traits.iter().flat_map(|info| { + traits::supertrait_def_ids(tcx, info.trait_ref().def_id()) + .filter(|def_id| tcx.trait_is_auto(*def_id)) + })) + .collect(); // Erase the `dummy_self` (`trait_object_dummy_self`) used above. let existential_trait_refs = regular_traits.iter().map(|i| { @@ -351,9 +351,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let regular_trait_predicates = existential_trait_refs .map(|trait_ref| trait_ref.map_bound(ty::ExistentialPredicate::Trait)); - let auto_trait_predicates = auto_traits.into_iter().map(|trait_ref| { - ty::Binder::dummy(ty::ExistentialPredicate::AutoTrait(trait_ref.trait_ref().def_id())) - }); + let auto_trait_predicates = auto_traits + .into_iter() + .map(|def_id| ty::Binder::dummy(ty::ExistentialPredicate::AutoTrait(def_id))); // N.b. principal, projections, auto traits // FIXME: This is actually wrong with multiple principals in regards to symbol mangling let mut v = regular_trait_predicates diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index a10bdc6012c07..d6fbbbb9b22ea 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1293,6 +1293,19 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { // FIXME(eddyb) avoid printing twice (needed to ensure // that the auto traits are sorted *and* printed via cx). let mut auto_traits: Vec<_> = predicates.auto_traits().collect(); + let principal_super_traits: FxHashSet<_> = predicates + .principal() + .into_iter() + .flat_map(|principal| { + supertraits_for_pretty_printing( + self.tcx(), + principal.with_self_ty(self.tcx(), self.tcx().types.trait_object_dummy_self), + ) + .map(|trait_ref| trait_ref.def_id()) + }) + .collect(); + + auto_traits.retain(|def_id| !principal_super_traits.contains(def_id)); // The auto traits come ordered by `DefPathHash`. While // `DefPathHash` is *stable* in the sense that it depends on diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index caf9470b4c646..7a827fd263343 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -853,6 +853,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { let principal_trait_ref = principal.with_self_ty(tcx, self_ty); self.walk_vtable(principal_trait_ref, |ecx, assumption, vtable_base, _| { match G::consider_object_bound_candidate(ecx, goal, assumption.to_predicate(tcx)) { + // FIXME: We could skip auto traits here, since they're eagerly elaborated in + // . Ok(result) => candidates.push(Candidate { source: CandidateSource::BuiltinImpl(BuiltinImplSource::Object { vtable_base, diff --git a/tests/ui/coherence/coherence-impl-trait-for-marker-trait-negative.rs b/tests/ui/coherence/coherence-impl-trait-for-marker-trait-negative.rs index 98f1558b7ffe1..a1c027b8b8262 100644 --- a/tests/ui/coherence/coherence-impl-trait-for-marker-trait-negative.rs +++ b/tests/ui/coherence/coherence-impl-trait-for-marker-trait-negative.rs @@ -12,8 +12,11 @@ auto trait Marker2 {} trait Object: Marker1 {} // A supertrait marker is illegal... -impl !Marker1 for dyn Object + Marker2 {} //~ ERROR E0371 - //~^ ERROR 0321 +impl !Marker1 for dyn Object + Marker2 {} +//~^ ERROR E0371 +//~| ERROR E0321 +//~| ERROR E0371 + // ...and also a direct component. impl !Marker2 for dyn Object + Marker2 {} //~ ERROR E0371 //~^ ERROR 0321 diff --git a/tests/ui/coherence/coherence-impl-trait-for-marker-trait-negative.stderr b/tests/ui/coherence/coherence-impl-trait-for-marker-trait-negative.stderr index ea38afc40ce80..90c30b5e19b2f 100644 --- a/tests/ui/coherence/coherence-impl-trait-for-marker-trait-negative.stderr +++ b/tests/ui/coherence/coherence-impl-trait-for-marker-trait-negative.stderr @@ -4,6 +4,14 @@ error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically i LL | impl !Marker1 for dyn Object + Marker2 {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker1` +error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker1` + --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:15:1 + | +LL | impl !Marker1 for dyn Object + Marker2 {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker1` + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + error[E0321]: traits with a default impl, like `Marker1`, cannot be implemented for trait object `(dyn Object + Marker2 + 'static)` --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:15:1 | @@ -13,13 +21,13 @@ LL | impl !Marker1 for dyn Object + Marker2 {} = note: a trait object implements `Marker1` if and only if `Marker1` is one of the trait object's trait bounds error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker2` - --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:18:1 + --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:21:1 | LL | impl !Marker2 for dyn Object + Marker2 {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker2` error[E0321]: traits with a default impl, like `Marker2`, cannot be implemented for trait object `(dyn Object + Marker2 + 'static)` - --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:18:1 + --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:21:1 | LL | impl !Marker2 for dyn Object + Marker2 {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -27,7 +35,7 @@ LL | impl !Marker2 for dyn Object + Marker2 {} = note: a trait object implements `Marker2` if and only if `Marker2` is one of the trait object's trait bounds error[E0321]: traits with a default impl, like `Marker2`, cannot be implemented for trait object `(dyn Object + 'static)` - --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:26:1 + --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:29:1 | LL | impl !Marker2 for dyn Object {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -35,7 +43,7 @@ LL | impl !Marker2 for dyn Object {} = note: a trait object implements `Marker2` if and only if `Marker2` is one of the trait object's trait bounds error[E0117]: only traits defined in the current crate can be implemented for arbitrary types - --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:22:1 + --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:25:1 | LL | impl !Send for dyn Marker2 {} | ^^^^^^^^^^^^^^^----------- @@ -46,26 +54,26 @@ LL | impl !Send for dyn Marker2 {} = note: define and implement a trait or new type instead error[E0321]: cross-crate traits with a default impl, like `Send`, can only be implemented for a struct/enum type, not `(dyn Object + 'static)` - --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:27:1 + --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:30:1 | LL | impl !Send for dyn Object {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type 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)` - --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:28:1 + --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:31:1 | LL | impl !Send for dyn Object + Marker2 {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type error[E0321]: traits with a default impl, like `Marker3`, cannot be implemented for generic type `T` - --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:32:1 + --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:35:1 | LL | impl !Marker3 for T {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: a trait object implements `Marker3` if and only if `Marker3` is one of the trait object's trait bounds -error: aborting due to 9 previous errors +error: aborting due to 10 previous errors Some errors have detailed explanations: E0117, E0321, E0371. For more information about an error, try `rustc --explain E0117`. diff --git a/tests/ui/coherence/coherence-impl-trait-for-marker-trait-positive.rs b/tests/ui/coherence/coherence-impl-trait-for-marker-trait-positive.rs index db2e2b4509a2a..89ccfdb0c54d1 100644 --- a/tests/ui/coherence/coherence-impl-trait-for-marker-trait-positive.rs +++ b/tests/ui/coherence/coherence-impl-trait-for-marker-trait-positive.rs @@ -12,8 +12,10 @@ auto trait Marker2 {} trait Object: Marker1 {} // A supertrait marker is illegal... -impl Marker1 for dyn Object + Marker2 {} //~ ERROR E0371 - //~^ ERROR E0321 +impl Marker1 for dyn Object + Marker2 {} +//~^ ERROR E0371 +//~| ERROR E0321 +//~| ERROR E0371 // ...and also a direct component. impl Marker2 for dyn Object + Marker2 {} //~ ERROR E0371 //~^ ERROR E0321 diff --git a/tests/ui/coherence/coherence-impl-trait-for-marker-trait-positive.stderr b/tests/ui/coherence/coherence-impl-trait-for-marker-trait-positive.stderr index 2a8713bc32794..6f17be6880f25 100644 --- a/tests/ui/coherence/coherence-impl-trait-for-marker-trait-positive.stderr +++ b/tests/ui/coherence/coherence-impl-trait-for-marker-trait-positive.stderr @@ -4,6 +4,14 @@ error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically i LL | impl Marker1 for dyn Object + Marker2 {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker1` +error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker1` + --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:15:1 + | +LL | impl Marker1 for dyn Object + Marker2 {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker1` + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + error[E0321]: traits with a default impl, like `Marker1`, cannot be implemented for trait object `(dyn Object + Marker2 + 'static)` --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:15:1 | @@ -13,13 +21,13 @@ LL | impl Marker1 for dyn Object + Marker2 {} = note: a trait object implements `Marker1` if and only if `Marker1` is one of the trait object's trait bounds error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker2` - --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:18:1 + --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:20:1 | LL | impl Marker2 for dyn Object + Marker2 {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker2` error[E0321]: traits with a default impl, like `Marker2`, cannot be implemented for trait object `(dyn Object + Marker2 + 'static)` - --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:18:1 + --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:20:1 | LL | impl Marker2 for dyn Object + Marker2 {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -27,7 +35,7 @@ LL | impl Marker2 for dyn Object + Marker2 {} = note: a trait object implements `Marker2` if and only if `Marker2` is one of the trait object's trait bounds error[E0321]: traits with a default impl, like `Marker2`, cannot be implemented for trait object `(dyn Object + 'static)` - --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:26:1 + --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:28:1 | LL | impl Marker2 for dyn Object {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -35,7 +43,7 @@ LL | impl Marker2 for dyn Object {} = note: a trait object implements `Marker2` if and only if `Marker2` is one of the trait object's trait bounds error[E0117]: only traits defined in the current crate can be implemented for arbitrary types - --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:22:1 + --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:24:1 | LL | unsafe impl Send for dyn Marker2 {} | ^^^^^^^^^^^^^^^^^^^^^----------- @@ -46,26 +54,26 @@ LL | unsafe impl Send for dyn Marker2 {} = note: define and implement a trait or new type instead error[E0321]: cross-crate traits with a default impl, like `Send`, can only be implemented for a struct/enum type, not `(dyn Object + 'static)` - --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:27:1 + --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:29:1 | LL | unsafe impl Send for dyn Object {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type 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)` - --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:28:1 + --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:30:1 | LL | unsafe impl Send for dyn Object + Marker2 {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type error[E0321]: traits with a default impl, like `Marker3`, cannot be implemented for generic type `T` - --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:32:1 + --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:34:1 | LL | impl Marker3 for T {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: a trait object implements `Marker3` if and only if `Marker3` is one of the trait object's trait bounds -error: aborting due to 9 previous errors +error: aborting due to 10 previous errors Some errors have detailed explanations: E0117, E0321, E0371. For more information about an error, try `rustc --explain E0117`. diff --git a/tests/ui/traits/object/coherence-with-implied-auto-traits.rs b/tests/ui/traits/object/coherence-with-implied-auto-traits.rs new file mode 100644 index 0000000000000..52cf27aca6d12 --- /dev/null +++ b/tests/ui/traits/object/coherence-with-implied-auto-traits.rs @@ -0,0 +1,9 @@ +trait Foo: Send {} + +trait Bar {} + +impl Bar for dyn Foo {} +impl Bar for dyn Foo + Send {} +//~^ ERROR conflicting implementations of trait `Bar` for type `(dyn Foo + 'static)` + +fn main() {} diff --git a/tests/ui/traits/object/coherence-with-implied-auto-traits.stderr b/tests/ui/traits/object/coherence-with-implied-auto-traits.stderr new file mode 100644 index 0000000000000..f874252d51e41 --- /dev/null +++ b/tests/ui/traits/object/coherence-with-implied-auto-traits.stderr @@ -0,0 +1,11 @@ +error[E0119]: conflicting implementations of trait `Bar` for type `(dyn Foo + 'static)` + --> $DIR/coherence-with-implied-auto-traits.rs:6:1 + | +LL | impl Bar for dyn Foo {} + | -------------------- first implementation here +LL | impl Bar for dyn Foo + Send {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Foo + 'static)` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/traits/object/upcasting-with-implied-auto-traits.rs b/tests/ui/traits/object/upcasting-with-implied-auto-traits.rs new file mode 100644 index 0000000000000..9db985237124e --- /dev/null +++ b/tests/ui/traits/object/upcasting-with-implied-auto-traits.rs @@ -0,0 +1,13 @@ +// check-pass +// revisions: current next +//[next] compile-flags: -Znext-solver + +trait Target {} +trait Source: Send + Target {} + +fn upcast(x: &dyn Source) -> &(dyn Target + Send) { x } + +fn same(x: &dyn Source) -> &(dyn Source + Send) { x } +// ^ This isn't upcasting, just passing dyn through unchanged. + +fn main() {}