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:
commit
fb6977c126
14 changed files with 128 additions and 115 deletions
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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<_>;
|
||||
|
|
|
|||
|
|
@ -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>;
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue