Skip to content

Commit 27288bc

Browse files
committed
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>; | ++++ + ```
1 parent df8102f commit 27288bc

File tree

11 files changed

+118
-96
lines changed

11 files changed

+118
-96
lines changed

compiler/rustc_hir_typeck/src/cast.rs

Lines changed: 37 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -380,16 +380,14 @@ impl<'a, 'tcx> CastCheck<'tcx> {
380380
err.span_label(self.span, "invalid cast");
381381
if self.expr_ty.is_numeric() {
382382
if self.expr_ty == fcx.tcx.types.u32 {
383-
match fcx.tcx.sess.source_map().span_to_snippet(self.expr.span) {
384-
Ok(snippet) => err.span_suggestion(
385-
self.span,
386-
"try `char::from_u32` instead",
387-
format!("char::from_u32({snippet})"),
388-
Applicability::MachineApplicable,
389-
),
390-
391-
Err(_) => err.span_help(self.span, "try `char::from_u32` instead"),
392-
};
383+
err.multipart_suggestion(
384+
"try `char::from_u32` instead",
385+
vec![
386+
(self.expr_span.shrink_to_lo(), "char::from_u32(".to_string()),
387+
(self.expr_span.shrink_to_hi().to(self.cast_span), ")".to_string()),
388+
],
389+
Applicability::MachineApplicable,
390+
);
393391
} else if self.expr_ty == fcx.tcx.types.i8 {
394392
err.span_help(self.span, "try casting from `u8` instead");
395393
} else {
@@ -496,9 +494,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
496494
) {
497495
let mut label = true;
498496
// Check `impl From<self.expr_ty> for self.cast_ty {}` for accurate suggestion:
499-
if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr_span)
500-
&& let Some(from_trait) = fcx.tcx.get_diagnostic_item(sym::From)
501-
{
497+
if let Some(from_trait) = fcx.tcx.get_diagnostic_item(sym::From) {
502498
let ty = fcx.resolve_vars_if_possible(self.cast_ty);
503499
let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty);
504500
if fcx
@@ -507,25 +503,22 @@ impl<'a, 'tcx> CastCheck<'tcx> {
507503
.must_apply_modulo_regions()
508504
{
509505
label = false;
510-
if let ty::Adt(def, args) = self.cast_ty.kind() {
511-
err.span_suggestion_verbose(
512-
self.span,
513-
"consider using the `From` trait instead",
514-
format!(
515-
"{}::from({})",
516-
fcx.tcx.value_path_str_with_args(def.did(), args),
517-
snippet
518-
),
519-
Applicability::MaybeIncorrect,
520-
);
506+
let to_ty = if let ty::Adt(def, args) = self.cast_ty.kind() {
507+
fcx.tcx.value_path_str_with_args(def.did(), args)
521508
} else {
522-
err.span_suggestion(
523-
self.span,
524-
"consider using the `From` trait instead",
525-
format!("{}::from({})", self.cast_ty, snippet),
526-
Applicability::MaybeIncorrect,
527-
);
509+
self.cast_ty.to_string()
528510
};
511+
err.multipart_suggestion(
512+
"consider using the `From` trait instead",
513+
vec![
514+
(self.expr_span.shrink_to_lo(), format!("{to_ty}::from(")),
515+
(
516+
self.expr_span.shrink_to_hi().to(self.cast_span),
517+
")".to_string(),
518+
),
519+
],
520+
Applicability::MaybeIncorrect,
521+
);
529522
}
530523
}
531524

@@ -654,38 +647,22 @@ impl<'a, 'tcx> CastCheck<'tcx> {
654647
match self.expr_ty.kind() {
655648
ty::Ref(_, _, mt) => {
656649
let mtstr = mt.prefix_str();
657-
match fcx.tcx.sess.source_map().span_to_snippet(self.cast_span) {
658-
Ok(s) => {
659-
err.span_suggestion(
660-
self.cast_span,
661-
"try casting to a reference instead",
662-
format!("&{mtstr}{s}"),
663-
Applicability::MachineApplicable,
664-
);
665-
}
666-
Err(_) => {
667-
let msg = format!("did you mean `&{mtstr}{tstr}`?");
668-
err.span_help(self.cast_span, msg);
669-
}
670-
}
650+
err.span_suggestion_verbose(
651+
self.cast_span.shrink_to_lo(),
652+
"try casting to a reference instead",
653+
format!("&{mtstr}"),
654+
Applicability::MachineApplicable,
655+
);
671656
}
672657
ty::Adt(def, ..) if def.is_box() => {
673-
match fcx.tcx.sess.source_map().span_to_snippet(self.cast_span) {
674-
Ok(s) => {
675-
err.span_suggestion(
676-
self.cast_span,
677-
"you can cast to a `Box` instead",
678-
format!("Box<{s}>"),
679-
Applicability::MachineApplicable,
680-
);
681-
}
682-
Err(_) => {
683-
err.span_help(
684-
self.cast_span,
685-
format!("you might have meant `Box<{tstr}>`"),
686-
);
687-
}
688-
}
658+
err.multipart_suggestion(
659+
"you can cast to a `Box` instead",
660+
vec![
661+
(self.cast_span.shrink_to_lo(), "Box<".to_string()),
662+
(self.cast_span.shrink_to_hi(), ">".to_string()),
663+
],
664+
Applicability::MachineApplicable,
665+
);
689666
}
690667
_ => {
691668
err.span_help(self.expr_span, "consider using a box or reference as appropriate");

tests/ui/cast/cast-to-slice.stderr

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,23 @@ error[E0620]: cast to unsized type: `&[u8]` as `[char]`
22
--> $DIR/cast-to-slice.rs:2:5
33
|
44
LL | "example".as_bytes() as [char];
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^------
6-
| |
7-
| help: try casting to a reference instead: `&[char]`
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
help: try casting to a reference instead
8+
|
9+
LL | "example".as_bytes() as &[char];
10+
| +
811

912
error[E0620]: cast to unsized type: `&[u8]` as `[char]`
1013
--> $DIR/cast-to-slice.rs:6:5
1114
|
1215
LL | arr as [char];
13-
| ^^^^^^^------
14-
| |
15-
| help: try casting to a reference instead: `&[char]`
16+
| ^^^^^^^^^^^^^
17+
|
18+
help: try casting to a reference instead
19+
|
20+
LL | arr as &[char];
21+
| +
1622

1723
error: aborting due to 2 previous errors
1824

tests/ui/cast/cast-to-unsized-trait-object-suggestion.stderr

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,23 @@ error[E0620]: cast to unsized type: `&{integer}` as `dyn Send`
22
--> $DIR/cast-to-unsized-trait-object-suggestion.rs:2:5
33
|
44
LL | &1 as dyn Send;
5-
| ^^^^^^--------
6-
| |
7-
| help: try casting to a reference instead: `&dyn Send`
5+
| ^^^^^^^^^^^^^^
6+
|
7+
help: try casting to a reference instead
8+
|
9+
LL | &1 as &dyn Send;
10+
| +
811

912
error[E0620]: cast to unsized type: `Box<{integer}>` as `dyn Send`
1013
--> $DIR/cast-to-unsized-trait-object-suggestion.rs:3:5
1114
|
1215
LL | Box::new(1) as dyn Send;
13-
| ^^^^^^^^^^^^^^^--------
14-
| |
15-
| help: you can cast to a `Box` instead: `Box<dyn Send>`
16+
| ^^^^^^^^^^^^^^^^^^^^^^^
17+
|
18+
help: you can cast to a `Box` instead
19+
|
20+
LL | Box::new(1) as Box<dyn Send>;
21+
| ++++ +
1622

1723
error: aborting due to 2 previous errors
1824

tests/ui/error-codes/E0604.stderr

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@ error[E0604]: only `u8` can be cast as `char`, not `u32`
22
--> $DIR/E0604.rs:2:5
33
|
44
LL | 1u32 as char;
5-
| ^^^^^^^^^^^^
6-
| |
7-
| invalid cast
8-
| help: try `char::from_u32` instead: `char::from_u32(1u32)`
5+
| ^^^^^^^^^^^^ invalid cast
6+
|
7+
help: try `char::from_u32` instead
8+
|
9+
LL - 1u32 as char;
10+
LL + char::from_u32(1u32);
11+
|
912

1013
error: aborting due to 1 previous error
1114

tests/ui/error-codes/E0620.stderr

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@ error[E0620]: cast to unsized type: `&[usize; 2]` as `[usize]`
22
--> $DIR/E0620.rs:2:16
33
|
44
LL | let _foo = &[1_usize, 2] as [usize];
5-
| ^^^^^^^^^^^^^^^^^-------
6-
| |
7-
| help: try casting to a reference instead: `&[usize]`
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
help: try casting to a reference instead
8+
|
9+
LL | let _foo = &[1_usize, 2] as &[usize];
10+
| +
811

912
error: aborting due to 1 previous error
1013

tests/ui/error-emitter/error-festival.stderr

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,13 @@ error[E0604]: only `u8` can be cast as `char`, not `u32`
5858
--> $DIR/error-festival.rs:27:5
5959
|
6060
LL | 0u32 as char;
61-
| ^^^^^^^^^^^^
62-
| |
63-
| invalid cast
64-
| help: try `char::from_u32` instead: `char::from_u32(0u32)`
61+
| ^^^^^^^^^^^^ invalid cast
62+
|
63+
help: try `char::from_u32` instead
64+
|
65+
LL - 0u32 as char;
66+
LL + char::from_u32(0u32);
67+
|
6568

6669
error[E0605]: non-primitive cast: `u8` as `Vec<u8>`
6770
--> $DIR/error-festival.rs:31:5

tests/ui/issues/issue-16048.stderr

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,14 @@ error[E0605]: non-primitive cast: `Foo<'a>` as `T`
1111
--> $DIR/issue-16048.rs:24:16
1212
|
1313
LL | return *self as T;
14-
| ^^^^^^^^^^ help: consider using the `From` trait instead: `T::from(*self)`
14+
| ^^^^^^^^^^
1515
|
1616
= note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
17+
help: consider using the `From` trait instead
18+
|
19+
LL - return *self as T;
20+
LL + return T::from(*self);
21+
|
1722

