@@ -125,19 +125,15 @@ pub trait InferCtxtExt<'tcx> {
125
125
fn note_obligation_cause_for_async_await (
126
126
& self ,
127
127
err : & mut DiagnosticBuilder < ' _ > ,
128
- target_span : Span ,
129
- scope_span : & Option < Span > ,
130
- yield_span : Option < Span > ,
131
- expr : Option < hir:: HirId > ,
132
- snippet : String ,
128
+ interior : Option < ( Span , Option < Span > , Option < Span > , Option < hir:: HirId > , Option < Span > ) > ,
129
+ upvar : Option < ( Ty < ' tcx > , Span ) > ,
133
130
inner_generator_body : Option < & hir:: Body < ' _ > > ,
134
131
outer_generator : Option < DefId > ,
135
132
trait_ref : ty:: TraitRef < ' _ > ,
136
133
target_ty : Ty < ' tcx > ,
137
134
tables : & ty:: TypeckTables < ' _ > ,
138
135
obligation : & PredicateObligation < ' tcx > ,
139
136
next_code : Option < & ObligationCauseCode < ' tcx > > ,
140
- from_awaited_ty : Option < Span > ,
141
137
) ;
142
138
143
139
fn note_obligation_cause_code < T > (
@@ -1136,7 +1132,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
1136
1132
obligation.cause.span={:?}",
1137
1133
obligation. predicate, obligation. cause. span
1138
1134
) ;
1139
- let source_map = self . tcx . sess . source_map ( ) ;
1140
1135
let hir = self . tcx . hir ( ) ;
1141
1136
1142
1137
// Attempt to detect an async-await error by looking at the obligation causes, looking
@@ -1173,6 +1168,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
1173
1168
} ;
1174
1169
let mut generator = None ;
1175
1170
let mut outer_generator = None ;
1171
+ let mut generator_substs = None ;
1176
1172
let mut next_code = Some ( & obligation. cause . code ) ;
1177
1173
while let Some ( code) = next_code {
1178
1174
debug ! ( "maybe_note_obligation_cause_for_async_await: code={:?}" , code) ;
@@ -1188,8 +1184,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
1188
1184
) ;
1189
1185
1190
1186
match ty. kind {
1191
- ty:: Generator ( did, ..) => {
1187
+ ty:: Generator ( did, substs , ..) => {
1192
1188
generator = generator. or ( Some ( did) ) ;
1189
+ generator_substs = generator_substs. or ( Some ( substs) ) ;
1193
1190
outer_generator = Some ( did) ;
1194
1191
}
1195
1192
ty:: GeneratorWitness ( ..) => { }
@@ -1212,12 +1209,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
1212
1209
target_ty={:?}",
1213
1210
generator, trait_ref, target_ty
1214
1211
) ;
1215
- let ( generator_did, trait_ref, target_ty) = match ( generator, trait_ref, target_ty) {
1216
- ( Some ( generator_did) , Some ( trait_ref) , Some ( target_ty) ) => {
1217
- ( generator_did, trait_ref, target_ty)
1218
- }
1219
- _ => return false ,
1220
- } ;
1212
+ let ( generator_did, _generator_substs, trait_ref, target_ty) =
1213
+ match ( generator, generator_substs, trait_ref, target_ty) {
1214
+ ( Some ( generator_did) , Some ( generator_substs) , Some ( trait_ref) , Some ( target_ty) ) => {
1215
+ ( generator_did, generator_substs, trait_ref, target_ty)
1216
+ }
1217
+ _ => return false ,
1218
+ } ;
1221
1219
1222
1220
let span = self . tcx . def_span ( generator_did) ;
1223
1221
@@ -1285,7 +1283,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
1285
1283
) ;
1286
1284
eq
1287
1285
} ;
1288
- let target_span = tables
1286
+ let interior = tables
1289
1287
. generator_interior_types
1290
1288
. iter ( )
1291
1289
. find ( |ty:: GeneratorInteriorTypeCause { ty, .. } | ty_matches ( ty) )
@@ -1306,39 +1304,36 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
1306
1304
. map ( |expr| expr. span ) ;
1307
1305
let ty:: GeneratorInteriorTypeCause { span, scope_span, yield_span, expr, .. } =
1308
1306
cause;
1309
- (
1310
- span,
1311
- source_map. span_to_snippet ( * span) ,
1312
- scope_span,
1313
- yield_span,
1314
- expr,
1315
- from_awaited_ty,
1316
- )
1307
+ ( * span, * scope_span, * yield_span, * expr, from_awaited_ty)
1317
1308
} ) ;
1318
1309
1310
+ let upvar = if let Some ( upvars) = self . tcx . upvars ( generator_did) {
1311
+ upvars. iter ( ) . find_map ( |( upvar_id, upvar) | {
1312
+ let upvar_ty = tables. node_type ( * upvar_id) ;
1313
+ let upvar_ty = self . resolve_vars_if_possible ( & upvar_ty) ;
1314
+ if ty_matches ( & upvar_ty) { Some ( ( upvar_ty, upvar. span ) ) } else { None }
1315
+ } )
1316
+ } else {
1317
+ None
1318
+ } ;
1319
+
1319
1320
debug ! (
1320
- "maybe_note_obligation_cause_for_async_await: target_ty ={:?} \
1321
- generator_interior_types={:?} target_span= {:?}",
1322
- target_ty , tables. generator_interior_types, target_span
1321
+ "maybe_note_obligation_cause_for_async_await: interior ={:?} \
1322
+ generator_interior_types={:?} upvar: {:?}",
1323
+ interior , tables. generator_interior_types, upvar
1323
1324
) ;
1324
- if let Some ( ( target_span, Ok ( snippet) , scope_span, yield_span, expr, from_awaited_ty) ) =
1325
- target_span
1326
- {
1325
+ if interior. is_some ( ) || upvar. is_some ( ) {
1327
1326
self . note_obligation_cause_for_async_await (
1328
1327
err,
1329
- * target_span,
1330
- scope_span,
1331
- * yield_span,
1332
- * expr,
1333
- snippet,
1328
+ interior,
1329
+ upvar,
1334
1330
generator_body,
1335
1331
outer_generator,
1336
1332
trait_ref,
1337
1333
target_ty,
1338
1334
tables,
1339
1335
obligation,
1340
1336
next_code,
1341
- from_awaited_ty,
1342
1337
) ;
1343
1338
true
1344
1339
} else {
@@ -1351,19 +1346,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
1351
1346
fn note_obligation_cause_for_async_await (
1352
1347
& self ,
1353
1348
err : & mut DiagnosticBuilder < ' _ > ,
1354
- target_span : Span ,
1355
- scope_span : & Option < Span > ,
1356
- yield_span : Option < Span > ,
1357
- expr : Option < hir:: HirId > ,
1358
- snippet : String ,
1349
+ interior : Option < ( Span , Option < Span > , Option < Span > , Option < hir:: HirId > , Option < Span > ) > ,
1350
+ upvar : Option < ( Ty < ' tcx > , Span ) > ,
1359
1351
inner_generator_body : Option < & hir:: Body < ' _ > > ,
1360
1352
outer_generator : Option < DefId > ,
1361
1353
trait_ref : ty:: TraitRef < ' _ > ,
1362
1354
target_ty : Ty < ' tcx > ,
1363
1355
tables : & ty:: TypeckTables < ' _ > ,
1364
1356
obligation : & PredicateObligation < ' tcx > ,
1365
1357
next_code : Option < & ObligationCauseCode < ' tcx > > ,
1366
- from_awaited_ty : Option < Span > ,
1367
1358
) {
1368
1359
let source_map = self . tcx . sess . source_map ( ) ;
1369
1360
@@ -1424,99 +1415,122 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
1424
1415
format ! ( "does not implement `{}`" , trait_ref. print_only_trait_path( ) )
1425
1416
} ;
1426
1417
1427
- if let Some ( await_span) = from_awaited_ty {
1428
- // The type causing this obligation is one being awaited at await_span.
1429
- let mut span = MultiSpan :: from_span ( await_span) ;
1430
-
1431
- span. push_span_label (
1432
- await_span,
1433
- format ! ( "await occurs here on type `{}`, which {}" , target_ty, trait_explanation) ,
1434
- ) ;
1418
+ if let Some ( ( target_span, scope_span, yield_span, expr, from_awaited_ty) ) = interior {
1419
+ if let Some ( await_span) = from_awaited_ty {
1420
+ // The type causing this obligation is one being awaited at await_span.
1421
+ let mut span = MultiSpan :: from_span ( await_span) ;
1435
1422
1436
- err. span_note (
1437
- span,
1438
- & format ! (
1439
- "future {not_trait} as it awaits another future which {not_trait}" ,
1440
- not_trait = trait_explanation
1441
- ) ,
1442
- ) ;
1443
- } else {
1444
- // Look at the last interior type to get a span for the `.await`.
1445
- debug ! (
1446
- "note_obligation_cause_for_async_await generator_interior_types: {:#?}" ,
1447
- tables. generator_interior_types
1448
- ) ;
1449
-
1450
- if let Some ( yield_span) = yield_span {
1451
- let mut span = MultiSpan :: from_span ( yield_span) ;
1452
1423
span. push_span_label (
1453
- yield_span,
1454
- format ! ( "{} occurs here, with `{}` maybe used later" , await_or_yield, snippet) ,
1455
- ) ;
1456
-
1457
- span. push_span_label (
1458
- target_span,
1459
- format ! ( "has type `{}` which {}" , target_ty, trait_explanation) ,
1424
+ await_span,
1425
+ format ! (
1426
+ "await occurs here on type `{}`, which {}" ,
1427
+ target_ty, trait_explanation
1428
+ ) ,
1460
1429
) ;
1461
1430
1462
- // If available, use the scope span to annotate the drop location.
1463
- if let Some ( scope_span) = scope_span {
1464
- span. push_span_label (
1465
- source_map. end_point ( * scope_span) ,
1466
- format ! ( "`{}` is later dropped here" , snippet) ,
1467
- ) ;
1468
- }
1469
-
1470
1431
err. span_note (
1471
1432
span,
1472
1433
& format ! (
1473
- "{} { } as this value is used across { }" ,
1474
- future_or_generator , trait_explanation , an_await_or_yield
1434
+ "future {not_trait } as it awaits another future which {not_trait }" ,
1435
+ not_trait = trait_explanation
1475
1436
) ,
1476
1437
) ;
1477
- }
1478
- }
1438
+ } else {
1439
+ // Look at the last interior type to get a span for the `.await`.
1440
+ debug ! (
1441
+ "note_obligation_cause_for_async_await generator_interior_types: {:#?}" ,
1442
+ tables. generator_interior_types
1443
+ ) ;
1479
1444
1480
- if let Some ( expr_id) = expr {
1481
- let expr = hir. expect_expr ( expr_id) ;
1482
- debug ! ( "target_ty evaluated from {:?}" , expr) ;
1483
-
1484
- let parent = hir. get_parent_node ( expr_id) ;
1485
- if let Some ( hir:: Node :: Expr ( e) ) = hir. find ( parent) {
1486
- let parent_span = hir. span ( parent) ;
1487
- let parent_did = parent. owner . to_def_id ( ) ;
1488
- // ```rust
1489
- // impl T {
1490
- // fn foo(&self) -> i32 {}
1491
- // }
1492
- // T.foo();
1493
- // ^^^^^^^ a temporary `&T` created inside this method call due to `&self`
1494
- // ```
1495
- //
1496
- let is_region_borrow =
1497
- tables. expr_adjustments ( expr) . iter ( ) . any ( |adj| adj. is_region_borrow ( ) ) ;
1498
-
1499
- // ```rust
1500
- // struct Foo(*const u8);
1501
- // bar(Foo(std::ptr::null())).await;
1502
- // ^^^^^^^^^^^^^^^^^^^^^ raw-ptr `*T` created inside this struct ctor.
1503
- // ```
1504
- debug ! ( "parent_def_kind: {:?}" , self . tcx. def_kind( parent_did) ) ;
1505
- let is_raw_borrow_inside_fn_like_call = match self . tcx . def_kind ( parent_did) {
1506
- DefKind :: Fn | DefKind :: Ctor ( ..) => target_ty. is_unsafe_ptr ( ) ,
1507
- _ => false ,
1508
- } ;
1445
+ if let Some ( yield_span) = yield_span {
1446
+ let mut span = MultiSpan :: from_span ( yield_span) ;
1447
+ if let Ok ( snippet) = source_map. span_to_snippet ( target_span) {
1448
+ span. push_span_label (
1449
+ yield_span,
1450
+ format ! (
1451
+ "{} occurs here, with `{}` maybe used later" ,
1452
+ await_or_yield, snippet
1453
+ ) ,
1454
+ ) ;
1455
+ // If available, use the scope span to annotate the drop location.
1456
+ if let Some ( scope_span) = scope_span {
1457
+ span. push_span_label (
1458
+ source_map. end_point ( scope_span) ,
1459
+ format ! ( "`{}` is later dropped here" , snippet) ,
1460
+ ) ;
1461
+ }
1462
+ }
1463
+ span. push_span_label (
1464
+ target_span,
1465
+ format ! ( "has type `{}` which {}" , target_ty, trait_explanation) ,
1466
+ ) ;
1509
1467
1510
- if ( tables. is_method_call ( e) && is_region_borrow)
1511
- || is_raw_borrow_inside_fn_like_call
1512
- {
1513
- err. span_help (
1514
- parent_span,
1515
- "consider moving this into a `let` \
1516
- binding to create a shorter lived borrow",
1468
+ err. span_note (
1469
+ span,
1470
+ & format ! (
1471
+ "{} {} as this value is used across {}" ,
1472
+ future_or_generator, trait_explanation, an_await_or_yield
1473
+ ) ,
1517
1474
) ;
1518
1475
}
1519
1476
}
1477
+ if let Some ( ( _, upvar_span) ) = upvar {
1478
+ let mut span = MultiSpan :: from_span ( upvar_span) ;
1479
+ span. push_span_label (
1480
+ upvar_span,
1481
+ format ! ( "has type `{}` which {}" , target_ty, trait_explanation) ,
1482
+ ) ;
1483
+ }
1484
+ if let Some ( expr_id) = expr {
1485
+ let expr = hir. expect_expr ( expr_id) ;
1486
+ debug ! ( "target_ty evaluated from {:?}" , expr) ;
1487
+
1488
+ let parent = hir. get_parent_node ( expr_id) ;
1489
+ if let Some ( hir:: Node :: Expr ( e) ) = hir. find ( parent) {
1490
+ let parent_span = hir. span ( parent) ;
1491
+ let parent_did = parent. owner . to_def_id ( ) ;
1492
+ // ```rust
1493
+ // impl T {
1494
+ // fn foo(&self) -> i32 {}
1495
+ // }
1496
+ // T.foo();
1497
+ // ^^^^^^^ a temporary `&T` created inside this method call due to `&self`
1498
+ // ```
1499
+ //
1500
+ let is_region_borrow =
1501
+ tables. expr_adjustments ( expr) . iter ( ) . any ( |adj| adj. is_region_borrow ( ) ) ;
1502
+
1503
+ // ```rust
1504
+ // struct Foo(*const u8);
1505
+ // bar(Foo(std::ptr::null())).await;
1506
+ // ^^^^^^^^^^^^^^^^^^^^^ raw-ptr `*T` created inside this struct ctor.
1507
+ // ```
1508
+ debug ! ( "parent_def_kind: {:?}" , self . tcx. def_kind( parent_did) ) ;
1509
+ let is_raw_borrow_inside_fn_like_call = match self . tcx . def_kind ( parent_did) {
1510
+ DefKind :: Fn | DefKind :: Ctor ( ..) => target_ty. is_unsafe_ptr ( ) ,
1511
+ _ => false ,
1512
+ } ;
1513
+
1514
+ if ( tables. is_method_call ( e) && is_region_borrow)
1515
+ || is_raw_borrow_inside_fn_like_call
1516
+ {
1517
+ err. span_help (
1518
+ parent_span,
1519
+ "consider moving this into a `let` \
1520
+ binding to create a shorter lived borrow",
1521
+ ) ;
1522
+ }
1523
+ }
1524
+ }
1525
+ } else {
1526
+ if let Some ( ( _, upvar_span) ) = upvar {
1527
+ let mut span = MultiSpan :: from_span ( upvar_span) ;
1528
+ span. push_span_label (
1529
+ upvar_span,
1530
+ format ! ( "has type `{}` which {}" , target_ty, trait_explanation) ,
1531
+ ) ;
1532
+ err. span_note ( span, & format ! ( "captured outer value {}" , trait_explanation) ) ;
1533
+ }
1520
1534
}
1521
1535
1522
1536
// Add a note for the item obligation that remains - normally a note pointing to the
0 commit comments