Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Emit coercion suggestions in more places #67009

Merged
merged 2 commits into from
Dec 7, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/librustc_typeck/check/coercion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
22 changes: 17 additions & 5 deletions src/librustc_typeck/check/demand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>) {
Expand Down Expand Up @@ -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))
}
Expand Down
8 changes: 6 additions & 2 deletions src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down Expand Up @@ -4957,15 +4955,21 @@ 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,
"consider using `.await` here",
format!("{}.await", code),
Applicability::MaybeIncorrect,
);
} else {
debug!("suggest_missing_await: no snippet for {:?}", sp);
}
} else {
debug!("suggest_missing_await: obligation did not hold: {:?}", obligation)
}
}
}
Expand Down
11 changes: 11 additions & 0 deletions src/test/ui/async-await/suggest-missing-await.fixed
Original file line number Diff line number Diff line change
Expand Up @@ -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() {}
11 changes: 11 additions & 0 deletions src/test/ui/async-await/suggest-missing-await.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {}
19 changes: 18 additions & 1 deletion src/test/ui/async-await/suggest-missing-await.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
4 changes: 4 additions & 0 deletions src/test/ui/issues/issue-59756.rs
Original file line number Diff line number Diff line change
@@ -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)]

Expand Down
13 changes: 9 additions & 4 deletions src/test/ui/issues/issue-59756.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
10 changes: 8 additions & 2 deletions src/test/ui/mismatched_types/abridged.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand All @@ -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`
Expand Down
5 changes: 5 additions & 0 deletions src/test/ui/proc-macro/span-preservation.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions src/test/ui/tail-typeck.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
5 changes: 5 additions & 0 deletions src/test/ui/wrong-ret-type.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down