Rollup merge of #142131 - estebank:cast-sugg, r=Urgau

Make cast suggestions verbose

```
error[E0604]: only `u8` can be cast as `char`, not `u32`
  --> $DIR/E0604.rs:2:5
   |
LL |     1u32 as char;
   |     ^^^^^^^^^^^^ invalid cast
   |
help: try `char::from_u32` instead
   |
LL -     1u32 as char;
LL +     char::from_u32(1u32);
   |
```

```
error[E0620]: cast to unsized type: `&[u8]` as `[char]`
  --> $DIR/cast-to-slice.rs:6:5
   |
LL |     arr as [char];
   |     ^^^^^^^^^^^^^
   |
help: try casting to a reference instead
   |
LL |     arr as &[char];
   |            +
```

```
error[E0620]: cast to unsized type: `Box<{integer}>` as `dyn Send`
  --> $DIR/cast-to-unsized-trait-object-suggestion.rs:3:5
   |
LL |     Box::new(1) as dyn Send;
   |     ^^^^^^^^^^^^^^^^^^^^^^^
   |
help: you can cast to a `Box` instead
   |
LL |     Box::new(1) as Box<dyn Send>;
   |                    ++++        +
```

Part of rust-lang/rust#141973.
This commit is contained in:
Jacob Pratt 2025-06-07 07:05:48 +02:00 committed by GitHub
commit fb6977c126
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 128 additions and 115 deletions

View file

