Skip to content

Commit 462f06d

Browse files
committed
Emit coercion suggestions in more places
Fixes #66910 We have several different kinds of suggestions we can try to make when type coercion fails. However, we were previously only emitting these suggestions from `demand_coerce_diag`. This resulted in the compiler failing to emit applicable suggestions in several different cases, such as when the implicit return value of a function had the wrong type. This commit adds a new `emit_coerce_suggestions` method, which tries to emit a number of related suggestions. This method is called from both `demand_coerce_diag` and `CoerceMany::coerce_inner`, which covers a much wider range of cases than before. We now suggest using `.await` in more cases where it is applicable, among other improvements.
1 parent 7afe6d9 commit 462f06d

13 files changed

+112
-19
lines changed

src/librustc_typeck/check/coercion.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1284,6 +1284,10 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
12841284
augment_error(&mut err);
12851285
}
12861286

1287+
if let Some(expr) = expression {
1288+
fcx.emit_coerce_suggestions(&mut err, expr, found, expected);
1289+
}
1290+
12871291
// Error possibly reported in `check_assign` so avoid emitting error again.
12881292
err.emit_unless(expression.filter(|e| fcx.is_assign_to_bool(e, expected))
12891293
.is_some());

src/librustc_typeck/check/demand.rs

+17-5
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,22 @@ use errors::{Applicability, DiagnosticBuilder};
1515
use super::method::probe;
1616

1717
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
18+
19+
pub fn emit_coerce_suggestions(
20+
&self,
21+
err: &mut DiagnosticBuilder<'_>,
22+
expr: &hir::Expr,
23+
expr_ty: Ty<'tcx>,
24+
expected: Ty<'tcx>
25+
) {
26+
self.annotate_expected_due_to_let_ty(err, expr);
27+
self.suggest_compatible_variants(err, expr, expected, expr_ty);
28+
self.suggest_ref_or_into(err, expr, expected, expr_ty);
29+
self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty);
30+
self.suggest_missing_await(err, expr, expected, expr_ty);
31+
}
32+
33+
1834
// Requires that the two types unify, and prints an error message if
1935
// they don't.
2036
pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
@@ -127,11 +143,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
127143
return (expected, None)
128144
}
129145

130-
self.annotate_expected_due_to_let_ty(&mut err, expr);
131-
self.suggest_compatible_variants(&mut err, expr, expected, expr_ty);
132-
self.suggest_ref_or_into(&mut err, expr, expected, expr_ty);
133-
self.suggest_boxing_when_appropriate(&mut err, expr, expected, expr_ty);
134-
self.suggest_missing_await(&mut err, expr, expected, expr_ty);
146+
self.emit_coerce_suggestions(&mut err, expr, expr_ty, expected);
135147

136148
(expected, Some(err))
137149
}

src/librustc_typeck/check/mod.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -4584,8 +4584,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
45844584
pointing_at_return_type = self.suggest_missing_return_type(
45854585
err, &fn_decl, expected, found, can_suggest);
45864586
}
4587-
self.suggest_ref_or_into(err, expr, expected, found);
4588-
self.suggest_boxing_when_appropriate(err, expr, expected, found);
45894587
pointing_at_return_type
45904588
}
45914589

@@ -4957,15 +4955,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
49574955
ty: expected,
49584956
}));
49594957
let obligation = traits::Obligation::new(self.misc(sp), self.param_env, predicate);
4958+
debug!("suggest_missing_await: trying obligation {:?}", obligation);
49604959
if self.infcx.predicate_may_hold(&obligation) {
4960+
debug!("suggest_missing_await: obligation held: {:?}", obligation);
49614961
if let Ok(code) = self.sess().source_map().span_to_snippet(sp) {
49624962
err.span_suggestion(
49634963
sp,
49644964
"consider using `.await` here",
49654965
format!("{}.await", code),
49664966
Applicability::MaybeIncorrect,
49674967
);
4968+
} else {
4969+
debug!("suggest_missing_await: no snippet for {:?}", sp);
49684970
}
4971+
} else {
4972+
debug!("suggest_missing_await: obligation did not hold: {:?}", obligation)
49694973
}
49704974
}
49714975
}

