diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 216aa89dd1f28..0a22c02520939 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -474,6 +474,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { err.span_label(span, explanation); } + if let ObligationCauseCode::ObjectCastObligation(obj_ty) = obligation.cause.code().peel_derives() && + let Some(self_ty) = trait_predicate.self_ty().no_bound_vars() && + Some(trait_ref.def_id()) == self.tcx.lang_items().sized_trait() { + self.suggest_borrowing_for_object_cast(&mut err, &obligation, self_ty, *obj_ty); + } + if trait_predicate.is_const_if_const() && obligation.param_env.is_const() { let non_const_predicate = trait_ref.without_const(); let non_const_obligation = Obligation { diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index b49a5f6578f75..105e338048680 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -77,6 +77,14 @@ pub trait InferCtxtExt<'tcx> { has_custom_message: bool, ) -> bool; + fn suggest_borrowing_for_object_cast( + &self, + err: &mut Diagnostic, + obligation: &PredicateObligation<'tcx>, + self_ty: Ty<'tcx>, + object_ty: Ty<'tcx>, + ); + fn suggest_remove_reference( &self, obligation: &PredicateObligation<'tcx>, @@ -801,6 +809,35 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } } + // Suggest borrowing the type + fn suggest_borrowing_for_object_cast( + &self, + err: &mut Diagnostic, + obligation: &PredicateObligation<'tcx>, + self_ty: Ty<'tcx>, + object_ty: Ty<'tcx>, + ) { + let ty::Dynamic(predicates, _) = object_ty.kind() else { return; }; + let self_ref_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, self_ty); + + for predicate in predicates.iter() { + if !self.predicate_must_hold_modulo_regions( + &obligation.with(predicate.with_self_ty(self.tcx, self_ref_ty)), + ) { + return; + } + } + + err.span_suggestion( + obligation.cause.span.shrink_to_lo(), + &format!( + "consider borrowing the value, since `&{self_ty}` can be coerced into `{object_ty}`" + ), + "&".to_string(), + Applicability::MaybeIncorrect, + ); + } + /// Whenever references are used by mistake, like `for (i, e) in &vec.iter().enumerate()`, /// suggest removing these references until we reach a type that implements the trait. fn suggest_remove_reference( diff --git a/src/test/ui/issues/issue-14366.stderr b/src/test/ui/issues/issue-14366.stderr index d5dab561ddefb..b96b07c91a1fe 100644 --- a/src/test/ui/issues/issue-14366.stderr +++ b/src/test/ui/issues/issue-14366.stderr @@ -6,6 +6,10 @@ LL | let _x = "test" as &dyn (::std::any::Any); | = help: the trait `Sized` is not implemented for `str` = note: required for the cast to the object type `dyn Any` +help: consider borrowing the value, since `&str` can be coerced into `dyn Any` + | +LL | let _x = &"test" as &dyn (::std::any::Any); + | + error: aborting due to previous error diff --git a/src/test/ui/mismatched_types/cast-rfc0401.stderr b/src/test/ui/mismatched_types/cast-rfc0401.stderr index 5f11e4ded8004..84220ea172a11 100644 --- a/src/test/ui/mismatched_types/cast-rfc0401.stderr +++ b/src/test/ui/mismatched_types/cast-rfc0401.stderr @@ -224,6 +224,10 @@ LL | let _ = fat_v as *const dyn Foo; | = help: the trait `Sized` is not implemented for `[u8]` = note: required for the cast to the object type `dyn Foo` +help: consider borrowing the value, since `&[u8]` can be coerced into `dyn Foo` + | +LL | let _ = &fat_v as *const dyn Foo; + | + error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/cast-rfc0401.rs:62:13 @@ -233,6 +237,10 @@ LL | let _ = a as *const dyn Foo; | = help: the trait `Sized` is not implemented for `str` = note: required for the cast to the object type `dyn Foo` +help: consider borrowing the value, since `&str` can be coerced into `dyn Foo` + | +LL | let _ = &a as *const dyn Foo; + | + error[E0606]: casting `&{float}` as `f32` is invalid --> $DIR/cast-rfc0401.rs:71:30 diff --git a/src/test/ui/unsized/unsized-fn-param.stderr b/src/test/ui/unsized/unsized-fn-param.stderr index b498259efe700..3eecca0fa09d9 100644 --- a/src/test/ui/unsized/unsized-fn-param.stderr +++ b/src/test/ui/unsized/unsized-fn-param.stderr @@ -6,6 +6,10 @@ LL | foo11("bar", &"baz"); | = help: the trait `Sized` is not implemented for `str` = note: required for the cast to the object type `dyn AsRef` +help: consider borrowing the value, since `&str` can be coerced into `dyn AsRef` + | +LL | foo11(&"bar", &"baz"); + | + error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/unsized-fn-param.rs:13:19 @@ -15,6 +19,10 @@ LL | foo12(&"bar", "baz"); | = help: the trait `Sized` is not implemented for `str` = note: required for the cast to the object type `dyn AsRef` +help: consider borrowing the value, since `&str` can be coerced into `dyn AsRef` + | +LL | foo12(&"bar", &"baz"); + | + error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/unsized-fn-param.rs:16:11 @@ -24,6 +32,10 @@ LL | foo21("bar", &"baz"); | = help: the trait `Sized` is not implemented for `str` = note: required for the cast to the object type `dyn AsRef` +help: consider borrowing the value, since `&str` can be coerced into `dyn AsRef` + | +LL | foo21(&"bar", &"baz"); + | + error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/unsized-fn-param.rs:18:19 @@ -33,6 +45,10 @@ LL | foo22(&"bar", "baz"); | = help: the trait `Sized` is not implemented for `str` = note: required for the cast to the object type `dyn AsRef` +help: consider borrowing the value, since `&str` can be coerced into `dyn AsRef` + | +LL | foo22(&"bar", &"baz"); + | + error: aborting due to 4 previous errors