@@ -31,13 +31,14 @@ use rustc_infer::infer;
31
31
use rustc_infer:: infer:: type_variable:: { TypeVariableOrigin , TypeVariableOriginKind } ;
32
32
use rustc_middle:: ty;
33
33
use rustc_middle:: ty:: adjustment:: { Adjust , Adjustment , AllowTwoPhase } ;
34
+ use rustc_middle:: ty:: subst:: SubstsRef ;
34
35
use rustc_middle:: ty:: Ty ;
35
36
use rustc_middle:: ty:: TypeFoldable ;
36
37
use rustc_middle:: ty:: { AdtKind , Visibility } ;
37
38
use rustc_span:: hygiene:: DesugaringKind ;
38
39
use rustc_span:: source_map:: Span ;
39
40
use rustc_span:: symbol:: { kw, sym, Ident , Symbol } ;
40
- use rustc_trait_selection:: traits:: { self , ObligationCauseCode } ;
41
+ use rustc_trait_selection:: traits:: { self , ObligationCauseCode , SelectionContext } ;
41
42
42
43
use std:: fmt:: Display ;
43
44
@@ -1509,13 +1510,81 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1509
1510
self . tcx ( ) . ty_error ( )
1510
1511
}
1511
1512
1513
+ fn suggest_await_on_field_access (
1514
+ & self ,
1515
+ err : & mut DiagnosticBuilder < ' _ > ,
1516
+ field_ident : Ident ,
1517
+ base : & ' tcx hir:: Expr < ' tcx > ,
1518
+ expr : & ' tcx hir:: Expr < ' tcx > ,
1519
+ def_id : DefId ,
1520
+ substs : SubstsRef < ' tcx > ,
1521
+ ) {
1522
+ let param_env = self . tcx ( ) . param_env ( def_id) ;
1523
+ let future_trait = self . tcx . require_lang_item ( lang_items:: FutureTraitLangItem , None ) ;
1524
+ let future_trait_ref = ty:: TraitRef { def_id : future_trait, substs } ;
1525
+ // Future::Output
1526
+ let future_projection = ty:: ProjectionTy :: from_ref_and_name (
1527
+ self . tcx ,
1528
+ future_trait_ref,
1529
+ Ident :: with_dummy_span ( sym:: Output ) ,
1530
+ ) ;
1531
+
1532
+ let mut projection_ty = None ;
1533
+ for ( predicate, _) in self . tcx . predicates_of ( def_id) . predicates {
1534
+ if let ty:: PredicateAtom :: Projection ( projection_predicate) = predicate. skip_binders ( ) {
1535
+ if future_projection. item_def_id == projection_predicate. projection_ty . item_def_id {
1536
+ projection_ty = Some ( projection_predicate. projection_ty ) ;
1537
+ break ;
1538
+ }
1539
+ }
1540
+ }
1541
+ debug ! ( "suggest_await_on_field_access: projection_ty={:?}" , projection_ty) ;
1542
+
1543
+ let cause = self . misc ( expr. span ) ;
1544
+ let mut selcx = SelectionContext :: new ( & self . infcx ) ;
1545
+
1546
+ let mut obligations = vec ! [ ] ;
1547
+ if let Some ( projection_ty) = projection_ty {
1548
+ let normalized_ty = rustc_trait_selection:: traits:: normalize_projection_type (
1549
+ & mut selcx,
1550
+ param_env,
1551
+ projection_ty,
1552
+ cause,
1553
+ 0 ,
1554
+ & mut obligations,
1555
+ ) ;
1556
+ debug ! (
1557
+ "suggest_await_on_field_access: normalized_ty={:?}, ty_kind={:?}" ,
1558
+ self . resolve_vars_if_possible( & normalized_ty) ,
1559
+ normalized_ty. kind,
1560
+ ) ;
1561
+ if let ty:: Adt ( def, _) = normalized_ty. kind {
1562
+ if def. non_enum_variant ( ) . fields . iter ( ) . any ( |field| field. ident == field_ident) {
1563
+ if let Ok ( base) = self . tcx . sess . source_map ( ) . span_to_snippet ( base. span ) {
1564
+ let suggestion = format ! ( "{}.await.{}" , base, field_ident) ;
1565
+ err. span_suggestion (
1566
+ expr. span ,
1567
+ "consider await before field access" ,
1568
+ suggestion,
1569
+ Applicability :: MaybeIncorrect ,
1570
+ ) ;
1571
+ }
1572
+ }
1573
+ }
1574
+ }
1575
+ }
1576
+
1512
1577
fn ban_nonexisting_field (
1513
1578
& self ,
1514
1579
field : Ident ,
1515
1580
base : & ' tcx hir:: Expr < ' tcx > ,
1516
1581
expr : & ' tcx hir:: Expr < ' tcx > ,
1517
1582
expr_t : Ty < ' tcx > ,
1518
1583
) {
1584
+ debug ! (
1585
+ "ban_nonexisting_field: field={:?}, base={:?}, expr={:?}, expr_ty={:?}" ,
1586
+ field, base, expr, expr_t
1587
+ ) ;
1519
1588
let mut err = self . no_such_field_err ( field. span , field, expr_t) ;
1520
1589
1521
1590
match expr_t. peel_refs ( ) . kind {
@@ -1531,6 +1600,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1531
1600
ty:: Param ( param_ty) => {
1532
1601
self . point_at_param_definition ( & mut err, param_ty) ;
1533
1602
}
1603
+ ty:: Opaque ( def_id, subts) => {
1604
+ self . suggest_await_on_field_access ( & mut err, field, base, expr, def_id, subts) ;
1605
+ }
1534
1606
_ => { }
1535
1607
}
1536
1608
0 commit comments