Skip to content

Commit 00a85d2

Browse files
authored
Rollup merge of rust-lang#93072 - m-ou-se:compatible-variants-suggestion-with-desugaring, r=estebank
Compatible variants suggestion with desugaring This fixes rust-lang#90553 for `for` loops and other desugarings. r? `@estebank`
2 parents 67758c0 + ad663a2 commit 00a85d2

File tree

3 files changed

+87
-10
lines changed

3 files changed

+87
-10
lines changed

Diff for: compiler/rustc_typeck/src/check/demand.rs

+19-2
Original file line numberDiff line numberDiff line change
@@ -276,11 +276,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
276276
// we suggest adding a separate return expression instead.
277277
// (To avoid things like suggesting `Ok(while .. { .. })`.)
278278
if expr_ty.is_unit() {
279+
let mut id = expr.hir_id;
280+
let mut parent;
281+
282+
// Unroll desugaring, to make sure this works for `for` loops etc.
283+
loop {
284+
parent = self.tcx.hir().get_parent_node(id);
285+
if let Some(parent_span) = self.tcx.hir().opt_span(parent) {
286+
if parent_span.find_ancestor_inside(expr.span).is_some() {
287+
// The parent node is part of the same span, so is the result of the
288+
// same expansion/desugaring and not the 'real' parent node.
289+
id = parent;
290+
continue;
291+
}
292+
}
293+
break;
294+
}
295+
279296
if let Some(hir::Node::Block(&hir::Block {
280297
span: block_span, expr: Some(e), ..
281-
})) = self.tcx.hir().find(self.tcx.hir().get_parent_node(expr.hir_id))
298+
})) = self.tcx.hir().find(parent)
282299
{
283-
if e.hir_id == expr.hir_id {
300+
if e.hir_id == id {
284301
if let Some(span) = expr.span.find_ancestor_inside(block_span) {
285302
let return_suggestions =
286303
if self.tcx.is_diagnostic_item(sym::Result, expected_adt.did) {

Diff for: src/test/ui/did_you_mean/compatible-variants.rs

+15
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,21 @@ fn b() -> Result<(), ()> {
2323
//~| HELP try adding an expression
2424
}
2525

26+
fn c() -> Option<()> {
27+
for _ in [1, 2] {
28+
//~^ ERROR mismatched types
29+
f();
30+
}
31+
//~^ HELP try adding an expression
32+
}
33+
34+
fn d() -> Option<()> {
35+
c()?
36+
//~^ ERROR incompatible types
37+
//~| HELP try removing this `?`
38+
//~| HELP try adding an expression
39+
}
40+
2641
fn main() {
2742
let _: Option<()> = while false {};
2843
//~^ ERROR mismatched types

Diff for: src/test/ui/did_you_mean/compatible-variants.stderr

+53-8
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,52 @@ LL + Ok(())
3737
|
3838

3939
error[E0308]: mismatched types
40-
--> $DIR/compatible-variants.rs:27:25
40+
--> $DIR/compatible-variants.rs:27:5
41+
|
42+
LL | fn c() -> Option<()> {
43+
| ---------- expected `Option<()>` because of return type
44+
LL | / for _ in [1, 2] {
45+
LL | |
46+
LL | | f();
47+
LL | | }
48+
| |_____^ expected enum `Option`, found `()`
49+
|
50+
= note: expected enum `Option<()>`
51+
found unit type `()`
52+
help: try adding an expression at the end of the block
53+
|
54+
LL ~ }
55+
LL + None
56+
|
57+
LL ~ }
58+
LL + Some(())
59+
|
60+
61+
error[E0308]: `?` operator has incompatible types
62+
--> $DIR/compatible-variants.rs:35:5
63+
|
64+
LL | c()?
65+
| ^^^^ expected enum `Option`, found `()`
66+
|
67+
= note: `?` operator cannot convert from `()` to `Option<()>`
68+
= note: expected enum `Option<()>`
69+
found unit type `()`
70+
help: try removing this `?`
71+
|
72+
LL - c()?
73+
LL + c()
74+
|
75+
help: try adding an expression at the end of the block
76+
|
77+
LL ~ c()?;
78+
LL + None
79+
|
80+
LL ~ c()?;
81+
LL + Some(())
82+
|
83+
84+
error[E0308]: mismatched types
85+
--> $DIR/compatible-variants.rs:42:25
4186
|
4287
LL | let _: Option<()> = while false {};
4388
| ---------- ^^^^^^^^^^^^^^ expected enum `Option`, found `()`
@@ -52,7 +97,7 @@ LL | let _: Option<()> = Some(while false {});
5297
| +++++ +
5398

5499
error[E0308]: mismatched types
55-
--> $DIR/compatible-variants.rs:31:9
100+
--> $DIR/compatible-variants.rs:46:9
56101
|
57102
LL | while false {}
58103
| ^^^^^^^^^^^^^^ expected enum `Option`, found `()`
@@ -69,7 +114,7 @@ LL + Some(())
69114
|
70115

71116
error[E0308]: mismatched types
72-
--> $DIR/compatible-variants.rs:35:31
117+
--> $DIR/compatible-variants.rs:50:31
73118
|
74119
LL | let _: Result<i32, i32> = 1;
75120
| ---------------- ^ expected enum `Result`, found integer
@@ -86,7 +131,7 @@ LL | let _: Result<i32, i32> = Err(1);
86131
| ++++ +
87132

88133
error[E0308]: mismatched types
89-
--> $DIR/compatible-variants.rs:38:26
134+
--> $DIR/compatible-variants.rs:53:26
90135
|
91136
LL | let _: Option<i32> = 1;
92137
| ----------- ^ expected enum `Option`, found integer
@@ -101,7 +146,7 @@ LL | let _: Option<i32> = Some(1);
101146
| +++++ +
102147

103148
error[E0308]: mismatched types
104-
--> $DIR/compatible-variants.rs:41:28
149+
--> $DIR/compatible-variants.rs:56:28
105150
|
106151
LL | let _: Hey<i32, i32> = 1;
107152
| ------------- ^ expected enum `Hey`, found integer
@@ -118,7 +163,7 @@ LL | let _: Hey<i32, i32> = Hey::B(1);
118163
| +++++++ +
119164

120165
error[E0308]: mismatched types
121-
--> $DIR/compatible-variants.rs:44:29
166+
--> $DIR/compatible-variants.rs:59:29
122167
|
123168
LL | let _: Hey<i32, bool> = false;
124169
| -------------- ^^^^^ expected enum `Hey`, found `bool`
@@ -133,7 +178,7 @@ LL | let _: Hey<i32, bool> = Hey::B(false);
133178
| +++++++ +
134179

135180
error[E0308]: mismatched types
136-
--> $DIR/compatible-variants.rs:48:19
181+
--> $DIR/compatible-variants.rs:63:19
137182
|
138183
LL | let _ = Foo { bar };
139184
| ^^^ expected enum `Option`, found `i32`
@@ -145,6 +190,6 @@ help: try wrapping the expression in `Some`
145190
LL | let _ = Foo { bar: Some(bar) };
146191
| ++++++++++ +
147192

148-
error: aborting due to 9 previous errors
193+
error: aborting due to 11 previous errors
149194

150195
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)