From 28f1c436dcae005fa2d976e5763fb6eae548ef90 Mon Sep 17 00:00:00 2001 From: Ada Bohm Date: Wed, 8 Apr 2026 17:12:50 +0200 Subject: [PATCH 1/2] Error on projection of dyn noncompat type in old trait solver --- .../src/traits/project.rs | 6 +++++ ...ch-dyn-incompatible-that-does-not-deref.rs | 2 +- ...yn-incompatible-that-does-not-deref.stderr | 19 ++++----------- .../ui/traits/ice-with-dyn-pointee-errors.rs | 3 ++- .../traits/ice-with-dyn-pointee-errors.stderr | 23 ++++++++++++++++--- 5 files changed, 34 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index e2257703f5775..181bbe40ff256 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -856,6 +856,12 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>( } _ => return, }; + + // Projecting `dyn Trait` is only valid when `Trait` is dyn-compatible. + if data.principal_def_id().is_some_and(|def_id| !tcx.is_dyn_compatible(def_id)) { + return; + } + let env_predicates = data .projection_bounds() .filter(|bound| bound.item_def_id() == obligation.predicate.expect_projection_def_id()) diff --git a/tests/ui/self/dispatch-dyn-incompatible-that-does-not-deref.rs b/tests/ui/self/dispatch-dyn-incompatible-that-does-not-deref.rs index af35d1e0359db..40c1e07a70073 100644 --- a/tests/ui/self/dispatch-dyn-incompatible-that-does-not-deref.rs +++ b/tests/ui/self/dispatch-dyn-incompatible-that-does-not-deref.rs @@ -12,7 +12,7 @@ trait Foo: Deref { fn test(x: &dyn Foo) { //~^ ERROR the trait `Foo` is not dyn compatible x.method(); - //~^ ERROR the trait `Foo` is not dyn compatible + //~^ ERROR no method named `method` found for reference `&dyn Foo` } fn main() {} diff --git a/tests/ui/self/dispatch-dyn-incompatible-that-does-not-deref.stderr b/tests/ui/self/dispatch-dyn-incompatible-that-does-not-deref.stderr index 237bbc5671515..bb071ad87195f 100644 --- a/tests/ui/self/dispatch-dyn-incompatible-that-does-not-deref.stderr +++ b/tests/ui/self/dispatch-dyn-incompatible-that-does-not-deref.stderr @@ -25,25 +25,16 @@ LL | fn method(self: &W) {} = note: type of `self` must be `Self` or a type that dereferences to it = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) -error[E0038]: the trait `Foo` is not dyn compatible - --> $DIR/dispatch-dyn-incompatible-that-does-not-deref.rs:14:5 +error[E0599]: no method named `method` found for reference `&dyn Foo` in the current scope + --> $DIR/dispatch-dyn-incompatible-that-does-not-deref.rs:14:7 | LL | fn method(self: &W) {} - | -- help: consider changing method `method`'s `self` parameter to be `&self`: `&Self` + | -- the method might not be found because of this arbitrary self type ... LL | x.method(); - | ^^^^^^^^^^ `Foo` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/dispatch-dyn-incompatible-that-does-not-deref.rs:8:21 - | -LL | trait Foo: Deref { - | --- this trait is not dyn compatible... -LL | fn method(self: &W) {} - | ^^ ...because method `method`'s `self` parameter cannot be dispatched on + | ^^^^^^ method not found in `&dyn Foo` error: aborting due to 3 previous errors -Some errors have detailed explanations: E0038, E0307. +Some errors have detailed explanations: E0038, E0307, E0599. For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/traits/ice-with-dyn-pointee-errors.rs b/tests/ui/traits/ice-with-dyn-pointee-errors.rs index bb89f103e3f95..4c2b775f25c9a 100644 --- a/tests/ui/traits/ice-with-dyn-pointee-errors.rs +++ b/tests/ui/traits/ice-with-dyn-pointee-errors.rs @@ -8,7 +8,8 @@ fn unknown_sized_object_ptr_in(_: &(impl Pointee + ?Sized)) {} fn raw_pointer_in(x: &dyn Pointee) { //~^ ERROR the trait `Pointee` is not dyn compatible unknown_sized_object_ptr_in(x) - //~^ ERROR the trait `Pointee` is not dyn compatible + //~^ ERROR type mismatch resolving ` as Pointee>::Metadata == ()` + //~| ERROR the trait `Pointee` is not dyn compatible } fn main() { diff --git a/tests/ui/traits/ice-with-dyn-pointee-errors.stderr b/tests/ui/traits/ice-with-dyn-pointee-errors.stderr index 9ff0445cda09b..b6eee86bdef2e 100644 --- a/tests/ui/traits/ice-with-dyn-pointee-errors.stderr +++ b/tests/ui/traits/ice-with-dyn-pointee-errors.stderr @@ -10,6 +10,22 @@ note: for a trait to be dyn compatible it needs to allow building a vtable | = note: the trait is not dyn compatible because it opted out of dyn-compatibility +error[E0271]: type mismatch resolving ` as Pointee>::Metadata == ()` + --> $DIR/ice-with-dyn-pointee-errors.rs:10:33 + | +LL | unknown_sized_object_ptr_in(x) + | --------------------------- ^ expected `()`, found `DynMetadata>` + | | + | required by a bound introduced by this call + | + = note: expected unit type `()` + found struct `DynMetadata>` +note: required by a bound in `unknown_sized_object_ptr_in` + --> $DIR/ice-with-dyn-pointee-errors.rs:6:50 + | +LL | fn unknown_sized_object_ptr_in(_: &(impl Pointee + ?Sized)) {} + | ^^^^^^^^^^^^^ required by this bound in `unknown_sized_object_ptr_in` + error[E0038]: the trait `Pointee` is not dyn compatible --> $DIR/ice-with-dyn-pointee-errors.rs:10:5 | @@ -23,7 +39,7 @@ note: for a trait to be dyn compatible it needs to allow building a vtable = note: the trait is not dyn compatible because it opted out of dyn-compatibility error[E0038]: the trait `Pointee` is not dyn compatible - --> $DIR/ice-with-dyn-pointee-errors.rs:15:20 + --> $DIR/ice-with-dyn-pointee-errors.rs:16:20 | LL | raw_pointer_in(&42) | ^^^ `Pointee` is not dyn compatible @@ -34,6 +50,7 @@ note: for a trait to be dyn compatible it needs to allow building a vtable | = note: the trait is not dyn compatible because it opted out of dyn-compatibility -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0038`. +Some errors have detailed explanations: E0038, E0271. +For more information about an error, try `rustc --explain E0038`. From 2ffefb5e05dee46d91597441cd0a67b5a9195a52 Mon Sep 17 00:00:00 2001 From: Ada Bohm Date: Mon, 29 Jun 2026 12:02:50 +0200 Subject: [PATCH 2/2] Reduce number of error messages --- .../src/traits/project.rs | 35 ++++++++++++++++--- ...ch-dyn-incompatible-that-does-not-deref.rs | 1 - ...yn-incompatible-that-does-not-deref.stderr | 13 ++----- .../ui/traits/ice-with-dyn-pointee-errors.rs | 2 +- .../traits/ice-with-dyn-pointee-errors.stderr | 21 +++++------ .../traits/object/dyn-proj-non-dyn-compat.rs | 20 +++++++++++ .../object/dyn-proj-non-dyn-compat.stderr | 21 +++++++++++ .../dyn-type-param-bound-not-checked.rs | 13 +++++++ 8 files changed, 95 insertions(+), 31 deletions(-) create mode 100644 tests/ui/traits/object/dyn-proj-non-dyn-compat.rs create mode 100644 tests/ui/traits/object/dyn-proj-non-dyn-compat.stderr create mode 100644 tests/ui/traits/object/dyn-type-param-bound-not-checked.rs diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 181bbe40ff256..a0bab2b2a987d 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -26,6 +26,7 @@ use super::{ SelectionError, specialization_graph, translate_args, util, }; use crate::diagnostics::InherentProjectionNormalizationOverflow; +use crate::error_reporting::traits::report_dyn_incompatibility; use crate::infer::{BoundRegionConversionTime, InferOk}; use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to}; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; @@ -712,6 +713,35 @@ fn project<'cx, 'tcx>( ))); } + // `::Name` is only valid when `Trait` is dyn-compatible. + // If it isn't, create an error at the projection site and return a tainted error term. + let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty()); + if let ty::Dynamic(data, ..) = self_ty.kind() { + if let Some(def_id) = data.principal_def_id() { + let tcx = selcx.tcx(); + if !tcx.is_dyn_compatible(def_id) { + let span = obligation.cause.span; + let guar = if !span.is_dummy() { + let violations = tcx.dyn_compatibility_violations(def_id); + report_dyn_incompatibility(tcx, span, None, def_id, &violations).emit() + } else { + tcx.dcx().span_delayed_bug( + span, + format!( + "projection from non-dyn-compatible trait `{}`", + tcx.def_path_str(def_id) + ), + ) + }; + return Ok(Projected::Progress(Progress::error_for_term( + tcx, + obligation.predicate, + guar, + ))); + } + } + } + let mut candidates = ProjectionCandidateSet::None; // Make sure that the following procedures are kept in order. ParamEnv @@ -857,11 +887,6 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>( _ => return, }; - // Projecting `dyn Trait` is only valid when `Trait` is dyn-compatible. - if data.principal_def_id().is_some_and(|def_id| !tcx.is_dyn_compatible(def_id)) { - return; - } - let env_predicates = data .projection_bounds() .filter(|bound| bound.item_def_id() == obligation.predicate.expect_projection_def_id()) diff --git a/tests/ui/self/dispatch-dyn-incompatible-that-does-not-deref.rs b/tests/ui/self/dispatch-dyn-incompatible-that-does-not-deref.rs index 40c1e07a70073..7b64f3f35e89f 100644 --- a/tests/ui/self/dispatch-dyn-incompatible-that-does-not-deref.rs +++ b/tests/ui/self/dispatch-dyn-incompatible-that-does-not-deref.rs @@ -12,7 +12,6 @@ trait Foo: Deref { fn test(x: &dyn Foo) { //~^ ERROR the trait `Foo` is not dyn compatible x.method(); - //~^ ERROR no method named `method` found for reference `&dyn Foo` } fn main() {} diff --git a/tests/ui/self/dispatch-dyn-incompatible-that-does-not-deref.stderr b/tests/ui/self/dispatch-dyn-incompatible-that-does-not-deref.stderr index bb071ad87195f..b37dd6411cab3 100644 --- a/tests/ui/self/dispatch-dyn-incompatible-that-does-not-deref.stderr +++ b/tests/ui/self/dispatch-dyn-incompatible-that-does-not-deref.stderr @@ -25,16 +25,7 @@ LL | fn method(self: &W) {} = note: type of `self` must be `Self` or a type that dereferences to it = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) -error[E0599]: no method named `method` found for reference `&dyn Foo` in the current scope - --> $DIR/dispatch-dyn-incompatible-that-does-not-deref.rs:14:7 - | -LL | fn method(self: &W) {} - | -- the method might not be found because of this arbitrary self type -... -LL | x.method(); - | ^^^^^^ method not found in `&dyn Foo` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0038, E0307, E0599. +Some errors have detailed explanations: E0038, E0307. For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/traits/ice-with-dyn-pointee-errors.rs b/tests/ui/traits/ice-with-dyn-pointee-errors.rs index 4c2b775f25c9a..a862eda5f0151 100644 --- a/tests/ui/traits/ice-with-dyn-pointee-errors.rs +++ b/tests/ui/traits/ice-with-dyn-pointee-errors.rs @@ -8,7 +8,7 @@ fn unknown_sized_object_ptr_in(_: &(impl Pointee + ?Sized)) {} fn raw_pointer_in(x: &dyn Pointee) { //~^ ERROR the trait `Pointee` is not dyn compatible unknown_sized_object_ptr_in(x) - //~^ ERROR type mismatch resolving ` as Pointee>::Metadata == ()` + //~^ ERROR the trait `Pointee` is not dyn compatible //~| ERROR the trait `Pointee` is not dyn compatible } diff --git a/tests/ui/traits/ice-with-dyn-pointee-errors.stderr b/tests/ui/traits/ice-with-dyn-pointee-errors.stderr index b6eee86bdef2e..6fe4020726a78 100644 --- a/tests/ui/traits/ice-with-dyn-pointee-errors.stderr +++ b/tests/ui/traits/ice-with-dyn-pointee-errors.stderr @@ -10,21 +10,17 @@ note: for a trait to be dyn compatible it needs to allow building a vtable | = note: the trait is not dyn compatible because it opted out of dyn-compatibility -error[E0271]: type mismatch resolving ` as Pointee>::Metadata == ()` - --> $DIR/ice-with-dyn-pointee-errors.rs:10:33 +error[E0038]: the trait `Pointee` is not dyn compatible + --> $DIR/ice-with-dyn-pointee-errors.rs:10:5 | LL | unknown_sized_object_ptr_in(x) - | --------------------------- ^ expected `()`, found `DynMetadata>` - | | - | required by a bound introduced by this call + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Pointee` is not dyn compatible | - = note: expected unit type `()` - found struct `DynMetadata>` -note: required by a bound in `unknown_sized_object_ptr_in` - --> $DIR/ice-with-dyn-pointee-errors.rs:6:50 +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit + --> $SRC_DIR/core/src/ptr/metadata.rs:LL:COL | -LL | fn unknown_sized_object_ptr_in(_: &(impl Pointee + ?Sized)) {} - | ^^^^^^^^^^^^^ required by this bound in `unknown_sized_object_ptr_in` + = note: the trait is not dyn compatible because it opted out of dyn-compatibility error[E0038]: the trait `Pointee` is not dyn compatible --> $DIR/ice-with-dyn-pointee-errors.rs:10:5 @@ -52,5 +48,4 @@ note: for a trait to be dyn compatible it needs to allow building a vtable error: aborting due to 4 previous errors -Some errors have detailed explanations: E0038, E0271. -For more information about an error, try `rustc --explain E0038`. +For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/traits/object/dyn-proj-non-dyn-compat.rs b/tests/ui/traits/object/dyn-proj-non-dyn-compat.rs new file mode 100644 index 0000000000000..663e8f6cb04c0 --- /dev/null +++ b/tests/ui/traits/object/dyn-proj-non-dyn-compat.rs @@ -0,0 +1,20 @@ +// Check that we are not producing long error messages + +trait Trait { + type Output; + fn process(&mut self, input: T) -> T; +} + +struct MyImpl; + +impl Trait for MyImpl { + type Output = &'static str; + fn process(&mut self, input: T) -> T { input } +} + +fn make() -> impl Trait as Trait>::Output> { + //~^ ERROR the trait `Trait` is not dyn compatible + MyImpl +} + +fn main() {} diff --git a/tests/ui/traits/object/dyn-proj-non-dyn-compat.stderr b/tests/ui/traits/object/dyn-proj-non-dyn-compat.stderr new file mode 100644 index 0000000000000..e3c6d2ffb2eda --- /dev/null +++ b/tests/ui/traits/object/dyn-proj-non-dyn-compat.stderr @@ -0,0 +1,21 @@ +error[E0038]: the trait `Trait` is not dyn compatible + --> $DIR/dyn-proj-non-dyn-compat.rs:15:14 + | +LL | fn make() -> impl Trait as Trait>::Output> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Trait` is not dyn compatible + | +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit + --> $DIR/dyn-proj-non-dyn-compat.rs:5:8 + | +LL | trait Trait { + | ----- this trait is not dyn compatible... +LL | type Output; +LL | fn process(&mut self, input: T) -> T; + | ^^^^^^^ ...because method `process` has generic type parameters + = help: consider moving `process` to another trait + = help: only type `MyImpl` implements `Trait`; consider using it directly instead. + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/traits/object/dyn-type-param-bound-not-checked.rs b/tests/ui/traits/object/dyn-type-param-bound-not-checked.rs new file mode 100644 index 0000000000000..77f1c78942d8d --- /dev/null +++ b/tests/ui/traits/object/dyn-type-param-bound-not-checked.rs @@ -0,0 +1,13 @@ +//@ check-pass +// Protection against a naive fix for #152607 + +//@ revisions: current next + +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +trait Trait {} + +fn foo(_: &dyn Trait<[u32]>) {} + +fn main() {}