Skip to content

Commit 8727538

Browse files
authored
Rollup merge of #118413 - chenyukang:yukang-fix-118145-unwrap-for-shorthand, r=compiler-errors
Fix the issue of suggesting unwrap/expect for shorthand field Fixes #118145
2 parents 69e48d0 + 3a4edf0 commit 8727538

8 files changed

+341
-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

+37-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,
@@ -1811,6 +1834,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
18111834
".expect(\"REASON\")",
18121835
)
18131836
};
1837+
1838+
let sugg = match self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) {
1839+
Some(ident) => format!(": {ident}{sugg}"),
1840+
None => sugg.to_string(),
1841+
};
1842+
18141843
err.span_suggestion_verbose(
18151844
expr.span.shrink_to_hi(),
18161845
msg,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// run-rustfix
2+
#![allow(unused, dead_code)]
3+
4+
#[derive(Clone, Copy)]
5+
struct Stuff {
6+
count: i32,
7+
}
8+
struct Error;
9+
10+
fn demo() -> Result<Stuff, Error> {
11+
let count = Ok(1);
12+
Ok(Stuff { count: count? }) //~ ERROR mismatched types
13+
}
14+
15+
fn demo_unwrap() -> Stuff {
16+
let count = Some(1);
17+
Stuff { count: count.expect("REASON") } //~ ERROR mismatched types
18+
}
19+
20+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// run-rustfix
2+
#![allow(unused, dead_code)]
3+
4+
#[derive(Clone, Copy)]
5+
struct Stuff {
6+
count: i32,
7+
}
8+
struct Error;
9+
10+
fn demo() -> Result<Stuff, Error> {
11+
let count = Ok(1);
12+
Ok(Stuff { count }) //~ ERROR mismatched types
13+
}
14+
15+
fn demo_unwrap() -> Stuff {
16+
let count = Some(1);
17+
Stuff { count } //~ ERROR mismatched types
18+
}
19+
20+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/issue-118145-unwrap-for-shorthand.rs:12:16
3+
|
4+
LL | Ok(Stuff { count })
5+
| ^^^^^ expected `i32`, found `Result<{integer}, _>`
6+
|
7+
= note: expected type `i32`
8+
found enum `Result<{integer}, _>`
9+
help: use the `?` operator to extract the `Result<{integer}, _>` value, propagating a `Result::Err` value to the caller
10+
|
11+
LL | Ok(Stuff { count: count? })
12+
| ++++++++
13+
14+
error[E0308]: mismatched types
15+
--> $DIR/issue-118145-unwrap-for-shorthand.rs:17:13
16+
|
17+
LL | Stuff { count }
18+
| ^^^^^ expected `i32`, found `Option<{integer}>`
19+
|
20+
= note: expected type `i32`
21+
found enum `Option<{integer}>`
22+
help: consider using `Option::expect` to unwrap the `Option<{integer}>` value, panicking if the value is an `Option::None`
23+
|
24+
LL | Stuff { count: count.expect("REASON") }
25+
| ++++++++++++++++++++++++
26+
27+
error: aborting due to 2 previous errors
28+
29+
For more information about this error, try `rustc --explain E0308`.
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() {}

0 commit comments

Comments
 (0)