Skip to content

Commit

Permalink
Suggest borrowing when trying to coerce unsized type into dyn Trait
Browse files Browse the repository at this point in the history
  • Loading branch information
compiler-errors committed Apr 2, 2022
1 parent fbc45b6 commit 7d7715f
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
Expand Down Expand Up @@ -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(
Expand Down
4 changes: 4 additions & 0 deletions src/test/ui/issues/issue-14366.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
8 changes: 8 additions & 0 deletions src/test/ui/mismatched_types/cast-rfc0401.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
16 changes: 16 additions & 0 deletions src/test/ui/unsized/unsized-fn-param.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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<Path>`
help: consider borrowing the value, since `&str` can be coerced into `dyn AsRef<Path>`
|
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
Expand All @@ -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<Path>`
help: consider borrowing the value, since `&str` can be coerced into `dyn AsRef<Path>`
|
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
Expand All @@ -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<str>`
help: consider borrowing the value, since `&str` can be coerced into `dyn AsRef<str>`
|
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
Expand All @@ -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<str>`
help: consider borrowing the value, since `&str` can be coerced into `dyn AsRef<str>`
|
LL | foo22(&"bar", &"baz");
| +

error: aborting due to 4 previous errors

Expand Down

0 comments on commit 7d7715f

Please sign in to comment.