src/test/ui/async-await/suggest-missing-await.fixed

+11
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,15 @@ async fn suggest_await_in_async_fn() {
1616
//~| SUGGESTION x.await
1717
}
1818

19+
async fn dummy() {}
20+
21+
#[allow(unused)]
22+
async fn suggest_await_in_async_fn_return() {
23+
dummy().await;
24+
//~^ ERROR mismatched types [E0308]
25+
//~| HELP try adding a semicolon
26+
//~| HELP consider using `.await` here
27+
//~| SUGGESTION dummy().await
28+
}
29+
1930
fn main() {}

src/test/ui/async-await/suggest-missing-await.rs

+11
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,15 @@ async fn suggest_await_in_async_fn() {
1616
//~| SUGGESTION x.await
1717
}
1818

19+
async fn dummy() {}
20+
21+
#[allow(unused)]
22+
async fn suggest_await_in_async_fn_return() {
23+
dummy()
24+
//~^ ERROR mismatched types [E0308]
25+
//~| HELP try adding a semicolon
26+
//~| HELP consider using `.await` here
27+
//~| SUGGESTION dummy().await
28+
}
29+
1930
fn main() {}

src/test/ui/async-await/suggest-missing-await.stderr

+18-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,23 @@ LL | take_u32(x)
1010
= note: expected type `u32`
1111
found opaque type `impl std::future::Future`
1212

13-
error: aborting due to previous error
13+
error[E0308]: mismatched types
14+
--> $DIR/suggest-missing-await.rs:23:5
15+
|
16+
LL | dummy()
17+
| ^^^^^^^ expected `()`, found opaque type
18+
|
19+
= note: expected unit type `()`
20+
found opaque type `impl std::future::Future`
21+
help: try adding a semicolon
22+
|
23+
LL | dummy();
24+
| ^
25+
help: consider using `.await` here
26+
|
27+
LL | dummy().await
28+
|
29+
30+
error: aborting due to 2 previous errors
1431

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

src/test/ui/fully-qualified-type/fully-qualified-type-name4.stderr