1823
error: aborting due to 2 previous errors
1924

tests/ui/issues/issue-17441.stderr

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,23 @@ error[E0620]: cast to unsized type: `&[usize; 2]` as `[usize]`
22
--> $DIR/issue-17441.rs:2:16
33
|
44
LL | let _foo = &[1_usize, 2] as [usize];
5-
| ^^^^^^^^^^^^^^^^^-------
6-
| |
7-
| help: try casting to a reference instead: `&[usize]`
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
help: try casting to a reference instead
8+
|
9+
LL | let _foo = &[1_usize, 2] as &[usize];
10+
| +
811

912
error[E0620]: cast to unsized type: `Box<usize>` as `dyn Debug`
1013
--> $DIR/issue-17441.rs:5:16
1114
|
1215
LL | let _bar = Box::new(1_usize) as dyn std::fmt::Debug;
13-
| ^^^^^^^^^^^^^^^^^^^^^-------------------
14-
| |
15-
| help: you can cast to a `Box` instead: `Box<dyn std::fmt::Debug>`
16+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
17+
|
18+
help: you can cast to a `Box` instead
19+
|
20+
LL | let _bar = Box::new(1_usize) as Box<dyn std::fmt::Debug>;
21+
| ++++ +
1622

1723
error[E0620]: cast to unsized type: `usize` as `dyn Debug`
1824
--> $DIR/issue-17441.rs:8:16

