Skip to content

Commit 0c5f879

Browse files
authored
Rollup merge of #95609 - compiler-errors:borrow-unsized-to-dyn, r=nagisa
Suggest borrowing when trying to coerce unsized type into `dyn Trait` A helpful error in response to #95598, since we can't coerce e.g. `&str` into `&dyn Display`, but we can coerce `&&str` into `&dyn Display` :) Not sure if the suggestion message needs some help. Let me know, and I can refine this PR.
2 parents 4cbc003 + 7d7715f commit 0c5f879

File tree

5 files changed

+71
-0
lines changed

5 files changed

+71
-0
lines changed

compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs

+6
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
474474
err.span_label(span, explanation);
475475
}
476476

477+
if let ObligationCauseCode::ObjectCastObligation(obj_ty) = obligation.cause.code().peel_derives() &&
478+
let Some(self_ty) = trait_predicate.self_ty().no_bound_vars() &&
479+
Some(trait_ref.def_id()) == self.tcx.lang_items().sized_trait() {
480+
self.suggest_borrowing_for_object_cast(&mut err, &obligation, self_ty, *obj_ty);
481+
}
482+
477483
if trait_predicate.is_const_if_const() && obligation.param_env.is_const() {
478484
let non_const_predicate = trait_ref.without_const();
479485
let non_const_obligation = Obligation {

compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs

+37
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,14 @@ pub trait InferCtxtExt<'tcx> {
7777
has_custom_message: bool,
7878
) -> bool;
7979

80+
fn suggest_borrowing_for_object_cast(
81+
&self,
82+
err: &mut Diagnostic,
83+
obligation: &PredicateObligation<'tcx>,
84+
self_ty: Ty<'tcx>,
85+
object_ty: Ty<'tcx>,
86+
);
87+
8088
fn suggest_remove_reference(
8189
&self,
8290
obligation: &PredicateObligation<'tcx>,
@@ -801,6 +809,35 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
801809
}
802810
}
803811

812+
// Suggest borrowing the type
813+
fn suggest_borrowing_for_object_cast(
814+
&self,
815+
err: &mut Diagnostic,
816+
obligation: &PredicateObligation<'tcx>,
817+
self_ty: Ty<'tcx>,
818+
object_ty: Ty<'tcx>,
819+
) {
820+
let ty::Dynamic(predicates, _) = object_ty.kind() else { return; };
821+
let self_ref_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, self_ty);
822+
823+
for predicate in predicates.iter() {
824+
if !self.predicate_must_hold_modulo_regions(
825+
&obligation.with(predicate.with_self_ty(self.tcx, self_ref_ty)),
826+
) {
827+
return;
828+
}
829+
}
830+
831+
err.span_suggestion(
832+
obligation.cause.span.shrink_to_lo(),
833+
&format!(
834+
"consider borrowing the value, since `&{self_ty}` can be coerced into `{object_ty}`"
835+
),
836+
"&".to_string(),
837+
Applicability::MaybeIncorrect,
838+
);
839+
}
840+
804841
/// Whenever references are used by mistake, like `for (i, e) in &vec.iter().enumerate()`,
805842
/// suggest removing these references until we reach a type that implements the trait.
806843
fn suggest_remove_reference(

src/test/ui/issues/issue-14366.stderr

+4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ LL | let _x = "test" as &dyn (::std::any::Any);
66
|
77
= help: the trait `Sized` is not implemented for `str`
88
= note: required for the cast to the object type `dyn Any`
9+
help: consider borrowing the value, since `&str` can be coerced into `dyn Any`
10+
|
11+
LL | let _x = &"test" as &dyn (::std::any::Any);
12+
| +
913

1014
error: aborting due to previous error
1115

src/test/ui/mismatched_types/cast-rfc0401.stderr

+8
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,10 @@ LL | let _ = fat_v as *const dyn Foo;
224224
|
225225
= help: the trait `Sized` is not implemented for `[u8]`
226226
= note: required for the cast to the object type `dyn Foo`
227+
help: consider borrowing the value, since `&[u8]` can be coerced into `dyn Foo`
228+
|
229+
LL | let _ = &fat_v as *const dyn Foo;
230+
| +
227231

228232
error[E0277]: the size for values of type `str` cannot be known at compilation time
229233
--> $DIR/cast-rfc0401.rs:62:13
@@ -233,6 +237,10 @@ LL | let _ = a as *const dyn Foo;
233237
|
234238
= help: the trait `Sized` is not implemented for `str`
235239
= note: required for the cast to the object type `dyn Foo`
240+
help: consider borrowing the value, since `&str` can be coerced into `dyn Foo`
241+
|
242+
LL | let _ = &a as *const dyn Foo;
243+
| +
236244

237245
error[E0606]: casting `&{float}` as `f32` is invalid
238246
--> $DIR/cast-rfc0401.rs:71:30

src/test/ui/unsized/unsized-fn-param.stderr

+16
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ LL | foo11("bar", &"baz");
66
|
77
= help: the trait `Sized` is not implemented for `str`
88
= note: required for the cast to the object type `dyn AsRef<Path>`
9+
help: consider borrowing the value, since `&str` can be coerced into `dyn AsRef<Path>`
10+
|
11+
LL | foo11(&"bar", &"baz");
12+
| +
913

1014
error[E0277]: the size for values of type `str` cannot be known at compilation time
1115
--> $DIR/unsized-fn-param.rs:13:19
@@ -15,6 +19,10 @@ LL | foo12(&"bar", "baz");
1519
|
1620
= help: the trait `Sized` is not implemented for `str`
1721
= note: required for the cast to the object type `dyn AsRef<Path>`
22+
help: consider borrowing the value, since `&str` can be coerced into `dyn AsRef<Path>`
23+
|
24+
LL | foo12(&"bar", &"baz");
25+
| +
1826

1927
error[E0277]: the size for values of type `str` cannot be known at compilation time
2028
--> $DIR/unsized-fn-param.rs:16:11
@@ -24,6 +32,10 @@ LL | foo21("bar", &"baz");
2432
|
2533
= help: the trait `Sized` is not implemented for `str`
2634
= note: required for the cast to the object type `dyn AsRef<str>`
35+
help: consider borrowing the value, since `&str` can be coerced into `dyn AsRef<str>`
36+
|
37+
LL | foo21(&"bar", &"baz");
38+
| +
2739

2840
error[E0277]: the size for values of type `str` cannot be known at compilation time
2941
--> $DIR/unsized-fn-param.rs:18:19
@@ -33,6 +45,10 @@ LL | foo22(&"bar", "baz");
3345
|
3446
= help: the trait `Sized` is not implemented for `str`
3547
= note: required for the cast to the object type `dyn AsRef<str>`
48+
help: consider borrowing the value, since `&str` can be coerced into `dyn AsRef<str>`
49+
|
50+
LL | foo22(&"bar", &"baz");
51+
| +
3652

3753
error: aborting due to 4 previous errors
3854

0 commit comments

Comments
 (0)