about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_infer/infer/error_reporting/mod.rs70
-rw-r--r--src/librustc_typeck/check/_match.rs4
-rw-r--r--src/librustc_typeck/check/expr.rs17
-rw-r--r--src/librustc_typeck/check/method/suggest.rs16
-rw-r--r--src/test/ui/async-await/issue-61076.rs5
-rw-r--r--src/test/ui/async-await/issue-61076.stderr46
6 files changed, 126 insertions, 32 deletions
diff --git a/src/librustc_infer/infer/error_reporting/mod.rs b/src/librustc_infer/infer/error_reporting/mod.rs
index 8212958510a..35b2d7e8468 100644
--- a/src/librustc_infer/infer/error_reporting/mod.rs
+++ b/src/librustc_infer/infer/error_reporting/mod.rs
@@ -50,6 +50,7 @@ use super::region_constraints::GenericKind;
 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::{pluralize, struct_span_err};
 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 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         };
         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 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         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(
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 40088bc0690..afd4413069e 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -28,7 +28,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         };
 
         // 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 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         // #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.
diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs
index 0f2e4240c01..702dc30957c 100644
--- a/src/librustc_typeck/check/expr.rs
+++ b/src/librustc_typeck/check/expr.rs
@@ -1518,7 +1518,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         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 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             );
             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,
+                    );
                 }
             }
         }
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index 8451918568d..3dd4c7c1439 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -911,15 +911,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 );
                 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,
+                    );
                 }
             }
         }
diff --git a/src/test/ui/async-await/issue-61076.rs b/src/test/ui/async-await/issue-61076.rs
index 743f1959828..e383a9126f7 100644
--- a/src/test/ui/async-await/issue-61076.rs
+++ b/src/test/ui/async-await/issue-61076.rs
@@ -64,5 +64,10 @@ async fn baz() -> Result<(), ()> {
     Ok(())
 }
 
+async fn match_() {
+    match tuple() {
+        Tuple(_) => {} //~ ERROR mismatched types
+    }
+}
 
 fn main() {}
diff --git a/src/test/ui/async-await/issue-61076.stderr b/src/test/ui/async-await/issue-61076.stderr
index 692117a06b0..69b6e8c3cf5 100644
--- a/src/test/ui/async-await/issue-61076.stderr
+++ b/src/test/ui/async-await/issue-61076.stderr
@@ -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 {
+   |                  ^^^^^^
+
+error: aborting due to 6 previous errors
 
-Some errors have detailed explanations: E0277, E0599, E0609.
+Some errors have detailed explanations: E0277, E0308, E0599, E0609.
 For more information about an error, try `rustc --explain E0277`.