@@ -50,6 +50,7 @@ use super::region_constraints::GenericKind;
50
50
use super :: { InferCtxt , RegionVariableOrigin , SubregionOrigin , TypeTrace , ValuePairs } ;
51
51
52
52
use crate :: infer;
53
+ use crate :: infer:: OriginalQueryValues ;
53
54
use crate :: traits:: error_reporting:: report_object_safety_error;
54
55
use crate :: traits:: {
55
56
IfExpressionCause , MatchExpressionArmCause , ObligationCause , ObligationCauseCode ,
@@ -60,8 +61,10 @@ use rustc_errors::{pluralize, struct_span_err};
60
61
use rustc_errors:: { Applicability , DiagnosticBuilder , DiagnosticStyledString } ;
61
62
use rustc_hir as hir;
62
63
use rustc_hir:: def_id:: DefId ;
64
+ use rustc_hir:: lang_items:: LangItem ;
63
65
use rustc_hir:: { Item , ItemKind , Node } ;
64
66
use rustc_middle:: ty:: error:: TypeError ;
67
+ use rustc_middle:: ty:: ParamEnvAnd ;
65
68
use rustc_middle:: ty:: {
66
69
self ,
67
70
subst:: { Subst , SubstsRef } ,
@@ -1529,6 +1532,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
1529
1532
} ;
1530
1533
if let Some ( exp_found) = exp_found {
1531
1534
self . suggest_as_ref_where_appropriate ( span, & exp_found, diag) ;
1535
+ self . suggest_await_on_expect_found ( cause, span, & exp_found, diag) ;
1532
1536
}
1533
1537
1534
1538
// 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> {
1547
1551
self . note_error_origin ( diag, cause, exp_found) ;
1548
1552
}
1549
1553
1554
+ fn suggest_await_on_expect_found (
1555
+ & self ,
1556
+ cause : & ObligationCause < ' tcx > ,
1557
+ exp_span : Span ,
1558
+ exp_found : & ty:: error:: ExpectedFound < Ty < ' tcx > > ,
1559
+ diag : & mut DiagnosticBuilder < ' tcx > ,
1560
+ ) {
1561
+ debug ! (
1562
+ "suggest_await_on_expect_found: exp_span={:?}, expected_ty={:?}, found_ty={:?}" ,
1563
+ exp_span, exp_found. expected, exp_found. found
1564
+ ) ;
1565
+
1566
+ if let ty:: Opaque ( def_id, _) = exp_found. expected . kind {
1567
+ let future_trait = self . tcx . require_lang_item ( LangItem :: Future , None ) ;
1568
+ // Future::Output
1569
+ let item_def_id = self
1570
+ . tcx
1571
+ . associated_items ( future_trait)
1572
+ . in_definition_order ( )
1573
+ . next ( )
1574
+ . unwrap ( )
1575
+ . def_id ;
1576
+
1577
+ let mut projection_ty = None ;
1578
+ for ( predicate, _) in self . tcx . predicates_of ( def_id) . predicates {
1579
+ if let ty:: PredicateAtom :: Projection ( projection_predicate) =
1580
+ predicate. skip_binders ( )
1581
+ {
1582
+ if item_def_id == projection_predicate. projection_ty . item_def_id {
1583
+ projection_ty = Some ( projection_predicate. projection_ty ) ;
1584
+ break ;
1585
+ }
1586
+ }
1587
+ }
1588
+ if let Some ( projection_ty) = projection_ty {
1589
+ let projection_query = self . canonicalize_query (
1590
+ & ParamEnvAnd { param_env : self . tcx . param_env ( def_id) , value : projection_ty } ,
1591
+ & mut OriginalQueryValues :: default ( ) ,
1592
+ ) ;
1593
+ if let Ok ( resp) = self . tcx . normalize_projection_ty ( projection_query) {
1594
+ let normalized_ty = resp. value . value . normalized_ty ;
1595
+ debug ! ( "suggest_await_on_expect_found: normalized={:?}" , normalized_ty) ;
1596
+ if ty:: TyS :: same_type ( normalized_ty, exp_found. found ) {
1597
+ let span = if let ObligationCauseCode :: Pattern {
1598
+ span,
1599
+ origin_expr : _,
1600
+ root_ty : _,
1601
+ } = cause. code
1602
+ {
1603
+ // scrutinee's span
1604
+ span. unwrap_or ( exp_span)
1605
+ } else {
1606
+ exp_span
1607
+ } ;
1608
+ diag. span_suggestion_verbose (
1609
+ span. shrink_to_hi ( ) ,
1610
+ "consider awaiting on the future" ,
1611
+ ".await" . to_string ( ) ,
1612
+ Applicability :: MaybeIncorrect ,
1613
+ ) ;
1614
+ }
1615
+ }
1616
+ }
1617
+ }
1618
+ }
1619
+
1550
1620
/// When encountering a case where `.as_ref()` on a `Result` or `Option` would be appropriate,
1551
1621
/// suggests it.
1552
1622
fn suggest_as_ref_where_appropriate (
0 commit comments