diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index e2257703f5775..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 @@ -856,6 +886,7 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>( } _ => 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..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 the trait `Foo` is not dyn compatible } 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..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,25 +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[E0038]: the trait `Foo` is not dyn compatible - --> $DIR/dispatch-dyn-incompatible-that-does-not-deref.rs:14:5 - | -LL | fn method(self: &W) {} - | -- help: consider changing method `method`'s `self` parameter to be `&self`: `&Self` -... -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 - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors 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 bb89f103e3f95..a862eda5f0151 100644 --- a/tests/ui/traits/ice-with-dyn-pointee-errors.rs +++ b/tests/ui/traits/ice-with-dyn-pointee-errors.rs @@ -9,6 +9,7 @@ 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 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..6fe4020726a78 100644 --- a/tests/ui/traits/ice-with-dyn-pointee-errors.stderr +++ b/tests/ui/traits/ice-with-dyn-pointee-errors.stderr @@ -10,6 +10,18 @@ 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:10:5 + | +LL | unknown_sized_object_ptr_in(x) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Pointee` is not dyn compatible + | +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 + | + = 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 | @@ -23,7 +35,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 +46,6 @@ 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`. 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() {}