@ -380,20 +380,21 @@ impl<'a, 'tcx> CastCheck<'tcx> {
err.span_label(self.span, "invalid cast");
if self.expr_ty.is_numeric() {
if self.expr_ty == fcx.tcx.types.u32 {
match fcx.tcx.sess.source_map().span_to_snippet(self.expr.span) {
Ok(snippet) => err.span_suggestion(
self.span,
"try `char::from_u32` instead",
format!("char::from_u32({snippet})"),
Applicability::MachineApplicable,
),
Err(_) => err.span_help(self.span, "try `char::from_u32` instead"),
};
err.multipart_suggestion(
"consider using `char::from_u32` instead",
vec![
(self.expr_span.shrink_to_lo(), "char::from_u32(".to_string()),
(self.expr_span.shrink_to_hi().to(self.cast_span), ")".to_string()),
],
Applicability::MachineApplicable,
);
} else if self.expr_ty == fcx.tcx.types.i8 {
err.span_help(self.span, "try casting from `u8` instead");
err.span_help(self.span, "consider casting from `u8` instead");
} else {
err.span_help(self.span, "try `char::from_u32` instead (via a `u32`)");
err.span_help(
self.span,
"consider using `char::from_u32` instead (via a `u32`)",
);
};
}
err.emit();
@ -494,11 +495,8 @@ impl<'a, 'tcx> CastCheck<'tcx> {
self.cast_ty.kind(),
ty::FnDef(..) | ty::FnPtr(..) | ty::Closure(..)
) {
let mut label = true;
// Check `impl From<self.expr_ty> for self.cast_ty {}` for accurate suggestion:
if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr_span)
&& let Some(from_trait) = fcx.tcx.get_diagnostic_item(sym::From)
{
if let Some(from_trait) = fcx.tcx.get_diagnostic_item(sym::From) {
let ty = fcx.resolve_vars_if_possible(self.cast_ty);
let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty);
if fcx
@ -506,26 +504,22 @@ impl<'a, 'tcx> CastCheck<'tcx> {
.type_implements_trait(from_trait, [ty, expr_ty], fcx.param_env)
.must_apply_modulo_regions()
{
label = false;
if let ty::Adt(def, args) = self.cast_ty.kind() {
err.span_suggestion_verbose(
self.span,
"consider using the `From` trait instead",
format!(
"{}::from({})",
fcx.tcx.value_path_str_with_args(def.did(), args),
snippet
),
Applicability::MaybeIncorrect,
);
let to_ty = if let ty::Adt(def, args) = self.cast_ty.kind() {
fcx.tcx.value_path_str_with_args(def.did(), args)
} else {
err.span_suggestion(
self.span,
"consider using the `From` trait instead",
format!("{}::from({})", self.cast_ty, snippet),
Applicability::MaybeIncorrect,
);
self.cast_ty.to_string()
};
err.multipart_suggestion(
"consider using the `From` trait instead",
vec![
(self.expr_span.shrink_to_lo(), format!("{to_ty}::from(")),
(
self.expr_span.shrink_to_hi().to(self.cast_span),
")".to_string(),
),
],
Applicability::MaybeIncorrect,
);
}
}
@ -548,11 +542,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
)
};
if label {
err.span_label(self.span, msg);
} else {
err.note(msg);
}
err.span_label(self.span, msg);
if let Some(note) = note {
err.note(note);
@ -654,38 +644,22 @@ impl<'a, 'tcx> CastCheck<'tcx> {
match self.expr_ty.kind() {
ty::Ref(_, _, mt) => {
let mtstr = mt.prefix_str();
match fcx.tcx.sess.source_map().span_to_snippet(self.cast_span) {
Ok(s) => {
err.span_suggestion(
self.cast_span,
"try casting to a reference instead",
format!("&{mtstr}{s}"),
Applicability::MachineApplicable,
);
}
Err(_) => {
let msg = format!("did you mean `&{mtstr}{tstr}`?");
err.span_help(self.cast_span, msg);
}
}
err.span_suggestion_verbose(
self.cast_span.shrink_to_lo(),
"consider casting to a reference instead",
format!("&{mtstr}"),
Applicability::MachineApplicable,
);
}
ty::Adt(def, ..) if def.is_box() => {
match fcx.tcx.sess.source_map().span_to_snippet(self.cast_span) {
Ok(s) => {
err.span_suggestion(
self.cast_span,
"you can cast to a `Box` instead",
format!("Box<{s}>"),
Applicability::MachineApplicable,
);
}
Err(_) => {
err.span_help(
self.cast_span,
format!("you might have meant `Box<{tstr}>`"),
);
}
}
err.multipart_suggestion(
"you can cast to a `Box` instead",
vec![
(self.cast_span.shrink_to_lo(), "Box<".to_string()),
(self.cast_span.shrink_to_hi(), ">".to_string()),
],
Applicability::MachineApplicable,
);
}
_ => {
err.span_help(self.expr_span, "consider using a box or reference as appropriate");

View file

@ -2,17 +2,23 @@ error[E0620]: cast to unsized type: `&[u8]` as `[char]`
--> $DIR/cast-to-slice.rs:2:5
|
LL | "example".as_bytes() as [char];
| ^^^^^^^^^^^^^^^^^^^^^^^^------
| |
| help: try casting to a reference instead: `&[char]`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: consider casting to a reference instead
|
LL | "example".as_bytes() as &[char];
| +
error[E0620]: cast to unsized type: `&[u8]` as `[char]`
--> $DIR/cast-to-slice.rs:6:5
|
LL | arr as [char];
| ^^^^^^^------
| |
| help: try casting to a reference instead: `&[char]`
| ^^^^^^^^^^^^^
|
help: consider casting to a reference instead
|
LL | arr as &[char];
| +
error: aborting due to 2 previous errors

View file

@ -2,17 +2,23 @@ error[E0620]: cast to unsized type: `&{integer}` as `dyn Send`
--> $DIR/cast-to-unsized-trait-object-suggestion.rs:2:5
|
LL | &1 as dyn Send;
| ^^^^^^--------
| |
| help: try casting to a reference instead: `&dyn Send`
| ^^^^^^^^^^^^^^
|
help: consider casting to a reference instead
|
LL | &1 as &dyn Send;
| +
error[E0620]: cast to unsized type: `Box<{integer}>` as `dyn Send`
--> $DIR/cast-to-unsized-trait-object-suggestion.rs:3:5
|
LL | Box::new(1) as dyn Send;
| ^^^^^^^^^^^^^^^--------
| |
| help: you can cast to a `Box` instead: `Box<dyn Send>`
| ^^^^^^^^^^^^^^^^^^^^^^^
|
help: you can cast to a `Box` instead
|
LL | Box::new(1) as Box<dyn Send>;
| ++++ +
error: aborting due to 2 previous errors

View file

@ -10,9 +10,8 @@ error[E0605]: non-primitive cast: `u32` as `Option<_>`
--> $DIR/issue-73886.rs:4:13
|
LL | let _ = 7u32 as Option<_>;
| ^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
|
= note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
help: consider using the `From` trait instead
|
LL - let _ = 7u32 as Option<_>;

View file

@ -2,9 +2,8 @@ error[E0605]: non-primitive cast: `u32` as `Option<_>`
--> $DIR/non-primitive-cast-135412.rs:6:13
|
LL | let _ = 7u32 as Option<_>;
| ^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
|
= note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
help: consider using the `From` trait instead
|
LL - let _ = 7u32 as Option<_>;
@ -15,9 +14,8 @@ error[E0605]: non-primitive cast: `&'static str` as `Arc<str>`
--> $DIR/non-primitive-cast-135412.rs:8:13
|
LL | let _ = "String" as Arc<str>;
| ^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
|
= note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
help: consider using the `From` trait instead
|
LL - let _ = "String" as Arc<str>;

View file

@ -23,7 +23,7 @@ error[E0604]: only `u8` can be cast as `char`, not `i8`
LL | : [u32; 5i8 as char as usize]
| ^^^^^^^^^^^ invalid cast
|
help: try casting from `u8` instead
help: consider casting from `u8` instead
--> $DIR/const-eval-overflow-4b.rs:24:13
|
LL | : [u32; 5i8 as char as usize]

View file

@ -2,10 +2,13 @@ error[E0604]: only `u8` can be cast as `char`, not `u32`
--> $DIR/E0604.rs:2:5
|
LL | 1u32 as char;
| ^^^^^^^^^^^^
| |
| invalid cast
| help: try `char::from_u32` instead: `char::from_u32(1u32)`
| ^^^^^^^^^^^^ invalid cast
|
help: consider using `char::from_u32` instead
|
LL - 1u32 as char;
LL + char::from_u32(1u32);
|
error: aborting due to 1 previous error

View file

@ -2,9 +2,12 @@ error[E0620]: cast to unsized type: `&[usize; 2]` as `[usize]`
--> $DIR/E0620.rs:2:16
|
LL | let _foo = &[1_usize, 2] as [usize];
| ^^^^^^^^^^^^^^^^^-------
| |
| help: try casting to a reference instead: `&[usize]`
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
help: consider casting to a reference instead
|
LL | let _foo = &[1_usize, 2] as &[usize];
| +
error: aborting due to 1 previous error

View file

@ -58,10 +58,13 @@ error[E0604]: only `u8` can be cast as `char`, not `u32`
--> $DIR/error-festival.rs:27:5
|
LL | 0u32 as char;
| ^^^^^^^^^^^^
| |
| invalid cast
| help: try `char::from_u32` instead: `char::from_u32(0u32)`
| ^^^^^^^^^^^^ invalid cast
|
help: consider using `char::from_u32` instead
|
LL - 0u32 as char;
LL + char::from_u32(0u32);
|
error[E0605]: non-primitive cast: `u8` as `Vec<u8>`
--> $DIR/error-festival.rs:31:5

View file

@ -11,9 +11,13 @@ error[E0605]: non-primitive cast: `Foo<'a>` as `T`
--> $DIR/issue-16048.rs:24:16
|
LL | return *self as T;
| ^^^^^^^^^^ help: consider using the `From` trait instead: `T::from(*self)`
| ^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
|
help: consider using the `From` trait instead
|
LL - return *self as T;
LL + return T::from(*self);
|
= note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
error: aborting due to 2 previous errors

View file

@ -2,17 +2,23 @@ error[E0620]: cast to unsized type: `&[usize; 2]` as `[usize]`
--> $DIR/issue-17441.rs:2:16
|
LL | let _foo = &[1_usize, 2] as [usize];
| ^^^^^^^^^^^^^^^^^-------
| |
| help: try casting to a reference instead: `&[usize]`
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
help: consider casting to a reference instead
|
LL | let _foo = &[1_usize, 2] as &[usize];
| +
error[E0620]: cast to unsized type: `Box<usize>` as `dyn Debug`
--> $DIR/issue-17441.rs:5:16
|
LL | let _bar = Box::new(1_usize) as dyn std::fmt::Debug;
| ^^^^^^^^^^^^^^^^^^^^^-------------------
| |
| help: you can cast to a `Box` instead: `Box<dyn std::fmt::Debug>`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: you can cast to a `Box` instead
|
LL | let _bar = Box::new(1_usize) as Box<dyn std::fmt::Debug>;
| ++++ +
error[E0620]: cast to unsized type: `usize` as `dyn Debug`
--> $DIR/issue-17441.rs:8:16

View file

@ -104,10 +104,13 @@ error[E0604]: only `u8` can be cast as `char`, not `u32`
--> $DIR/cast-rfc0401.rs:41:13
|
LL | let _ = 0x61u32 as char;
| ^^^^^^^^^^^^^^^
| |
| invalid cast
| help: try `char::from_u32` instead: `char::from_u32(0x61u32)`
| ^^^^^^^^^^^^^^^ invalid cast
|
help: consider using `char::from_u32` instead
|
LL - let _ = 0x61u32 as char;
LL + let _ = char::from_u32(0x61u32);
|
error[E0606]: casting `bool` as `f32` is invalid
--> $DIR/cast-rfc0401.rs:43:13

View file

@ -2,9 +2,13 @@ error[E0605]: non-primitive cast: `Foo` as `isize`
--> $DIR/nonscalar-cast.rs:15:20
|
LL | println!("{}", Foo { x: 1 } as isize);
| ^^^^^^^^^^^^^^^^^^^^^ help: consider using the `From` trait instead: `isize::from(Foo { x: 1 })`
| ^^^^^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
|
help: consider using the `From` trait instead
|
LL - println!("{}", Foo { x: 1 } as isize);
LL + println!("{}", isize::from(Foo { x: 1 }));
|
= note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
error: aborting due to 1 previous error

View file

@ -2,10 +2,14 @@ error[E0605]: non-primitive cast: `NonNullary` as `isize`
--> $DIR/tag-variant-cast-non-nullary.rs:19:15
|
LL | let val = v as isize;
| ^^^^^^^^^^ help: consider using the `From` trait instead: `isize::from(v)`
| ^^^^^^^^^^ an `as` expression can be used to convert enum types to numeric types only if the enum type is unit-only or field-less
|
= note: an `as` expression can be used to convert enum types to numeric types only if the enum type is unit-only or field-less
= note: see https://doc.rust-lang.org/reference/items/enumerations.html#casting for more information
help: consider using the `From` trait instead
|
LL - let val = v as isize;
LL + let val = isize::from(v);
|
error: aborting due to 1 previous error