Skip to content

Commit da907ec

Browse files
committed
suggest unwrap/expect for let binding type mismatch
1 parent a483969 commit da907ec

File tree

6 files changed

+161
-1
lines changed

6 files changed

+161
-1
lines changed

compiler/rustc_hir_typeck/src/demand.rs

+49-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
5858
|| self.suggest_into(err, expr, expr_ty, expected)
5959
|| self.suggest_floating_point_literal(err, expr, expected)
6060
|| self.suggest_null_ptr_for_literal_zero_given_to_ptr_arg(err, expr, expected)
61-
|| self.suggest_coercing_result_via_try_operator(err, expr, expected, expr_ty);
61+
|| self.suggest_coercing_result_via_try_operator(err, expr, expected, expr_ty)
62+
|| self.suggest_missing_unwrap_expect(err, expr, expected, expr_ty);
6263

6364
if !suggested {
6465
self.note_source_of_type_mismatch_constraint(
@@ -954,6 +955,53 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
954955
);
955956
}
956957

958+
pub(crate) fn suggest_missing_unwrap_expect(
959+
&self,
960+
err: &mut Diagnostic,
961+
expr: &hir::Expr<'tcx>,
962+
expected: Ty<'tcx>,
963+
found: Ty<'tcx>,
964+
) -> bool {
965+
if let ty::Adt(adt, args) = found.kind() {
966+
if self.tcx.is_diagnostic_item(sym::Option, adt.did())
967+
|| self.tcx.is_diagnostic_item(sym::Result, adt.did())
968+
{
969+
// don't suggest anything like `Ok(ok_val).unwrap()` , `Some(some_val).unwrap()`, `None.unwrap()` etc.
970+
let is_ctor = match expr.kind {
971+
hir::ExprKind::Call(
972+
hir::Expr {
973+
kind:
974+
hir::ExprKind::Path(hir::QPath::Resolved(
975+
None,
976+
hir::Path {
977+
res: Res::Def(hir::def::DefKind::Ctor(_, _), _),
978+
..
979+
},
980+
)),
981+
..
982+
},
983+
..,
984+
) => true,
985+
hir::ExprKind::Path(hir::QPath::Resolved(
986+
None,
987+
hir::Path { res: Res::Def(hir::def::DefKind::Ctor(_, _), _), .. },
988+
)) => true,
989+
_ => false,
990+
};
991+
if !is_ctor && self.can_coerce(args.type_at(0), expected) {
992+
err.span_suggestion_verbose(
993+
expr.span.shrink_to_hi(),
994+
"you may missing `unwrap` or `expect(...)` here",
995+
".unwrap()",
996+
Applicability::MaybeIncorrect,
997+
);
998+
return true;
999+
};
1000+
}
1001+
}
1002+
return false;
1003+
}
1004+
9571005
pub(crate) fn suggest_coercing_result_via_try_operator(
9581006
&self,
9591007
err: &mut Diagnostic,

tests/ui/lifetimes/issue-26638.stderr

+4
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ LL | fn parse_type(iter: Box<dyn Iterator<Item=&str>+'static>) -> &str { iter.ne
4444
|
4545
= note: expected reference `&str`
4646
found enum `Option<&str>`
47+
help: you may missing `unwrap` or `expect(...)` here
48+
|
49+
LL | fn parse_type(iter: Box<dyn Iterator<Item=&str>+'static>) -> &str { iter.next().unwrap() }
50+
| +++++++++
4751

4852
error[E0061]: this function takes 1 argument but 0 arguments were supplied
4953
--> $DIR/issue-26638.rs:5:47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
fn func() -> Option<i32> {
2+
Some(1)
3+
}
4+
5+
fn main() {
6+
let v: i32 = Some(1); //~ ERROR mismatched types
7+
let v: i32 = None; //~ ERROR mismatched types
8+
9+
let a = Some(1);
10+
let v: i32 = a; //~ ERROR mismatched types
11+
12+
let b = Ok(1);
13+
let v: i32 = b; //~ ERROR mismatched types
14+
15+
let c = Ok(false);
16+
let v: i32 = c; //~ ERROR mismatched types
17+
18+
let v: i32 = func(); //~ ERROR mismatched types
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/mismatch-ty-unwrap-expect.rs:6:18
3+
|
4+
LL | let v: i32 = Some(1);
5+
| --- ^^^^^^^ expected `i32`, found `Option<{integer}>`
6+
| |
7+
| expected due to this
8+
|
9+
= note: expected type `i32`
10+
found enum `Option<{integer}>`
11+
12+
error[E0308]: mismatched types
13+
--> $DIR/mismatch-ty-unwrap-expect.rs:7:18
14+
|
15+
LL | let v: i32 = None;
16+
| --- ^^^^ expected `i32`, found `Option<_>`
17+
| |
18+
| expected due to this
19+
|
20+
= note: expected type `i32`
21+
found enum `Option<_>`
22+
23+
error[E0308]: mismatched types
24+
--> $DIR/mismatch-ty-unwrap-expect.rs:10:18
25+
|
26+
LL | let v: i32 = a;
27+
| --- ^ expected `i32`, found `Option<{integer}>`
28+
| |
29+
| expected due to this
30+
|
31+
= note: expected type `i32`
32+
found enum `Option<{integer}>`
33+
help: you may missing `unwrap` or `expect(...)` here
34+
|
35+
LL | let v: i32 = a.unwrap();
36+
| +++++++++
37+
38+
error[E0308]: mismatched types
39+
--> $DIR/mismatch-ty-unwrap-expect.rs:13:18
40+
|
41+
LL | let v: i32 = b;
42+
| --- ^ expected `i32`, found `Result<{integer}, _>`
43+
| |
44+
| expected due to this
45+
|
46+
= note: expected type `i32`
47+
found enum `Result<{integer}, _>`
48+
help: you may missing `unwrap` or `expect(...)` here
49+
|
50+
LL | let v: i32 = b.unwrap();
51+
| +++++++++
52+
53+
error[E0308]: mismatched types
54+
--> $DIR/mismatch-ty-unwrap-expect.rs:16:18
55+
|
56+
LL | let v: i32 = c;
57+
| --- ^ expected `i32`, found `Result<bool, _>`
58+
| |
59+
| expected due to this
60+
|
61+
= note: expected type `i32`
62+
found enum `Result<bool, _>`
63+
64+
error[E0308]: mismatched types
65+
--> $DIR/mismatch-ty-unwrap-expect.rs:18:18
66+
|
67+
LL | let v: i32 = func();
68+
| --- ^^^^^^ expected `i32`, found `Option<i32>`
69+
| |
70+
| expected due to this
71+
|
72+
= note: expected type `i32`
73+
found enum `Option<i32>`
74+
help: you may missing `unwrap` or `expect(...)` here
75+
|
76+
LL | let v: i32 = func().unwrap();
77+
| +++++++++
78+
79+
error: aborting due to 6 previous errors
80+
81+
For more information about this error, try `rustc --explain E0308`.

tests/ui/noexporttypeexe.stderr

+4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ LL | let x: isize = noexporttypelib::foo();
88
|
99
= note: expected type `isize`
1010
found enum `Option<isize>`
11+
help: you may missing `unwrap` or `expect(...)` here
12+
|
13+
LL | let x: isize = noexporttypelib::foo().unwrap();
14+
| +++++++++
1115

1216
error: aborting due to previous error
1317

tests/ui/typeck/tag-that-dare-not-speak-its-name.stderr

+4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ LL | let x : char = last(y);
88
|
99
= note: expected type `char`
1010
found enum `Option<_>`
11+
help: you may missing `unwrap` or `expect(...)` here
12+
|
13+
LL | let x : char = last(y).unwrap();
14+
| +++++++++
1115

1216
error: aborting due to previous error
1317

0 commit comments

Comments
 (0)