Skip to content

Commit fb6977c

Browse files
authored
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 #141973.
2 parents 6b4abb9 + 3c049e2 commit fb6977c

File tree

14 files changed

+128
-115
lines changed

14 files changed

+128
-115
lines changed

compiler/rustc_hir_typeck/src/cast.rs

Lines changed: 43 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -380,20 +380,21 @@ 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+
"consider using `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 {
394-
err.span_help(self.span, "try casting from `u8` instead");
392+
err.span_help(self.span, "consider casting from `u8` instead");
395393
} else {
396-
err.span_help(self.span, "try `char::from_u32` instead (via a `u32`)");
394+
err.span_help(
395+
self.span,
396+
"consider using `char::from_u32` instead (via a `u32`)",
397+
);
397398
};
398399
}
399400
err.emit();
@@ -494,38 +495,31 @@ impl<'a, 'tcx> CastCheck<'tcx> {
494495
self.cast_ty.kind(),
495496
ty::FnDef(..) | ty::FnPtr(..) | ty::Closure(..)
496497
) {
497-
let mut label = true;
498498
// 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-
{
499+
if let Some(from_trait) = fcx.tcx.get_diagnostic_item(sym::From) {
502500
let ty = fcx.resolve_vars_if_possible(self.cast_ty);
503501
let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty);
504502
if fcx
505503
.infcx
506504
.type_implements_trait(from_trait, [ty, expr_ty], fcx.param_env)
507505
.must_apply_modulo_regions()
508506
{
509-
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-
);
507+
let to_ty = if let ty::Adt(def, args) = self.cast_ty.kind() {
508+
fcx.tcx.value_path_str_with_args(def.did(), args)
521509
} 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-
);
510+
self.cast_ty.to_string()
528511
};
512+
err.multipart_suggestion(
513+
"consider using the `From` trait instead",
514+
vec![
515+
(self.expr_span.shrink_to_lo(), format!("{to_ty}::from(")),
516+
(
517+
self.expr_span.shrink_to_hi().to(self.cast_span),
518+
")".to_string(),
519+
),
520+
],
521+
Applicability::MaybeIncorrect,
522+
);
529523
}
530524
}
531525

@@ -548,11 +542,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
548542
)
549543
};
550544

551-
if label {
552-
err.span_label(self.span, msg);
553-
} else {
554-
err.note(msg);
555-
}
545+
err.span_label(self.span, msg);
556546

557547
if let Some(note) = note {
558548
err.note(note);
@@ -654,38 +644,22 @@ impl<'a, 'tcx> CastCheck<'tcx> {
654644
match self.expr_ty.kind() {
655645
ty::Ref(_, _, mt) => {
656646
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-
}
647+
err.span_suggestion_verbose(
648+
self.cast_span.shrink_to_lo(),
649+
"consider casting to a reference instead",
650+
format!("&{mtstr}"),
651+
Applicability::MachineApplicable,
652+
);
671653
}
672654
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-
}
655+
err.multipart_suggestion(
656+
"you can cast to a `Box` instead",
657+
vec![
658+
(self.cast_span.shrink_to_lo(), "Box<".to_string()),
659+
(self.cast_span.shrink_to_hi(), ">".to_string()),
660+
],
661+
Applicability::MachineApplicable,
662+
);
689663
}
690664
_ => {
691665
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: consider 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: consider 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: consider 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/coercion/issue-73886.stderr

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,8 @@ error[E0605]: non-primitive cast: `u32` as `Option<_>`
1010
--> $DIR/issue-73886.rs:4:13
1111
|
1212
LL | let _ = 7u32 as Option<_>;
13-
| ^^^^^^^^^^^^^^^^^
13+
| ^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
1414
|
15-
= note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
1615
help: consider using the `From` trait instead
1716
|
1817
LL - let _ = 7u32 as Option<_>;

tests/ui/coercion/non-primitive-cast-135412.stderr

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,8 @@ error[E0605]: non-primitive cast: `u32` as `Option<_>`
22
--> $DIR/non-primitive-cast-135412.rs:6:13
33
|
44
LL | let _ = 7u32 as Option<_>;
5-
| ^^^^^^^^^^^^^^^^^
5+
| ^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
66
|
7-
= note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
87
help: consider using the `From` trait instead
98
|
109
LL - let _ = 7u32 as Option<_>;
@@ -15,9 +14,8 @@ error[E0605]: non-primitive cast: `&'static str` as `Arc<str>`
1514
--> $DIR/non-primitive-cast-135412.rs:8:13
1615
|
1716
LL | let _ = "String" as Arc<str>;
18-
| ^^^^^^^^^^^^^^^^^^^^
17+
| ^^^^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
1918
|
20-
= note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
2119
help: consider using the `From` trait instead
2220
|
2321
LL - let _ = "String" as Arc<str>;

tests/ui/consts/const-eval/const-eval-overflow-4b.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ error[E0604]: only `u8` can be cast as `char`, not `i8`
2323
LL | : [u32; 5i8 as char as usize]
2424
| ^^^^^^^^^^^ invalid cast
2525
|
26-
help: try casting from `u8` instead
26+
help: consider casting from `u8` instead
2727
--> $DIR/const-eval-overflow-4b.rs:24:13
2828
|
2929
LL | : [u32; 5i8 as char as usize]

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: consider using `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: consider 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: consider using `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 & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,13 @@ 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+
| ^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
15+
|
16+
help: consider using the `From` trait instead
17+
|
18+
LL - return *self as T;
19+
LL + return T::from(*self);
1520
|
16-
= note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
1721

1822
error: aborting due to 2 previous errors
1923

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: consider 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: consider using `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 & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,13 @@ 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+
| ^^^^^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
6+
|
7+
help: consider using the `From` trait instead
8+
|
9+
LL - println!("{}", Foo { x: 1 } as isize);
10+
LL + println!("{}", isize::from(Foo { x: 1 }));
611
|
7-
= note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
812

913
error: aborting due to 1 previous error
1014

0 commit comments

Comments
 (0)