mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-23 23:34:48 +00:00
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.
This commit is contained in:
parent
7afe6d9d1f
commit
462f06de07
@ -1284,6 +1284,10 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
||||
augment_error(&mut err);
|
||||
}
|
||||
|
||||
if let Some(expr) = expression {
|
||||
fcx.emit_coerce_suggestions(&mut err, expr, found, expected);
|
||||
}
|
||||
|
||||
// Error possibly reported in `check_assign` so avoid emitting error again.
|
||||
err.emit_unless(expression.filter(|e| fcx.is_assign_to_bool(e, expected))
|
||||
.is_some());
|
||||
|
@ -15,6 +15,22 @@ use errors::{Applicability, DiagnosticBuilder};
|
||||
use super::method::probe;
|
||||
|
||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
||||
pub fn emit_coerce_suggestions(
|
||||
&self,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
expr: &hir::Expr,
|
||||
expr_ty: Ty<'tcx>,
|
||||
expected: Ty<'tcx>
|
||||
) {
|
||||
self.annotate_expected_due_to_let_ty(err, expr);
|
||||
self.suggest_compatible_variants(err, expr, expected, expr_ty);
|
||||
self.suggest_ref_or_into(err, expr, expected, expr_ty);
|
||||
self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty);
|
||||
self.suggest_missing_await(err, expr, expected, expr_ty);
|
||||
}
|
||||
|
||||
|
||||
// Requires that the two types unify, and prints an error message if
|
||||
// they don't.
|
||||
pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
|
||||
@ -127,11 +143,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
return (expected, None)
|
||||
}
|
||||
|
||||
self.annotate_expected_due_to_let_ty(&mut err, expr);
|
||||
self.suggest_compatible_variants(&mut err, expr, expected, expr_ty);
|
||||
self.suggest_ref_or_into(&mut err, expr, expected, expr_ty);
|
||||
self.suggest_boxing_when_appropriate(&mut err, expr, expected, expr_ty);
|
||||
self.suggest_missing_await(&mut err, expr, expected, expr_ty);
|
||||
self.emit_coerce_suggestions(&mut err, expr, expr_ty, expected);
|
||||
|
||||
(expected, Some(err))
|
||||
}
|
||||
|
@ -4584,8 +4584,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
pointing_at_return_type = self.suggest_missing_return_type(
|
||||
err, &fn_decl, expected, found, can_suggest);
|
||||
}
|
||||
self.suggest_ref_or_into(err, expr, expected, found);
|
||||
self.suggest_boxing_when_appropriate(err, expr, expected, found);
|
||||
pointing_at_return_type
|
||||
}
|
||||
|
||||
@ -4957,7 +4955,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
ty: expected,
|
||||
}));
|
||||
let obligation = traits::Obligation::new(self.misc(sp), self.param_env, predicate);
|
||||
debug!("suggest_missing_await: trying obligation {:?}", obligation);
|
||||
if self.infcx.predicate_may_hold(&obligation) {
|
||||
debug!("suggest_missing_await: obligation held: {:?}", obligation);
|
||||
if let Ok(code) = self.sess().source_map().span_to_snippet(sp) {
|
||||
err.span_suggestion(
|
||||
sp,
|
||||
@ -4965,7 +4965,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
format!("{}.await", code),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else {
|
||||
debug!("suggest_missing_await: no snippet for {:?}", sp);
|
||||
}
|
||||
} else {
|
||||
debug!("suggest_missing_await: obligation did not hold: {:?}", obligation)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,4 +16,15 @@ async fn suggest_await_in_async_fn() {
|
||||
//~| SUGGESTION x.await
|
||||
}
|
||||
|
||||
async fn dummy() {}
|
||||
|
||||
#[allow(unused)]
|
||||
async fn suggest_await_in_async_fn_return() {
|
||||
dummy().await;
|
||||
//~^ ERROR mismatched types [E0308]
|
||||
//~| HELP try adding a semicolon
|
||||
//~| HELP consider using `.await` here
|
||||
//~| SUGGESTION dummy().await
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -16,4 +16,15 @@ async fn suggest_await_in_async_fn() {
|
||||
//~| SUGGESTION x.await
|
||||
}
|
||||
|
||||
async fn dummy() {}
|
||||
|
||||
#[allow(unused)]
|
||||
async fn suggest_await_in_async_fn_return() {
|
||||
dummy()
|
||||
//~^ ERROR mismatched types [E0308]
|
||||
//~| HELP try adding a semicolon
|
||||
//~| HELP consider using `.await` here
|
||||
//~| SUGGESTION dummy().await
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -10,6 +10,23 @@ LL | take_u32(x)
|
||||
= note: expected type `u32`
|
||||
found opaque type `impl std::future::Future`
|
||||
|
||||
error: aborting due to previous error
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/suggest-missing-await.rs:23:5
|
||||
|
|
||||
LL | dummy()
|
||||
| ^^^^^^^ expected `()`, found opaque type
|
||||
|
|
||||
= note: expected unit type `()`
|
||||
found opaque type `impl std::future::Future`
|
||||
help: try adding a semicolon
|
||||
|
|
||||
LL | dummy();
|
||||
| ^
|
||||
help: consider using `.await` here
|
||||
|
|
||||
LL | dummy().await
|
||||
|
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
|
@ -4,7 +4,10 @@ error[E0308]: mismatched types
|
||||
LL | fn bar(x: usize) -> Option<usize> {
|
||||
| ------------- expected `std::option::Option<usize>` because of return type
|
||||
LL | return x;
|
||||
| ^ expected enum `std::option::Option`, found `usize`
|
||||
| ^
|
||||
| |
|
||||
| expected enum `std::option::Option`, found `usize`
|
||||
| help: try using a variant of the expected enum: `Some(x)`
|
||||
|
|
||||
= note: expected enum `std::option::Option<usize>`
|
||||
found type `usize`
|
||||
|
@ -2,13 +2,18 @@ error[E0308]: try expression alternatives have incompatible types
|
||||
--> $DIR/issue-51632-try-desugar-incompatible-types.rs:8:5
|
||||
|
|
||||
LL | missing_discourses()?
|
||||
| ^^^^^^^^^^^^^^^^^^^^-
|
||||
| | |
|
||||
| | help: try removing this `?`
|
||||
| expected enum `std::result::Result`, found `isize`
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ expected enum `std::result::Result`, found `isize`
|
||||
|
|
||||
= note: expected enum `std::result::Result<isize, ()>`
|
||||
found type `isize`
|
||||
help: try removing this `?`
|
||||
|
|
||||
LL | missing_discourses()
|
||||
| --
|
||||
help: try using a variant of the expected enum
|
||||
|
|
||||
LL | Ok(missing_discourses()?)
|
||||
|
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -2,13 +2,18 @@ error[E0308]: try expression alternatives have incompatible types
|
||||
--> $DIR/issue-59756.rs:13:5
|
||||
|
|
||||
LL | foo()?
|
||||
| ^^^^^-
|
||||
| | |
|
||||
| | help: try removing this `?`
|
||||
| expected enum `std::result::Result`, found struct `A`
|
||||
| ^^^^^^ expected enum `std::result::Result`, found struct `A`
|
||||
|
|
||||
= note: expected enum `std::result::Result<A, B>`
|
||||
found struct `A`
|
||||
help: try removing this `?`
|
||||
|
|
||||
LL | foo()
|
||||
| --
|
||||
help: try using a variant of the expected enum
|
||||
|
|
||||
LL | Ok(foo()?)
|
||||
|
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -26,7 +26,10 @@ error[E0308]: mismatched types
|
||||
LL | fn b() -> Option<Foo> {
|
||||
| ----------- expected `std::option::Option<Foo>` because of return type
|
||||
LL | Foo { bar: 1 }
|
||||
| ^^^^^^^^^^^^^^ expected enum `std::option::Option`, found struct `Foo`
|
||||
| ^^^^^^^^^^^^^^
|
||||
| |
|
||||
| expected enum `std::option::Option`, found struct `Foo`
|
||||
| help: try using a variant of the expected enum: `Some(Foo { bar: 1 })`
|
||||
|
|
||||
= note: expected enum `std::option::Option<Foo>`
|
||||
found struct `Foo`
|
||||
@ -37,7 +40,10 @@ error[E0308]: mismatched types
|
||||
LL | fn c() -> Result<Foo, Bar> {
|
||||
| ---------------- expected `std::result::Result<Foo, Bar>` because of return type
|
||||
LL | Foo { bar: 1 }
|
||||
| ^^^^^^^^^^^^^^ expected enum `std::result::Result`, found struct `Foo`
|
||||
| ^^^^^^^^^^^^^^
|
||||
| |
|
||||
| expected enum `std::result::Result`, found struct `Foo`
|
||||
| help: try using a variant of the expected enum: `Ok(Foo { bar: 1 })`
|
||||
|
|
||||
= note: expected enum `std::result::Result<Foo, Bar>`
|
||||
found struct `Foo`
|
||||
|
@ -14,6 +14,11 @@ LL | fn b(x: Option<isize>) -> usize {
|
||||
LL | match x {
|
||||
LL | Some(x) => { return x },
|
||||
| ^ expected `usize`, found `isize`
|
||||
|
|
||||
help: you can convert an `isize` to `usize` and panic if the converted value wouldn't fit
|
||||
|
|
||||
LL | Some(x) => { return x.try_into().unwrap() },
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/span-preservation.rs:33:22
|
||||
|
@ -5,6 +5,11 @@ LL | fn f() -> isize { return g(); }
|
||||
| ----- ^^^ expected `isize`, found `usize`
|
||||
| |
|
||||
| expected `isize` because of return type
|
||||
|
|
||||
help: you can convert an `usize` to `isize` and panic if the converted value wouldn't fit
|
||||
|
|
||||
LL | fn f() -> isize { return g().try_into().unwrap(); }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -5,6 +5,11 @@ LL | fn mk_int() -> usize { let i: isize = 3; return i; }
|
||||
| ----- ^ expected `usize`, found `isize`
|
||||
| |
|
||||
| expected `usize` because of return type
|
||||
|
|
||||
help: you can convert an `isize` to `usize` and panic if the converted value wouldn't fit
|
||||
|
|
||||
LL | fn mk_int() -> usize { let i: isize = 3; return i.try_into().unwrap(); }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user