@@ -127,13 +127,14 @@ pub trait InferCtxtExt<'tcx> {
127
127
scope_span : & Option < Span > ,
128
128
expr : Option < hir:: HirId > ,
129
129
snippet : String ,
130
- inner_generator : DefId ,
130
+ inner_generator_body : Option < & hir :: Body < ' _ > > ,
131
131
outer_generator : Option < DefId > ,
132
132
trait_ref : ty:: TraitRef < ' _ > ,
133
133
target_ty : Ty < ' tcx > ,
134
134
tables : & ty:: TypeckTables < ' _ > ,
135
135
obligation : & PredicateObligation < ' tcx > ,
136
136
next_code : Option < & ObligationCauseCode < ' tcx > > ,
137
+ from_awaited_ty : Option < Span > ,
137
138
) ;
138
139
139
140
fn note_obligation_cause_code < T > (
@@ -1203,6 +1204,17 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
1203
1204
}
1204
1205
} ;
1205
1206
1207
+ let generator_body = self . tcx
1208
+ . hir ( )
1209
+ . as_local_hir_id ( generator_did)
1210
+ . and_then ( |hir_id| self . tcx . hir ( ) . maybe_body_owned_by ( hir_id) )
1211
+ . map ( |body_id| self . tcx . hir ( ) . body ( body_id) ) ;
1212
+ let mut visitor = AwaitsVisitor :: default ( ) ;
1213
+ if let Some ( body) = generator_body {
1214
+ visitor. visit_body ( body) ;
1215
+ }
1216
+ debug ! ( "maybe_note_obligation_cause_for_async_await: awaits = {:?}" , visitor. awaits) ;
1217
+
1206
1218
// Look for a type inside the generator interior that matches the target type to get
1207
1219
// a span.
1208
1220
let target_ty_erased = self . tcx . erase_regions ( & target_ty) ;
@@ -1232,29 +1244,48 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
1232
1244
) ;
1233
1245
eq
1234
1246
} )
1235
- . map ( |ty:: GeneratorInteriorTypeCause { span, scope_span, expr, .. } | {
1236
- ( span, source_map. span_to_snippet ( * span) , scope_span, expr)
1247
+ . map ( |cause| {
1248
+ // Check to see if any awaited expressions have the target type.
1249
+ let from_awaited_ty = visitor. awaits . into_iter ( )
1250
+ . map ( |id| self . tcx . hir ( ) . expect_expr ( id) )
1251
+ . find ( |expr| {
1252
+ let ty = tables. expr_ty_adjusted ( & expr) ;
1253
+ // Compare types using the same logic as above.
1254
+ let ty_erased = self . tcx . erase_late_bound_regions ( & ty:: Binder :: bind ( ty) ) ;
1255
+ let ty_erased = self . tcx . erase_regions ( & ty_erased) ;
1256
+ let eq = ty:: TyS :: same_type ( ty_erased, target_ty_erased) ;
1257
+ debug ! (
1258
+ "maybe_note_obligation_cause_for_async_await: await_expr={:?} \
1259
+ await_ty_erased={:?} target_ty_erased={:?} eq={:?}",
1260
+ expr, ty_erased, target_ty_erased, eq
1261
+ ) ;
1262
+ eq
1263
+ } )
1264
+ . map ( |expr| expr. span ) ;
1265
+ let ty:: GeneratorInteriorTypeCause { span, scope_span, expr, .. } = cause;
1266
+ ( span, source_map. span_to_snippet ( * span) , scope_span, expr, from_awaited_ty)
1237
1267
} ) ;
1238
1268
1239
1269
debug ! (
1240
1270
"maybe_note_obligation_cause_for_async_await: target_ty={:?} \
1241
1271
generator_interior_types={:?} target_span={:?}",
1242
1272
target_ty, tables. generator_interior_types, target_span
1243
1273
) ;
1244
- if let Some ( ( target_span, Ok ( snippet) , scope_span, expr) ) = target_span {
1274
+ if let Some ( ( target_span, Ok ( snippet) , scope_span, expr, from_awaited_ty ) ) = target_span {
1245
1275
self . note_obligation_cause_for_async_await (
1246
1276
err,
1247
1277
* target_span,
1248
1278
scope_span,
1249
1279
* expr,
1250
1280
snippet,
1251
- generator_did ,
1281
+ generator_body ,
1252
1282
outer_generator,
1253
1283
trait_ref,
1254
1284
target_ty,
1255
1285
tables,
1256
1286
obligation,
1257
1287
next_code,
1288
+ from_awaited_ty,
1258
1289
) ;
1259
1290
true
1260
1291
} else {
@@ -1271,22 +1302,18 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
1271
1302
scope_span : & Option < Span > ,
1272
1303
expr : Option < hir:: HirId > ,
1273
1304
snippet : String ,
1274
- inner_generator : DefId ,
1305
+ inner_generator_body : Option < & hir :: Body < ' _ > > ,
1275
1306
outer_generator : Option < DefId > ,
1276
1307
trait_ref : ty:: TraitRef < ' _ > ,
1277
1308
target_ty : Ty < ' tcx > ,
1278
1309
tables : & ty:: TypeckTables < ' _ > ,
1279
1310
obligation : & PredicateObligation < ' tcx > ,
1280
1311
next_code : Option < & ObligationCauseCode < ' tcx > > ,
1312
+ from_awaited_ty : Option < Span > ,
1281
1313
) {
1282
1314
let source_map = self . tcx . sess . source_map ( ) ;
1283
1315
1284
- let is_async = self
1285
- . tcx
1286
- . hir ( )
1287
- . as_local_hir_id ( inner_generator)
1288
- . and_then ( |hir_id| self . tcx . hir ( ) . maybe_body_owned_by ( hir_id) )
1289
- . map ( |body_id| self . tcx . hir ( ) . body ( body_id) )
1316
+ let is_async = inner_generator_body
1290
1317
. and_then ( |body| body. generator_kind ( ) )
1291
1318
. map ( |generator_kind| match generator_kind {
1292
1319
hir:: GeneratorKind :: Async ( ..) => true ,
@@ -1345,33 +1372,57 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
1345
1372
)
1346
1373
} ;
1347
1374
1348
- // Look at the last interior type to get a span for the `.await`.
1349
- let await_span = tables. generator_interior_types . iter ( ) . map ( |t| t. span ) . last ( ) . unwrap ( ) ;
1350
- let mut span = MultiSpan :: from_span ( await_span) ;
1351
- span. push_span_label (
1352
- await_span,
1353
- format ! ( "{} occurs here, with `{}` maybe used later" , await_or_yield, snippet) ,
1354
- ) ;
1375
+ let push_target_span = |span : & mut MultiSpan | {
1376
+ if target_ty. is_impl_trait ( ) {
1377
+ // It's not very useful to tell the user the type if it's opaque.
1378
+ span. push_span_label ( target_span, "created here" . to_string ( ) ) ;
1379
+ } else {
1380
+ span. push_span_label ( target_span, format ! ( "has type `{}`" , target_ty) ) ;
1381
+ }
1382
+ } ;
1355
1383
1356
- if target_ty. is_impl_trait ( ) {
1357
- // It's not very useful to tell the user the type if it's opaque.
1358
- span. push_span_label ( target_span, "created here" . to_string ( ) ) ;
1359
- } else {
1360
- span. push_span_label ( target_span, format ! ( "has type `{}`" , target_ty) ) ;
1361
- }
1384
+ if let Some ( await_span) = from_awaited_ty {
1385
+ // The type causing this obligation is one being awaited at await_span.
1386
+ let mut span = MultiSpan :: from_span ( await_span) ;
1387
+ span. push_span_label (
1388
+ await_span,
1389
+ "await occurs here" . to_string ( ) ,
1390
+ ) ;
1391
+
1392
+ push_target_span ( & mut span) ;
1362
1393
1363
- // If available, use the scope span to annotate the drop location.
1364
- if let Some ( scope_span) = scope_span {
1394
+ err. span_note (
1395
+ span,
1396
+ & format ! ( "{} as this value is used in an await" , trait_explanation) ,
1397
+ ) ;
1398
+ } else {
1399
+ // Look at the last interior type to get a span for the `.await`.
1400
+ debug ! (
1401
+ "note_obligation_cause_for_async_await generator_interior_types: {:#?}" ,
1402
+ tables. generator_interior_types
1403
+ ) ;
1404
+ let await_span = tables. generator_interior_types . iter ( ) . map ( |t| t. span ) . last ( ) . unwrap ( ) ;
1405
+ let mut span = MultiSpan :: from_span ( await_span) ;
1365
1406
span. push_span_label (
1366
- source_map . end_point ( * scope_span ) ,
1367
- format ! ( "`{}` is later dropped here" , snippet) ,
1407
+ await_span ,
1408
+ format ! ( "{} occurs here, with `{}` maybe used later" , await_or_yield , snippet) ,
1368
1409
) ;
1369
- }
1370
1410
1371
- err. span_note (
1372
- span,
1373
- & format ! ( "{} as this value is used across an {}" , trait_explanation, await_or_yield) ,
1374
- ) ;
1411
+ push_target_span ( & mut span) ;
1412
+
1413
+ // If available, use the scope span to annotate the drop location.
1414
+ if let Some ( scope_span) = scope_span {
1415
+ span. push_span_label (
1416
+ source_map. end_point ( * scope_span) ,
1417
+ format ! ( "`{}` is later dropped here" , snippet) ,
1418
+ ) ;
1419
+ }
1420
+
1421
+ err. span_note (
1422
+ span,
1423
+ & format ! ( "{} as this value is used across an {}" , trait_explanation, await_or_yield) ,
1424
+ ) ;
1425
+ }
1375
1426
1376
1427
if let Some ( expr_id) = expr {
1377
1428
let expr = hir. expect_expr ( expr_id) ;
@@ -1716,6 +1767,29 @@ impl<'v> Visitor<'v> for ReturnsVisitor<'v> {
1716
1767
}
1717
1768
}
1718
1769
1770
+ /// Collect all the awaited expressions within the input expression.
1771
+ #[ derive( Default ) ]
1772
+ struct AwaitsVisitor {
1773
+ awaits : Vec < hir:: HirId > ,
1774
+ }
1775
+
1776
+ impl < ' v > Visitor < ' v > for AwaitsVisitor {
1777
+ type Map = hir:: intravisit:: ErasedMap < ' v > ;
1778
+
1779
+ fn nested_visit_map ( & mut self ) -> hir:: intravisit:: NestedVisitorMap < Self :: Map > {
1780
+ hir:: intravisit:: NestedVisitorMap :: None
1781
+ }
1782
+
1783
+ fn visit_expr ( & mut self , ex : & ' v hir:: Expr < ' v > ) {
1784
+ match ex. kind {
1785
+ hir:: ExprKind :: Yield ( _, hir:: YieldSource :: Await { expr : Some ( id) } ) =>
1786
+ self . awaits . push ( id) ,
1787
+ _ => ( ) ,
1788
+ }
1789
+ hir:: intravisit:: walk_expr ( self , ex)
1790
+ }
1791
+ }
1792
+
1719
1793
pub trait NextTypeParamName {
1720
1794
fn next_type_param_name ( & self , name : Option < & str > ) -> String ;
1721
1795
}
0 commit comments