suggest await on unexpected types
This commit is contained in:
parent
2271b081eb
commit
8ee206a80d
@ -50,6 +50,7 @@
|
||||
use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePairs};
|
||||
|
||||
use crate::infer;
|
||||
use crate::infer::OriginalQueryValues;
|
||||
use crate::traits::error_reporting::report_object_safety_error;
|
||||
use crate::traits::{
|
||||
IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
|
||||
@ -60,8 +61,10 @@
|
||||
use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{Item, ItemKind, Node};
|
||||
use rustc_middle::ty::error::TypeError;
|
||||
use rustc_middle::ty::ParamEnvAnd;
|
||||
use rustc_middle::ty::{
|
||||
self,
|
||||
subst::{Subst, SubstsRef},
|
||||
@ -1529,6 +1532,7 @@ enum Mismatch<'a> {
|
||||
};
|
||||
if let Some(exp_found) = exp_found {
|
||||
self.suggest_as_ref_where_appropriate(span, &exp_found, diag);
|
||||
self.suggest_await_on_expect_found(cause, span, &exp_found, diag);
|
||||
}
|
||||
|
||||
// In some (most?) cases cause.body_id points to actual body, but in some cases
|
||||
@ -1547,6 +1551,72 @@ enum Mismatch<'a> {
|
||||
self.note_error_origin(diag, cause, exp_found);
|
||||
}
|
||||
|
||||
fn suggest_await_on_expect_found(
|
||||
&self,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
exp_span: Span,
|
||||
exp_found: &ty::error::ExpectedFound<Ty<'tcx>>,
|
||||
diag: &mut DiagnosticBuilder<'tcx>,
|
||||
) {
|
||||
debug!(
|
||||
"suggest_await_on_expect_found: exp_span={:?}, expected_ty={:?}, found_ty={:?}",
|
||||
exp_span, exp_found.expected, exp_found.found
|
||||
);
|
||||
|
||||
if let ty::Opaque(def_id, _) = exp_found.expected.kind {
|
||||
let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
|
||||
// Future::Output
|
||||
let item_def_id = self
|
||||
.tcx
|
||||
.associated_items(future_trait)
|
||||
.in_definition_order()
|
||||
.next()
|
||||
.unwrap()
|
||||
.def_id;
|
||||
|
||||
let mut projection_ty = None;
|
||||
for (predicate, _) in self.tcx.predicates_of(def_id).predicates {
|
||||
if let ty::PredicateAtom::Projection(projection_predicate) =
|
||||
predicate.skip_binders()
|
||||
{
|
||||
if item_def_id == projection_predicate.projection_ty.item_def_id {
|
||||
projection_ty = Some(projection_predicate.projection_ty);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(projection_ty) = projection_ty {
|
||||
let projection_query = self.canonicalize_query(
|
||||
&ParamEnvAnd { param_env: self.tcx.param_env(def_id), value: projection_ty },
|
||||
&mut OriginalQueryValues::default(),
|
||||
);
|
||||
if let Ok(resp) = self.tcx.normalize_projection_ty(projection_query) {
|
||||
let normalized_ty = resp.value.value.normalized_ty;
|
||||
debug!("suggest_await_on_expect_found: normalized={:?}", normalized_ty);
|
||||
if ty::TyS::same_type(normalized_ty, exp_found.found) {
|
||||
let span = if let ObligationCauseCode::Pattern {
|
||||
span,
|
||||
origin_expr: _,
|
||||
root_ty: _,
|
||||
} = cause.code
|
||||
{
|
||||
// scrutinee's span
|
||||
span.unwrap_or(exp_span)
|
||||
} else {
|
||||
exp_span
|
||||
};
|
||||
diag.span_suggestion_verbose(
|
||||
span.shrink_to_hi(),
|
||||
"consider awaiting on the future",
|
||||
".await".to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// When encountering a case where `.as_ref()` on a `Result` or `Option` would be appropriate,
|
||||
/// suggests it.
|
||||
fn suggest_as_ref_where_appropriate(
|
||||
|
@ -28,7 +28,7 @@ pub fn check_match(
|
||||
};
|
||||
|
||||
// Type check the descriminant and get its type.
|
||||
let scrut_ty = if force_scrutinee_bool {
|
||||
let scrutinee_ty = if force_scrutinee_bool {
|
||||
// Here we want to ensure:
|
||||
//
|
||||
// 1. That default match bindings are *not* accepted in the condition of an
|
||||
@ -55,7 +55,7 @@ pub fn check_match(
|
||||
|
||||
// #55810: Type check patterns first so we get types for all bindings.
|
||||
for arm in arms {
|
||||
self.check_pat_top(&arm.pat, scrut_ty, Some(scrut.span), true);
|
||||
self.check_pat_top(&arm.pat, scrutinee_ty, Some(scrut.span), true);
|
||||
}
|
||||
|
||||
// Now typecheck the blocks.
|
||||
|
@ -1518,7 +1518,7 @@ fn suggest_await_on_field_access(
|
||||
def_id: DefId,
|
||||
) {
|
||||
let param_env = self.tcx().param_env(def_id);
|
||||
let future_trait = self.tcx.require_lang_item(lang_items::FutureTraitLangItem, None);
|
||||
let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
|
||||
// Future::Output
|
||||
let item_def_id =
|
||||
self.tcx.associated_items(future_trait).in_definition_order().next().unwrap().def_id;
|
||||
@ -1554,15 +1554,12 @@ fn suggest_await_on_field_access(
|
||||
);
|
||||
if let ty::Adt(def, _) = normalized_ty.kind {
|
||||
if def.non_enum_variant().fields.iter().any(|field| field.ident == field_ident) {
|
||||
if let Ok(base) = self.tcx.sess.source_map().span_to_snippet(base.span) {
|
||||
let suggestion = format!("{}.await.{}", base, field_ident);
|
||||
err.span_suggestion(
|
||||
expr.span,
|
||||
"consider await before field access",
|
||||
suggestion,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
err.span_suggestion_verbose(
|
||||
base.span.shrink_to_hi(),
|
||||
"consider awaiting before field access",
|
||||
".await".to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -911,15 +911,13 @@ fn suggest_await_before_method(
|
||||
);
|
||||
let method_exists = self.method_exists(item_name, normalized_ty, call.hir_id, true);
|
||||
debug!("suggest_await_before_method: is_method_exist={}", method_exists);
|
||||
if let Ok(sp) = self.tcx.sess.source_map().span_to_snippet(span) {
|
||||
if method_exists {
|
||||
err.span_suggestion(
|
||||
span,
|
||||
"consider await before this method call",
|
||||
format!("await.{}", sp),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
if method_exists {
|
||||
err.span_suggestion_verbose(
|
||||
span.shrink_to_lo(),
|
||||
"consider awaiting before this method call",
|
||||
"await.".to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -64,5 +64,10 @@ async fn baz() -> Result<(), ()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn match_() {
|
||||
match tuple() {
|
||||
Tuple(_) => {} //~ ERROR mismatched types
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -26,28 +26,52 @@ error[E0609]: no field `0` on type `impl std::future::Future`
|
||||
--> $DIR/issue-61076.rs:58:26
|
||||
|
|
||||
LL | let _: i32 = tuple().0;
|
||||
| --------^
|
||||
| |
|
||||
| help: consider await before field access: `tuple().await.0`
|
||||
| ^
|
||||
|
|
||||
help: consider awaiting before field access
|
||||
|
|
||||
LL | let _: i32 = tuple().await.0;
|
||||
| ^^^^^^
|
||||
|
||||
error[E0609]: no field `a` on type `impl std::future::Future`
|
||||
--> $DIR/issue-61076.rs:60:28
|
||||
|
|
||||
LL | let _: i32 = struct_().a;
|
||||
| ----------^
|
||||
| |
|
||||
| help: consider await before field access: `struct_().await.a`
|
||||
| ^
|
||||
|
|
||||
help: consider awaiting before field access
|
||||
|
|
||||
LL | let _: i32 = struct_().await.a;
|
||||
| ^^^^^^
|
||||
|
||||
error[E0599]: no method named `method` found for opaque type `impl std::future::Future` in the current scope
|
||||
--> $DIR/issue-61076.rs:62:15
|
||||
|
|
||||
LL | struct_().method();
|
||||
| ^^^^^^ method not found in `impl std::future::Future`
|
||||
|
|
||||
help: consider awaiting before this method call
|
||||
|
|
||||
LL | struct_().await.method();
|
||||
| ^^^^^^
|
||||
| |
|
||||
| method not found in `impl std::future::Future`
|
||||
| help: consider await before this method call: `await.method`
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/issue-61076.rs:69:9
|
||||
|
|
||||
LL | async fn tuple() -> Tuple {
|
||||
| ----- the `Output` of this `async fn`'s expected opaque type
|
||||
...
|
||||
LL | Tuple(_) => {}
|
||||
| ^^^^^^^^ expected opaque type, found struct `Tuple`
|
||||
|
|
||||
= note: expected opaque type `impl std::future::Future`
|
||||
found struct `Tuple`
|
||||
help: consider awaiting on the future
|
||||
|
|
||||
LL | match tuple().await {
|
||||
| ^^^^^^
|
||||
|
||||
Some errors have detailed explanations: E0277, E0599, E0609.
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0277, E0308, E0599, E0609.
|
||||
For more information about an error, try `rustc --explain E0277`.
|
||||
|
Loading…
Reference in New Issue
Block a user