tests/ui/mismatched_types/cast-rfc0401.stderr

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,10 +104,13 @@ error[E0604]: only `u8` can be cast as `char`, not `u32`
104104
--> $DIR/cast-rfc0401.rs:41:13
105105
|
106106
LL | let _ = 0x61u32 as char;
107-
| ^^^^^^^^^^^^^^^
108-
| |
109-
| invalid cast
110-
| help: try `char::from_u32` instead: `char::from_u32(0x61u32)`
107+
| ^^^^^^^^^^^^^^^ invalid cast
108+
|
109+
help: try `char::from_u32` instead
110+
|
111+
LL - let _ = 0x61u32 as char;
112+
LL + let _ = char::from_u32(0x61u32);
113+
|
111114

112115
error[E0606]: casting `bool` as `f32` is invalid
113116
--> $DIR/cast-rfc0401.rs:43:13

tests/ui/nonscalar-cast.stderr

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,14 @@ error[E0605]: non-primitive cast: `Foo` as `isize`
22
--> $DIR/nonscalar-cast.rs:15:20
33
|
44
LL | println!("{}", Foo { x: 1 } as isize);
5-
| ^^^^^^^^^^^^^^^^^^^^^ help: consider using the `From` trait instead: `isize::from(Foo { x: 1 })`
5+
| ^^^^^^^^^^^^^^^^^^^^^
66
|
77
= note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
8+
help: consider using the `From` trait instead
9+
|
10+
LL - println!("{}", Foo { x: 1 } as isize);
11+
LL + println!("{}", isize::from(Foo { x: 1 }));
12+
|
813

914
error: aborting due to 1 previous error
1015

tests/ui/tag-variant-cast-non-nullary.stderr

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,15 @@ error[E0605]: non-primitive cast: `NonNullary` as `isize`
22
--> $DIR/tag-variant-cast-non-nullary.rs:19:15
33
|
44
LL | let val = v as isize;
5-
| ^^^^^^^^^^ help: consider using the `From` trait instead: `isize::from(v)`
5+
| ^^^^^^^^^^
66
|
77
= 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
88
= note: see https://doc.rust-lang.org/reference/items/enumerations.html#casting for more information
9+
help: consider using the `From` trait instead
10+
|
11+
LL - let val = v as isize;
12+
LL + let val = isize::from(v);
13+
|
914

1015
error: aborting due to 1 previous error
1116

0 commit comments

Comments
 (0)