@@ -126,13 +126,14 @@ crate trait InferCtxtExt<'tcx> {
126126 scope_span : & Option < Span > ,
127127 expr : Option < hir:: HirId > ,
128128 snippet : String ,
129- inner_generator : DefId ,
129+ inner_generator_body : Option < & hir :: Body < ' _ > > ,
130130 outer_generator : Option < DefId > ,
131131 trait_ref : ty:: TraitRef < ' _ > ,
132132 target_ty : Ty < ' tcx > ,
133133 tables : & ty:: TypeckTables < ' _ > ,
134134 obligation : & PredicateObligation < ' tcx > ,
135135 next_code : Option < & ObligationCauseCode < ' tcx > > ,
136+ from_awaited_ty : Option < Span > ,
136137 ) ;
137138
138139 fn note_obligation_cause_code < T > (
@@ -1088,6 +1089,17 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
10881089 }
10891090 } ;
10901091
1092+ let generator_body = self . tcx
1093+ . hir ( )
1094+ . as_local_hir_id ( generator_did)
1095+ . and_then ( |hir_id| self . tcx . hir ( ) . maybe_body_owned_by ( hir_id) )
1096+ . map ( |body_id| self . tcx . hir ( ) . body ( body_id) ) ;
1097+ let mut visitor = AwaitsVisitor :: default ( ) ;
1098+ if let Some ( body) = generator_body {
1099+ visitor. visit_body ( body) ;
1100+ }
1101+ debug ! ( "maybe_note_obligation_cause_for_async_await: awaits = {:?}" , visitor. awaits) ;
1102+
10911103 // Look for a type inside the generator interior that matches the target type to get
10921104 // a span.
10931105 let target_ty_erased = self . tcx . erase_regions ( & target_ty) ;
@@ -1117,29 +1129,48 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
11171129 ) ;
11181130 eq
11191131 } )
1120- . map ( |ty:: GeneratorInteriorTypeCause { span, scope_span, expr, .. } | {
1121- ( span, source_map. span_to_snippet ( * span) , scope_span, expr)
1132+ . map ( |cause| {
1133+ // Check to see if any awaited expressions have the target type.
1134+ let from_awaited_ty = visitor. awaits . into_iter ( )
1135+ . map ( |id| self . tcx . hir ( ) . expect_expr ( id) )
1136+ . find ( |expr| {
1137+ let ty = tables. expr_ty_adjusted ( & expr) ;
1138+ // Compare types using the same logic as above.
1139+ let ty_erased = self . tcx . erase_late_bound_regions ( & ty:: Binder :: bind ( ty) ) ;
1140+ let ty_erased = self . tcx . erase_regions ( & ty_erased) ;
1141+ let eq = ty:: TyS :: same_type ( ty_erased, target_ty_erased) ;
1142+ debug ! (
1143+ "maybe_note_obligation_cause_for_async_await: await_expr={:?} \
1144+ await_ty_erased={:?} target_ty_erased={:?} eq={:?}",
1145+ expr, ty_erased, target_ty_erased, eq
1146+ ) ;
1147+ eq
1148+ } )
1149+ . map ( |expr| expr. span ) ;
1150+ let ty:: GeneratorInteriorTypeCause { span, scope_span, expr, .. } = cause;
1151+ ( span, source_map. span_to_snippet ( * span) , scope_span, expr, from_awaited_ty)
11221152 } ) ;
11231153
11241154 debug ! (
11251155 "maybe_note_obligation_cause_for_async_await: target_ty={:?} \
11261156 generator_interior_types={:?} target_span={:?}",
11271157 target_ty, tables. generator_interior_types, target_span
11281158 ) ;
1129- if let Some ( ( target_span, Ok ( snippet) , scope_span, expr) ) = target_span {
1159+ if let Some ( ( target_span, Ok ( snippet) , scope_span, expr, from_awaited_ty ) ) = target_span {
11301160 self . note_obligation_cause_for_async_await (
11311161 err,
11321162 * target_span,
11331163 scope_span,
11341164 * expr,
11351165 snippet,
1136- generator_did ,
1166+ generator_body ,
11371167 outer_generator,
11381168 trait_ref,
11391169 target_ty,
11401170 tables,
11411171 obligation,
11421172 next_code,
1173+ from_awaited_ty,
11431174 ) ;
11441175 true
11451176 } else {
@@ -1156,22 +1187,18 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
11561187 scope_span : & Option < Span > ,
11571188 expr : Option < hir:: HirId > ,
11581189 snippet : String ,
1159- inner_generator : DefId ,
1190+ inner_generator_body : Option < & hir :: Body < ' _ > > ,
11601191 outer_generator : Option < DefId > ,
11611192 trait_ref : ty:: TraitRef < ' _ > ,
11621193 target_ty : Ty < ' tcx > ,
11631194 tables : & ty:: TypeckTables < ' _ > ,
11641195 obligation : & PredicateObligation < ' tcx > ,
11651196 next_code : Option < & ObligationCauseCode < ' tcx > > ,
1197+ from_awaited_ty : Option < Span > ,
11661198 ) {
11671199 let source_map = self . tcx . sess . source_map ( ) ;
11681200
1169- let is_async = self
1170- . tcx
1171- . hir ( )
1172- . as_local_hir_id ( inner_generator)
1173- . and_then ( |hir_id| self . tcx . hir ( ) . maybe_body_owned_by ( hir_id) )
1174- . map ( |body_id| self . tcx . hir ( ) . body ( body_id) )
1201+ let is_async = inner_generator_body
11751202 . and_then ( |body| body. generator_kind ( ) )
11761203 . map ( |generator_kind| match generator_kind {
11771204 hir:: GeneratorKind :: Async ( ..) => true ,
@@ -1230,33 +1257,57 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
12301257 )
12311258 } ;
12321259
1233- // Look at the last interior type to get a span for the `.await`.
1234- let await_span = tables. generator_interior_types . iter ( ) . map ( |t| t. span ) . last ( ) . unwrap ( ) ;
1235- let mut span = MultiSpan :: from_span ( await_span) ;
1236- span. push_span_label (
1237- await_span,
1238- format ! ( "{} occurs here, with `{}` maybe used later" , await_or_yield, snippet) ,
1239- ) ;
1260+ let push_target_span = |span : & mut MultiSpan | {
1261+ if target_ty. is_impl_trait ( ) {
1262+ // It's not very useful to tell the user the type if it's opaque.
1263+ span. push_span_label ( target_span, "created here" . to_string ( ) ) ;
1264+ } else {
1265+ span. push_span_label ( target_span, format ! ( "has type `{}`" , target_ty) ) ;
1266+ }
1267+ } ;
12401268
1241- if target_ty. is_impl_trait ( ) {
1242- // It's not very useful to tell the user the type if it's opaque.
1243- span. push_span_label ( target_span, "created here" . to_string ( ) ) ;
1244- } else {
1245- span. push_span_label ( target_span, format ! ( "has type `{}`" , target_ty) ) ;
1246- }
1269+ if let Some ( await_span) = from_awaited_ty {
1270+ // The type causing this obligation is one being awaited at await_span.
1271+ let mut span = MultiSpan :: from_span ( await_span) ;
1272+ span. push_span_label (
1273+ await_span,
1274+ "await occurs here" . to_string ( ) ,
1275+ ) ;
1276+
1277+ push_target_span ( & mut span) ;
12471278
1248- // If available, use the scope span to annotate the drop location.
1249- if let Some ( scope_span) = scope_span {
1279+ err. span_note (
1280+ span,
1281+ & format ! ( "{} as this value is used in an await" , trait_explanation) ,
1282+ ) ;
1283+ } else {
1284+ // Look at the last interior type to get a span for the `.await`.
1285+ debug ! (
1286+ "note_obligation_cause_for_async_await generator_interior_types: {:#?}" ,
1287+ tables. generator_interior_types
1288+ ) ;
1289+ let await_span = tables. generator_interior_types . iter ( ) . map ( |t| t. span ) . last ( ) . unwrap ( ) ;
1290+ let mut span = MultiSpan :: from_span ( await_span) ;
12501291 span. push_span_label (
1251- source_map . end_point ( * scope_span ) ,
1252- format ! ( "`{}` is later dropped here" , snippet) ,
1292+ await_span ,
1293+ format ! ( "{} occurs here, with `{}` maybe used later" , await_or_yield , snippet) ,
12531294 ) ;
1254- }
12551295
1256- err. span_note (
1257- span,
1258- & format ! ( "{} as this value is used across an {}" , trait_explanation, await_or_yield) ,
1259- ) ;
1296+ push_target_span ( & mut span) ;
1297+
1298+ // If available, use the scope span to annotate the drop location.
1299+ if let Some ( scope_span) = scope_span {
1300+ span. push_span_label (
1301+ source_map. end_point ( * scope_span) ,
1302+ format ! ( "`{}` is later dropped here" , snippet) ,
1303+ ) ;
1304+ }
1305+
1306+ err. span_note (
1307+ span,
1308+ & format ! ( "{} as this value is used across an {}" , trait_explanation, await_or_yield) ,
1309+ ) ;
1310+ }
12601311
12611312 if let Some ( expr_id) = expr {
12621313 let expr = hir. expect_expr ( expr_id) ;
@@ -1593,3 +1644,26 @@ impl<'v> Visitor<'v> for ReturnsVisitor<'v> {
15931644 hir:: intravisit:: walk_body ( self , body) ;
15941645 }
15951646}
1647+
1648+ /// Collect all the awaited expressions within the input expression.
1649+ #[ derive( Default ) ]
1650+ struct AwaitsVisitor {
1651+ awaits : Vec < hir:: HirId > ,
1652+ }
1653+
1654+ impl < ' v > Visitor < ' v > for AwaitsVisitor {
1655+ type Map = hir:: intravisit:: ErasedMap < ' v > ;
1656+
1657+ fn nested_visit_map ( & mut self ) -> hir:: intravisit:: NestedVisitorMap < Self :: Map > {
1658+ hir:: intravisit:: NestedVisitorMap :: None
1659+ }
1660+
1661+ fn visit_expr ( & mut self , ex : & ' v hir:: Expr < ' v > ) {
1662+ match ex. kind {
1663+ hir:: ExprKind :: Yield ( _, hir:: YieldSource :: Await { expr : Some ( id) } ) =>
1664+ self . awaits . push ( id) ,
1665+ _ => ( ) ,
1666+ }
1667+ hir:: intravisit:: walk_expr ( self , ex)
1668+ }
1669+ }
0 commit comments