Suggest await on cases involving infer

This commit is contained in:
Michael Goulet 2021-11-17 21:38:04 -08:00
parent 93542a8240
commit 33c443dd9d
3 changed files with 85 additions and 4 deletions

View file

@ -310,6 +310,34 @@ pub fn unexpected_hidden_region_diagnostic(
err err
} }
/// Structurally compares two types, modulo any inference variables.
///
/// Returns `true` if two types are equal, or if one type is an inference variable compatible
/// with the other type. A TyVar inference type is compatible with any type, and an IntVar or
/// FloatVar inference type are compatible with themselves or their concrete types (Int and
/// Float types, respectively). When comparing two ADTs, these rules apply recursively.
pub fn same_type_modulo_infer(a: Ty<'tcx>, b: Ty<'ctx>) -> bool {
match (&a.kind(), &b.kind()) {
(&ty::Adt(did_a, substs_a), &ty::Adt(did_b, substs_b)) => {
if did_a != did_b {
return false;
}
substs_a.types().zip(substs_b.types()).all(|(a, b)| same_type_modulo_infer(a, b))
}
(&ty::Int(_), &ty::Infer(ty::InferTy::IntVar(_)))
| (&ty::Infer(ty::InferTy::IntVar(_)), &ty::Int(_) | &ty::Infer(ty::InferTy::IntVar(_)))
| (&ty::Float(_), &ty::Infer(ty::InferTy::FloatVar(_)))
| (
&ty::Infer(ty::InferTy::FloatVar(_)),
&ty::Float(_) | &ty::Infer(ty::InferTy::FloatVar(_)),
)
| (&ty::Infer(ty::InferTy::TyVar(_)), _)
| (_, &ty::Infer(ty::InferTy::TyVar(_))) => true,
_ => a == b,
}
}
impl<'a, 'tcx> InferCtxt<'a, 'tcx> { impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
pub fn report_region_errors(&self, errors: &Vec<RegionResolutionError<'tcx>>) { pub fn report_region_errors(&self, errors: &Vec<RegionResolutionError<'tcx>>) {
debug!("report_region_errors(): {} errors to start", errors.len()); debug!("report_region_errors(): {} errors to start", errors.len());
@ -1761,7 +1789,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
self.get_impl_future_output_ty(exp_found.expected), self.get_impl_future_output_ty(exp_found.expected),
self.get_impl_future_output_ty(exp_found.found), self.get_impl_future_output_ty(exp_found.found),
) { ) {
(Some(exp), Some(found)) if ty::TyS::same_type(exp, found) => match &cause.code { (Some(exp), Some(found)) if same_type_modulo_infer(exp, found) => match &cause.code {
ObligationCauseCode::IfExpression(box IfExpressionCause { then, .. }) => { ObligationCauseCode::IfExpression(box IfExpressionCause { then, .. }) => {
diag.multipart_suggestion( diag.multipart_suggestion(
"consider `await`ing on both `Future`s", "consider `await`ing on both `Future`s",
@ -1793,7 +1821,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
diag.help("consider `await`ing on both `Future`s"); diag.help("consider `await`ing on both `Future`s");
} }
}, },
(_, Some(ty)) if ty::TyS::same_type(exp_found.expected, ty) => { (_, Some(ty)) if same_type_modulo_infer(exp_found.expected, ty) => {
diag.span_suggestion_verbose( diag.span_suggestion_verbose(
exp_span.shrink_to_hi(), exp_span.shrink_to_hi(),
"consider `await`ing on the `Future`", "consider `await`ing on the `Future`",
@ -1801,7 +1829,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
); );
} }
(Some(ty), _) if ty::TyS::same_type(ty, exp_found.found) => match cause.code { (Some(ty), _) if same_type_modulo_infer(ty, exp_found.found) => match cause.code {
ObligationCauseCode::Pattern { span: Some(span), .. } ObligationCauseCode::Pattern { span: Some(span), .. }
| ObligationCauseCode::IfExpression(box IfExpressionCause { then: span, .. }) => { | ObligationCauseCode::IfExpression(box IfExpressionCause { then: span, .. }) => {
diag.span_suggestion_verbose( diag.span_suggestion_verbose(

View file

@ -54,4 +54,21 @@ async fn suggest_await_on_match_expr() {
}; };
} }
async fn dummy_result() -> Result<(), ()> {
Ok(())
}
#[allow(unused)]
async fn suggest_await_in_generic_pattern() {
match dummy_result() {
//~^ HELP consider `await`ing on the `Future`
//~| HELP consider `await`ing on the `Future`
//~| SUGGESTION .await
Ok(_) => {}
//~^ ERROR mismatched types [E0308]
Err(_) => {}
//~^ ERROR mismatched types [E0308]
}
}
fn main() {} fn main() {}

View file

@ -106,6 +106,42 @@ help: consider `await`ing on the `Future`
LL | let _x = match dummy().await { LL | let _x = match dummy().await {
| ++++++ | ++++++
error: aborting due to 5 previous errors error[E0308]: mismatched types
--> $DIR/suggest-missing-await.rs:67:9
|
LL | Ok(_) => {}
| ^^^^^ expected opaque type, found enum `Result`
|
note: while checking the return type of the `async fn`
--> $DIR/suggest-missing-await.rs:57:28
|
LL | async fn dummy_result() -> Result<(), ()> {
| ^^^^^^^^^^^^^^ checked the `Output` of this `async fn`, expected opaque type
= note: expected opaque type `impl Future`
found enum `Result<_, _>`
help: consider `await`ing on the `Future`
|
LL | match dummy_result().await {
| ++++++
error[E0308]: mismatched types
--> $DIR/suggest-missing-await.rs:69:9
|
LL | Err(_) => {}
| ^^^^^^ expected opaque type, found enum `Result`
|
note: while checking the return type of the `async fn`
--> $DIR/suggest-missing-await.rs:57:28
|
LL | async fn dummy_result() -> Result<(), ()> {
| ^^^^^^^^^^^^^^ checked the `Output` of this `async fn`, expected opaque type
= note: expected opaque type `impl Future`
found enum `Result<_, _>`
help: consider `await`ing on the `Future`
|
LL | match dummy_result().await {
| ++++++
error: aborting due to 7 previous errors
For more information about this error, try `rustc --explain E0308`. For more information about this error, try `rustc --explain E0308`.