未验证 提交 99fee789 编写于 作者: M Mazdak Farrokhzad 提交者: GitHub

Rollup merge of #67009 - Aaron1011:fix/coerce-suggestion, r=Centril

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.

I'm not happy about disabling the `issue-59756`, but from what I can tell, the suggestion infrastructure in rustc lacks any way of indicating mutually exclusive suggestions (and compiletest lacks a way to only apply a subset of available suggestions).
......@@ -1284,6 +1284,10 @@ fn coerce_inner<'a>(
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 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>) {
......@@ -137,11 +153,7 @@ pub fn demand_coerce_diag(
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 @@ pub fn suggest_mismatched_types_on_tail(
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 @@ fn suggest_missing_await(
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 @@ fn suggest_missing_await(
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
......
// run-rustfix
// ignore-test
//
// FIXME: Re-enable this test once we support choosing
// between multiple mutually exclusive suggestions for the same span
#![allow(warnings)]
......
......@@ -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
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册