+4-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ error[E0308]: mismatched types
44
LL | fn bar(x: usize) -> Option<usize> {
55
| ------------- expected `std::option::Option<usize>` because of return type
66
LL | return x;
7-
| ^ expected enum `std::option::Option`, found `usize`
7+
| ^
8+
| |
9+
| expected enum `std::option::Option`, found `usize`
10+
| help: try using a variant of the expected enum: `Some(x)`
811
|
912
= note: expected enum `std::option::Option<usize>`
1013
found type `usize`

src/test/ui/issues/issue-51632-try-desugar-incompatible-types.stderr

+9-4
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,18 @@ error[E0308]: try expression alternatives have incompatible types
22
--> $DIR/issue-51632-try-desugar-incompatible-types.rs:8:5
33
|
44
LL | missing_discourses()?
5-
| ^^^^^^^^^^^^^^^^^^^^-
6-
| | |
7-
| | help: try removing this `?`
8-
| expected enum `std::result::Result`, found `isize`
5+
| ^^^^^^^^^^^^^^^^^^^^^ expected enum `std::result::Result`, found `isize`
96
|
107
= note: expected enum `std::result::Result<isize, ()>`
118
found type `isize`
9+
help: try removing this `?`
10+
|
11+
LL | missing_discourses()
12+
| --
13+
help: try using a variant of the expected enum
14+
|
15+
LL | Ok(missing_discourses()?)
16+
|
1217

1318
error: aborting due to previous error
1419

src/test/ui/issues/issue-59756.stderr

+9-4
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,18 @@ error[E0308]: try expression alternatives have incompatible types
22
--> $DIR/issue-59756.rs:13:5
33
|
44
LL | foo()?
5-
| ^^^^^-
6-
| | |
7-
| | help: try removing this `?`
8-
| expected enum `std::result::Result`, found struct `A`
5+
| ^^^^^^ expected enum `std::result::Result`, found struct `A`
96
|
107
= note: expected enum `std::result::Result<A, B>`
118
found struct `A`
9+
help: try removing this `?`
10+
|
11+
LL | foo()
12+
| --
13+
help: try using a variant of the expected enum
14+
|
15+
LL | Ok(foo()?)
16+
|
1217

1318
error: aborting due to previous error
1419

src/test/ui/mismatched_types/abridged.stderr

+8-2
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,10 @@ error[E0308]: mismatched types
2626
LL | fn b() -> Option<Foo> {
2727
| ----------- expected `std::option::Option<Foo>` because of return type
2828
LL | Foo { bar: 1 }
29-
| ^^^^^^^^^^^^^^ expected enum `std::option::Option`, found struct `Foo`
29+
| ^^^^^^^^^^^^^^
30+
| |
31+
| expected enum `std::option::Option`, found struct `Foo`
32+
| help: try using a variant of the expected enum: `Some(Foo { bar: 1 })`
3033
|
3134
= note: expected enum `std::option::Option<Foo>`
3235
found struct `Foo`
@@ -37,7 +40,10 @@ error[E0308]: mismatched types
3740
LL | fn c() -> Result<Foo, Bar> {
3841
| ---------------- expected `std::result::Result<Foo, Bar>` because of return type
3942
LL | Foo { bar: 1 }
40-
| ^^^^^^^^^^^^^^ expected enum `std::result::Result`, found struct `Foo`
43+
| ^^^^^^^^^^^^^^
44+
| |
45+
| expected enum `std::result::Result`, found struct `Foo`
46+
| help: try using a variant of the expected enum: `Ok(Foo { bar: 1 })`
4147
|
4248
= note: expected enum `std::result::Result<Foo, Bar>`
4349
found struct `Foo`

src/test/ui/proc-macro/span-preservation.stderr

+5
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ LL | fn b(x: Option<isize>) -> usize {
1414
LL | match x {
1515
LL | Some(x) => { return x },
1616
| ^ expected `usize`, found `isize`
17+
|
18+
help: you can convert an `isize` to `usize` and panic if the converted value wouldn't fit
19+
|
20+
LL | Some(x) => { return x.try_into().unwrap() },
21+
| ^^^^^^^^^^^^^^^^^^^^^
1722

1823
error[E0308]: mismatched types
1924
--> $DIR/span-preservation.rs:33:22

src/test/ui/tail-typeck.stderr

+5
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ LL | fn f() -> isize { return g(); }
55
| ----- ^^^ expected `isize`, found `usize`
66
| |
77
| expected `isize` because of return type
8+
|
9+
help: you can convert an `usize` to `isize` and panic if the converted value wouldn't fit
10+
|
11+
LL | fn f() -> isize { return g().try_into().unwrap(); }
12+
| ^^^^^^^^^^^^^^^^^^^^^^^
813

914
error: aborting due to previous error
1015

src/test/ui/wrong-ret-type.stderr

+5
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ LL | fn mk_int() -> usize { let i: isize = 3; return i; }
55
| ----- ^ expected `usize`, found `isize`
66
| |
77
| expected `usize` because of return type
8+
|
9+
help: you can convert an `isize` to `usize` and panic if the converted value wouldn't fit
10+
|
11+
LL | fn mk_int() -> usize { let i: isize = 3; return i.try_into().unwrap(); }
12+
| ^^^^^^^^^^^^^^^^^^^^^
813

914
error: aborting due to previous error
1015

0 commit comments

Comments
 (0)