diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 901a2192e20dd..253fc5575c5bc 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -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()); diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 32df6c4636c2d..16a55d2a4d318 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -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>) { @@ -137,11 +153,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)) } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index c7a0190a1d1b4..a956aba4f62b9 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -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) } } } diff --git a/src/test/ui/async-await/suggest-missing-await.fixed b/src/test/ui/async-await/suggest-missing-await.fixed index 7c02a907ce7ad..1ec59d906206e 100644 --- a/src/test/ui/async-await/suggest-missing-await.fixed +++ b/src/test/ui/async-await/suggest-missing-await.fixed @@ -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() {} diff --git a/src/test/ui/async-await/suggest-missing-await.rs b/src/test/ui/async-await/suggest-missing-await.rs index 91abd44e65caf..70cc1f1d5a2c6 100644 --- a/src/test/ui/async-await/suggest-missing-await.rs +++ b/src/test/ui/async-await/suggest-missing-await.rs @@ -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() {} diff --git a/src/test/ui/async-await/suggest-missing-await.stderr b/src/test/ui/async-await/suggest-missing-await.stderr index 7a635a37107d2..7ab024434b2bf 100644 --- a/src/test/ui/async-await/suggest-missing-await.stderr +++ b/src/test/ui/async-await/suggest-missing-await.stderr @@ -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`. diff --git a/src/test/ui/fully-qualified-type/fully-qualified-type-name4.stderr b/src/test/ui/fully-qualified-type/fully-qualified-type-name4.stderr index b388f38a7fac7..ca61fb0c171fe 100644 --- a/src/test/ui/fully-qualified-type/fully-qualified-type-name4.stderr +++ b/src/test/ui/fully-qualified-type/fully-qualified-type-name4.stderr @@ -4,7 +4,10 @@ error[E0308]: mismatched types LL | fn bar(x: usize) -> Option { | ------------- expected `std::option::Option` 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` found type `usize` diff --git a/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.stderr b/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.stderr index aef6dc54747ce..9ca983df30af5 100644 --- a/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.stderr +++ b/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.stderr @@ -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` 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 diff --git a/src/test/ui/issues/issue-59756.rs b/src/test/ui/issues/issue-59756.rs index cccae396b7210..d6df0592be32c 100644 --- a/src/test/ui/issues/issue-59756.rs +++ b/src/test/ui/issues/issue-59756.rs @@ -1,4 +1,8 @@ // run-rustfix +// ignore-test +// +// FIXME: Re-enable this test once we support choosing +// between multiple mutually exclusive suggestions for the same span #![allow(warnings)] diff --git a/src/test/ui/issues/issue-59756.stderr b/src/test/ui/issues/issue-59756.stderr index 150916c03668a..9066e57aabfe5 100644 --- a/src/test/ui/issues/issue-59756.stderr +++ b/src/test/ui/issues/issue-59756.stderr @@ -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` 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 diff --git a/src/test/ui/mismatched_types/abridged.stderr b/src/test/ui/mismatched_types/abridged.stderr index c2081878629a6..c73130643db7b 100644 --- a/src/test/ui/mismatched_types/abridged.stderr +++ b/src/test/ui/mismatched_types/abridged.stderr @@ -26,7 +26,10 @@ error[E0308]: mismatched types LL | fn b() -> Option { | ----------- expected `std::option::Option` 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` found struct `Foo` @@ -37,7 +40,10 @@ error[E0308]: mismatched types LL | fn c() -> Result { | ---------------- expected `std::result::Result` 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` found struct `Foo` diff --git a/src/test/ui/proc-macro/span-preservation.stderr b/src/test/ui/proc-macro/span-preservation.stderr index cd6f0ea10eac9..a77e92022e2b6 100644 --- a/src/test/ui/proc-macro/span-preservation.stderr +++ b/src/test/ui/proc-macro/span-preservation.stderr @@ -14,6 +14,11 @@ LL | fn b(x: Option) -> 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 diff --git a/src/test/ui/tail-typeck.stderr b/src/test/ui/tail-typeck.stderr index eeeb258da215d..69f8ffa581bc1 100644 --- a/src/test/ui/tail-typeck.stderr +++ b/src/test/ui/tail-typeck.stderr @@ -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 diff --git a/src/test/ui/wrong-ret-type.stderr b/src/test/ui/wrong-ret-type.stderr index 440620f40b1e2..c1274bd0ea6bc 100644 --- a/src/test/ui/wrong-ret-type.stderr +++ b/src/test/ui/wrong-ret-type.stderr @@ -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