Skip to content

Commit 3a4edf0

Browse files
committed
More fix on mismatched type suggestion for shorthand fields
1 parent 9386e14 commit 3a4edf0

File tree

5 files changed

+266
-9
lines changed

5 files changed

+266
-9
lines changed

Diff for: compiler/rustc_hir_typeck/src/errors.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -626,7 +626,7 @@ pub struct SuggestConvertViaMethod<'tcx> {
626626
pub span: Span,
627627
#[suggestion_part(code = "")]
628628
pub borrow_removal_span: Option<Span>,
629-
pub sugg: &'static str,
629+
pub sugg: String,
630630
pub expected: Ty<'tcx>,
631631
pub found: Ty<'tcx>,
632632
}

Diff for: compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs

+31-8
Original file line numberDiff line numberDiff line change
@@ -442,12 +442,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
442442
expected,
443443
)
444444
});
445+
446+
let prefix_wrap = |sugg: &str| {
447+
if let Some(name) = self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) {
448+
format!(": {}{}", name, sugg)
449+
} else {
450+
sugg.to_string()
451+
}
452+
};
453+
445454
// FIXME: This could/should be extended to suggest `as_mut` and `as_deref_mut`,
446455
// but those checks need to be a bit more delicate and the benefit is diminishing.
447456
if self.can_eq(self.param_env, found_ty_inner, peeled) && error_tys_equate_as_ref {
457+
let sugg = prefix_wrap(".as_ref()");
448458
err.subdiagnostic(errors::SuggestConvertViaMethod {
449459
span: expr.span.shrink_to_hi(),
450-
sugg: ".as_ref()",
460+
sugg,
451461
expected,
452462
found,
453463
borrow_removal_span,
@@ -458,9 +468,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
458468
&& self.can_eq(self.param_env, deref_ty, peeled)
459469
&& error_tys_equate_as_ref
460470
{
471+
let sugg = prefix_wrap(".as_deref()");
461472
err.subdiagnostic(errors::SuggestConvertViaMethod {
462473
span: expr.span.shrink_to_hi(),
463-
sugg: ".as_deref()",
474+
sugg,
464475
expected,
465476
found,
466477
borrow_removal_span,
@@ -474,10 +485,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
474485
self.can_eq(self.param_env, found, expected)
475486
})
476487
{
488+
let sugg = prefix_wrap(".map(|x| x.as_str())");
477489
err.span_suggestion_verbose(
478490
expr.span.shrink_to_hi(),
479491
fluent::hir_typeck_convert_to_str,
480-
".map(|x| x.as_str())",
492+
sugg,
481493
Applicability::MachineApplicable,
482494
);
483495
return true;
@@ -628,12 +640,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
628640
err.help("use `Box::pin`");
629641
}
630642
_ => {
643+
let prefix = if let Some(name) =
644+
self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr)
645+
{
646+
format!("{}: ", name)
647+
} else {
648+
String::new()
649+
};
650+
let suggestion = vec![
651+
(expr.span.shrink_to_lo(), format!("{prefix}Box::pin(")),
652+
(expr.span.shrink_to_hi(), ")".to_string()),
653+
];
631654
err.multipart_suggestion(
632655
"you need to pin and box this expression",
633-
vec![
634-
(expr.span.shrink_to_lo(), "Box::pin(".to_string()),
635-
(expr.span.shrink_to_hi(), ")".to_string()),
636-
],
656+
suggestion,
637657
Applicability::MaybeIncorrect,
638658
);
639659
}
@@ -1214,14 +1234,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12141234
span = parent_callsite;
12151235
}
12161236

1217-
let sugg = if expr.precedence().order() >= PREC_POSTFIX {
1237+
let mut sugg = if expr.precedence().order() >= PREC_POSTFIX {
12181238
vec![(span.shrink_to_hi(), ".into()".to_owned())]
12191239
} else {
12201240
vec![
12211241
(span.shrink_to_lo(), "(".to_owned()),
12221242
(span.shrink_to_hi(), ").into()".to_owned()),
12231243
]
12241244
};
1245+
if let Some(name) = self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) {
1246+
sugg.insert(0, (expr.span.shrink_to_lo(), format!("{}: ", name)));
1247+
}
12251248
diag.multipart_suggestion(
12261249
format!("call `Into::into` on this expression to convert `{expr_ty}` into `{expected_ty}`"),
12271250
sugg,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// run-rustfix
2+
// edition:2021
3+
#![allow(dead_code)]
4+
#![allow(unused_variables)]
5+
use std::future::Future;
6+
use std::pin::Pin;
7+
8+
fn test1() {
9+
let string = String::from("Hello, world");
10+
11+
struct Demo<'a> {
12+
option: Option<&'a str>,
13+
}
14+
15+
let option: Option<String> = Some(string.clone());
16+
let s = Demo { option: option.as_deref() }; //~ ERROR mismatched types
17+
}
18+
19+
fn test2() {
20+
let string = String::from("Hello, world");
21+
22+
struct Demo<'a> {
23+
option_ref: Option<&'a str>,
24+
}
25+
26+
let option_ref = Some(&string);
27+
let s = Demo { option_ref: option_ref.map(|x| x.as_str()) }; //~ ERROR mismatched types
28+
}
29+
30+
fn test3() {
31+
let string = String::from("Hello, world");
32+
33+
struct Demo<'a> {
34+
option_ref_ref: Option<&'a str>,
35+
}
36+
37+
let option_ref = Some(&string);
38+
let option_ref_ref = option_ref.as_ref();
39+
40+
let s = Demo { option_ref_ref: option_ref_ref.map(|x| x.as_str()) }; //~ ERROR mismatched types
41+
}
42+
43+
fn test4() {
44+
let a = 1;
45+
struct Demo {
46+
a: String,
47+
}
48+
let s = Demo { a: a.to_string() }; //~ ERROR mismatched types
49+
}
50+
51+
type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
52+
fn test5() {
53+
let a = async { 42 };
54+
struct Demo {
55+
a: BoxFuture<'static, i32>,
56+
}
57+
let s = Demo { a: Box::pin(a) }; //~ ERROR mismatched types
58+
}
59+
60+
fn test6() {
61+
struct A;
62+
struct B;
63+
64+
impl From<B> for A {
65+
fn from(_: B) -> Self {
66+
A
67+
}
68+
}
69+
70+
struct Demo {
71+
a: A,
72+
}
73+
let a = B;
74+
let s = Demo { a: a.into() }; //~ ERROR mismatched types
75+
}
76+
77+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// run-rustfix
2+
// edition:2021
3+
#![allow(dead_code)]
4+
#![allow(unused_variables)]
5+
use std::future::Future;
6+
use std::pin::Pin;
7+
8+
fn test1() {
9+
let string = String::from("Hello, world");
10+
11+
struct Demo<'a> {
12+
option: Option<&'a str>,
13+
}
14+
15+
let option: Option<String> = Some(string.clone());
16+
let s = Demo { option }; //~ ERROR mismatched types
17+
}
18+
19+
fn test2() {
20+
let string = String::from("Hello, world");
21+
22+
struct Demo<'a> {
23+
option_ref: Option<&'a str>,
24+
}
25+
26+
let option_ref = Some(&string);
27+
let s = Demo { option_ref }; //~ ERROR mismatched types
28+
}
29+
30+
fn test3() {
31+
let string = String::from("Hello, world");
32+
33+
struct Demo<'a> {
34+
option_ref_ref: Option<&'a str>,
35+
}
36+
37+
let option_ref = Some(&string);
38+
let option_ref_ref = option_ref.as_ref();
39+
40+
let s = Demo { option_ref_ref }; //~ ERROR mismatched types
41+
}
42+
43+
fn test4() {
44+
let a = 1;
45+
struct Demo {
46+
a: String,
47+
}
48+
let s = Demo { a }; //~ ERROR mismatched types
49+
}
50+
51+
type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
52+
fn test5() {
53+
let a = async { 42 };
54+
struct Demo {
55+
a: BoxFuture<'static, i32>,
56+
}
57+
let s = Demo { a }; //~ ERROR mismatched types
58+
}
59+
60+
fn test6() {
61+
struct A;
62+
struct B;
63+
64+
impl From<B> for A {
65+
fn from(_: B) -> Self {
66+
A
67+
}
68+
}
69+
70+
struct Demo {
71+
a: A,
72+
}
73+
let a = B;
74+
let s = Demo { a }; //~ ERROR mismatched types
75+
}
76+
77+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/mismatch-sugg-for-shorthand-field.rs:16:20
3+
|
4+
LL | let s = Demo { option };
5+
| ^^^^^^ expected `Option<&str>`, found `Option<String>`
6+
|
7+
= note: expected enum `Option<&str>`
8+
found enum `Option<String>`
9+
help: try using `: option.as_deref()` to convert `Option<String>` to `Option<&str>`
10+
|
11+
LL | let s = Demo { option: option.as_deref() };
12+
| +++++++++++++++++++
13+
14+
error[E0308]: mismatched types
15+
--> $DIR/mismatch-sugg-for-shorthand-field.rs:27:20
16+
|
17+
LL | let s = Demo { option_ref };
18+
| ^^^^^^^^^^ expected `Option<&str>`, found `Option<&String>`
19+
|
20+
= note: expected enum `Option<&str>`
21+
found enum `Option<&String>`
22+
help: try converting the passed type into a `&str`
23+
|
24+
LL | let s = Demo { option_ref: option_ref.map(|x| x.as_str()) };
25+
| ++++++++++++++++++++++++++++++++
26+
27+
error[E0308]: mismatched types
28+
--> $DIR/mismatch-sugg-for-shorthand-field.rs:40:20
29+
|
30+
LL | let s = Demo { option_ref_ref };
31+
| ^^^^^^^^^^^^^^ expected `Option<&str>`, found `Option<&&String>`
32+
|
33+
= note: expected enum `Option<&str>`
34+
found enum `Option<&&String>`
35+
help: try converting the passed type into a `&str`
36+
|
37+
LL | let s = Demo { option_ref_ref: option_ref_ref.map(|x| x.as_str()) };
38+
| ++++++++++++++++++++++++++++++++++++
39+
40+
error[E0308]: mismatched types
41+
--> $DIR/mismatch-sugg-for-shorthand-field.rs:48:20
42+
|
43+
LL | let s = Demo { a };
44+
| ^ expected `String`, found integer
45+
|
46+
help: try using a conversion method
47+
|
48+
LL | let s = Demo { a: a.to_string() };
49+
| ++ ++++++++++++
50+
51+
error[E0308]: mismatched types
52+
--> $DIR/mismatch-sugg-for-shorthand-field.rs:57:20
53+
|
54+
LL | let a = async { 42 };
55+
| ------------ the found `async` block
56+
...
57+
LL | let s = Demo { a };
58+
| ^ expected `Pin<Box<...>>`, found `async` block
59+
|
60+
= note: expected struct `Pin<Box<(dyn Future<Output = i32> + Send + 'static)>>`
61+
found `async` block `{async block@$DIR/mismatch-sugg-for-shorthand-field.rs:53:13: 53:25}`
62+
help: you need to pin and box this expression
63+
|
64+
LL | let s = Demo { a: Box::pin(a) };
65+
| ++++++++++++ +
66+
67+
error[E0308]: mismatched types
68+
--> $DIR/mismatch-sugg-for-shorthand-field.rs:74:20
69+
|
70+
LL | let s = Demo { a };
71+
| ^ expected `A`, found `B`
72+
|
73+
help: call `Into::into` on this expression to convert `B` into `A`
74+
|
75+
LL | let s = Demo { a: a.into() };
76+
| ++ +++++++
77+
78+
error: aborting due to 6 previous errors
79+
80+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)