@@ -25,6 +25,14 @@ use std::fmt;
25
25
use super :: InferCtxtPrivExt ;
26
26
use crate :: traits:: query:: evaluate_obligation:: InferCtxtExt as _;
27
27
28
+ #[ derive( Debug ) ]
29
+ pub enum GeneratorInteriorOrUpvar {
30
+ // span of interior type
31
+ Interior ( Span ) ,
32
+ // span of upvar
33
+ Upvar ( Span ) ,
34
+ }
35
+
28
36
// This trait is public to expose the diagnostics methods to clippy.
29
37
pub trait InferCtxtExt < ' tcx > {
30
38
fn suggest_restricting_param_bound (
@@ -128,19 +136,15 @@ pub trait InferCtxtExt<'tcx> {
128
136
fn note_obligation_cause_for_async_await (
129
137
& self ,
130
138
err : & mut DiagnosticBuilder < ' _ > ,
131
- target_span : Span ,
132
- scope_span : & Option < Span > ,
133
- await_span : Span ,
134
- expr : Option < hir:: HirId > ,
135
- snippet : String ,
139
+ interior_or_upvar_span : GeneratorInteriorOrUpvar ,
140
+ interior_extra_info : Option < ( Option < Span > , Span , Option < hir:: HirId > , Option < Span > ) > ,
136
141
inner_generator_body : Option < & hir:: Body < ' _ > > ,
137
142
outer_generator : Option < DefId > ,
138
143
trait_ref : ty:: TraitRef < ' _ > ,
139
144
target_ty : Ty < ' tcx > ,
140
145
tables : & ty:: TypeckTables < ' _ > ,
141
146
obligation : & PredicateObligation < ' tcx > ,
142
147
next_code : Option < & ObligationCauseCode < ' tcx > > ,
143
- from_awaited_ty : Option < Span > ,
144
148
) ;
145
149
146
150
fn note_obligation_cause_code < T > (
@@ -1205,7 +1209,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
1205
1209
obligation.cause.span={:?}",
1206
1210
obligation. predicate, obligation. cause. span
1207
1211
) ;
1208
- let source_map = self . tcx . sess . source_map ( ) ;
1209
1212
let hir = self . tcx . hir ( ) ;
1210
1213
1211
1214
// Attempt to detect an async-await error by looking at the obligation causes, looking
@@ -1354,7 +1357,23 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
1354
1357
) ;
1355
1358
eq
1356
1359
} ;
1357
- let target_span = tables
1360
+
1361
+ let mut interior_or_upvar_span = None ;
1362
+ let mut interior_extra_info = None ;
1363
+
1364
+ if let Some ( upvars) = self . tcx . upvars ( generator_did) {
1365
+ interior_or_upvar_span = upvars. iter ( ) . find_map ( |( upvar_id, upvar) | {
1366
+ let upvar_ty = tables. node_type ( * upvar_id) ;
1367
+ let upvar_ty = self . resolve_vars_if_possible ( & upvar_ty) ;
1368
+ if ty_matches ( & upvar_ty) {
1369
+ Some ( GeneratorInteriorOrUpvar :: Upvar ( upvar. span ) )
1370
+ } else {
1371
+ None
1372
+ }
1373
+ } ) ;
1374
+ } ;
1375
+
1376
+ tables
1358
1377
. generator_interior_types
1359
1378
. iter ( )
1360
1379
. find ( |ty:: GeneratorInteriorTypeCause { ty, .. } | ty_matches ( ty) )
@@ -1375,39 +1394,28 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
1375
1394
. map ( |expr| expr. span ) ;
1376
1395
let ty:: GeneratorInteriorTypeCause { span, scope_span, yield_span, expr, .. } =
1377
1396
cause;
1378
- (
1379
- span,
1380
- source_map. span_to_snippet ( * span) ,
1381
- scope_span,
1382
- yield_span,
1383
- expr,
1384
- from_awaited_ty,
1385
- )
1397
+
1398
+ interior_or_upvar_span = Some ( GeneratorInteriorOrUpvar :: Interior ( * span) ) ;
1399
+ interior_extra_info = Some ( ( * scope_span, * yield_span, * expr, from_awaited_ty) ) ;
1386
1400
} ) ;
1387
1401
1388
1402
debug ! (
1389
- "maybe_note_obligation_cause_for_async_await: target_ty ={:?} \
1390
- generator_interior_types={:?} target_span={:?} ",
1391
- target_ty , tables. generator_interior_types, target_span
1403
+ "maybe_note_obligation_cause_for_async_await: interior_or_upvar ={:?} \
1404
+ generator_interior_types={:?}",
1405
+ interior_or_upvar_span , tables. generator_interior_types
1392
1406
) ;
1393
- if let Some ( ( target_span, Ok ( snippet) , scope_span, yield_span, expr, from_awaited_ty) ) =
1394
- target_span
1395
- {
1407
+ if let Some ( interior_or_upvar_span) = interior_or_upvar_span {
1396
1408
self . note_obligation_cause_for_async_await (
1397
1409
err,
1398
- * target_span,
1399
- scope_span,
1400
- * yield_span,
1401
- * expr,
1402
- snippet,
1410
+ interior_or_upvar_span,
1411
+ interior_extra_info,
1403
1412
generator_body,
1404
1413
outer_generator,
1405
1414
trait_ref,
1406
1415
target_ty,
1407
1416
tables,
1408
1417
obligation,
1409
1418
next_code,
1410
- from_awaited_ty,
1411
1419
) ;
1412
1420
true
1413
1421
} else {
@@ -1420,19 +1428,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
1420
1428
fn note_obligation_cause_for_async_await (
1421
1429
& self ,
1422
1430
err : & mut DiagnosticBuilder < ' _ > ,
1423
- target_span : Span ,
1424
- scope_span : & Option < Span > ,
1425
- yield_span : Span ,
1426
- expr : Option < hir:: HirId > ,
1427
- snippet : String ,
1431
+ interior_or_upvar_span : GeneratorInteriorOrUpvar ,
1432
+ interior_extra_info : Option < ( Option < Span > , Span , Option < hir:: HirId > , Option < Span > ) > ,
1428
1433
inner_generator_body : Option < & hir:: Body < ' _ > > ,
1429
1434
outer_generator : Option < DefId > ,
1430
1435
trait_ref : ty:: TraitRef < ' _ > ,
1431
1436
target_ty : Ty < ' tcx > ,
1432
1437
tables : & ty:: TypeckTables < ' _ > ,
1433
1438
obligation : & PredicateObligation < ' tcx > ,
1434
1439
next_code : Option < & ObligationCauseCode < ' tcx > > ,
1435
- from_awaited_ty : Option < Span > ,
1436
1440
) {
1437
1441
let source_map = self . tcx . sess . source_map ( ) ;
1438
1442
@@ -1493,46 +1497,27 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
1493
1497
format ! ( "does not implement `{}`" , trait_ref. print_only_trait_path( ) )
1494
1498
} ;
1495
1499
1496
- if let Some ( await_span) = from_awaited_ty {
1497
- // The type causing this obligation is one being awaited at await_span.
1498
- let mut span = MultiSpan :: from_span ( await_span) ;
1499
-
1500
- span. push_span_label (
1501
- await_span,
1502
- format ! ( "await occurs here on type `{}`, which {}" , target_ty, trait_explanation) ,
1503
- ) ;
1504
-
1505
- err. span_note (
1506
- span,
1507
- & format ! (
1508
- "future {not_trait} as it awaits another future which {not_trait}" ,
1509
- not_trait = trait_explanation
1510
- ) ,
1511
- ) ;
1512
- } else {
1513
- // Look at the last interior type to get a span for the `.await`.
1514
- debug ! (
1515
- "note_obligation_cause_for_async_await generator_interior_types: {:#?}" ,
1516
- tables. generator_interior_types
1517
- ) ;
1500
+ let mut explain_yield = |interior_span : Span ,
1501
+ yield_span : Span ,
1502
+ scope_span : Option < Span > | {
1518
1503
let mut span = MultiSpan :: from_span ( yield_span) ;
1519
- span. push_span_label (
1520
- yield_span,
1521
- format ! ( "{} occurs here, with `{}` maybe used later" , await_or_yield, snippet) ,
1522
- ) ;
1523
-
1524
- span. push_span_label (
1525
- target_span,
1526
- format ! ( "has type `{}` which {}" , target_ty, trait_explanation) ,
1527
- ) ;
1528
-
1529
- // If available, use the scope span to annotate the drop location.
1530
- if let Some ( scope_span) = scope_span {
1504
+ if let Ok ( snippet) = source_map. span_to_snippet ( interior_span) {
1531
1505
span. push_span_label (
1532
- source_map . end_point ( * scope_span ) ,
1533
- format ! ( "`{}` is later dropped here" , snippet) ,
1506
+ yield_span ,
1507
+ format ! ( "{} occurs here, with `{}` maybe used later" , await_or_yield , snippet) ,
1534
1508
) ;
1509
+ // If available, use the scope span to annotate the drop location.
1510
+ if let Some ( scope_span) = scope_span {
1511
+ span. push_span_label (
1512
+ source_map. end_point ( scope_span) ,
1513
+ format ! ( "`{}` is later dropped here" , snippet) ,
1514
+ ) ;
1515
+ }
1535
1516
}
1517
+ span. push_span_label (
1518
+ interior_span,
1519
+ format ! ( "has type `{}` which {}" , target_ty, trait_explanation) ,
1520
+ ) ;
1536
1521
1537
1522
err. span_note (
1538
1523
span,
@@ -1541,48 +1526,90 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
1541
1526
future_or_generator, trait_explanation, an_await_or_yield
1542
1527
) ,
1543
1528
) ;
1544
- }
1545
-
1546
- if let Some ( expr_id) = expr {
1547
- let expr = hir. expect_expr ( expr_id) ;
1548
- debug ! ( "target_ty evaluated from {:?}" , expr) ;
1549
-
1550
- let parent = hir. get_parent_node ( expr_id) ;
1551
- if let Some ( hir:: Node :: Expr ( e) ) = hir. find ( parent) {
1552
- let parent_span = hir. span ( parent) ;
1553
- let parent_did = parent. owner . to_def_id ( ) ;
1554
- // ```rust
1555
- // impl T {
1556
- // fn foo(&self) -> i32 {}
1557
- // }
1558
- // T.foo();
1559
- // ^^^^^^^ a temporary `&T` created inside this method call due to `&self`
1560
- // ```
1561
- //
1562
- let is_region_borrow =
1563
- tables. expr_adjustments ( expr) . iter ( ) . any ( |adj| adj. is_region_borrow ( ) ) ;
1564
-
1565
- // ```rust
1566
- // struct Foo(*const u8);
1567
- // bar(Foo(std::ptr::null())).await;
1568
- // ^^^^^^^^^^^^^^^^^^^^^ raw-ptr `*T` created inside this struct ctor.
1569
- // ```
1570
- debug ! ( "parent_def_kind: {:?}" , self . tcx. def_kind( parent_did) ) ;
1571
- let is_raw_borrow_inside_fn_like_call = match self . tcx . def_kind ( parent_did) {
1572
- DefKind :: Fn | DefKind :: Ctor ( ..) => target_ty. is_unsafe_ptr ( ) ,
1573
- _ => false ,
1574
- } ;
1529
+ } ;
1530
+ match interior_or_upvar_span {
1531
+ GeneratorInteriorOrUpvar :: Interior ( interior_span) => {
1532
+ if let Some ( ( scope_span, yield_span, expr, from_awaited_ty) ) = interior_extra_info {
1533
+ if let Some ( await_span) = from_awaited_ty {
1534
+ // The type causing this obligation is one being awaited at await_span.
1535
+ let mut span = MultiSpan :: from_span ( await_span) ;
1536
+ span. push_span_label (
1537
+ await_span,
1538
+ format ! (
1539
+ "await occurs here on type `{}`, which {}" ,
1540
+ target_ty, trait_explanation
1541
+ ) ,
1542
+ ) ;
1543
+ err. span_note (
1544
+ span,
1545
+ & format ! (
1546
+ "future {not_trait} as it awaits another future which {not_trait}" ,
1547
+ not_trait = trait_explanation
1548
+ ) ,
1549
+ ) ;
1550
+ } else {
1551
+ // Look at the last interior type to get a span for the `.await`.
1552
+ debug ! (
1553
+ "note_obligation_cause_for_async_await generator_interior_types: {:#?}" ,
1554
+ tables. generator_interior_types
1555
+ ) ;
1556
+ explain_yield ( interior_span, yield_span, scope_span) ;
1557
+ }
1575
1558
1576
- if ( tables. is_method_call ( e) && is_region_borrow)
1577
- || is_raw_borrow_inside_fn_like_call
1578
- {
1579
- err. span_help (
1580
- parent_span,
1581
- "consider moving this into a `let` \
1559
+ if let Some ( expr_id) = expr {
1560
+ let expr = hir. expect_expr ( expr_id) ;
1561
+ debug ! ( "target_ty evaluated from {:?}" , expr) ;
1562
+
1563
+ let parent = hir. get_parent_node ( expr_id) ;
1564
+ if let Some ( hir:: Node :: Expr ( e) ) = hir. find ( parent) {
1565
+ let parent_span = hir. span ( parent) ;
1566
+ let parent_did = parent. owner . to_def_id ( ) ;
1567
+ // ```rust
1568
+ // impl T {
1569
+ // fn foo(&self) -> i32 {}
1570
+ // }
1571
+ // T.foo();
1572
+ // ^^^^^^^ a temporary `&T` created inside this method call due to `&self`
1573
+ // ```
1574
+ //
1575
+ let is_region_borrow = tables
1576
+ . expr_adjustments ( expr)
1577
+ . iter ( )
1578
+ . any ( |adj| adj. is_region_borrow ( ) ) ;
1579
+
1580
+ // ```rust
1581
+ // struct Foo(*const u8);
1582
+ // bar(Foo(std::ptr::null())).await;
1583
+ // ^^^^^^^^^^^^^^^^^^^^^ raw-ptr `*T` created inside this struct ctor.
1584
+ // ```
1585
+ debug ! ( "parent_def_kind: {:?}" , self . tcx. def_kind( parent_did) ) ;
1586
+ let is_raw_borrow_inside_fn_like_call =
1587
+ match self . tcx . def_kind ( parent_did) {
1588
+ DefKind :: Fn | DefKind :: Ctor ( ..) => target_ty. is_unsafe_ptr ( ) ,
1589
+ _ => false ,
1590
+ } ;
1591
+
1592
+ if ( tables. is_method_call ( e) && is_region_borrow)
1593
+ || is_raw_borrow_inside_fn_like_call
1594
+ {
1595
+ err. span_help (
1596
+ parent_span,
1597
+ "consider moving this into a `let` \
1582
1598
binding to create a shorter lived borrow",
1583
- ) ;
1599
+ ) ;
1600
+ }
1601
+ }
1602
+ }
1584
1603
}
1585
1604
}
1605
+ GeneratorInteriorOrUpvar :: Upvar ( upvar_span) => {
1606
+ let mut span = MultiSpan :: from_span ( upvar_span) ;
1607
+ span. push_span_label (
1608
+ upvar_span,
1609
+ format ! ( "has type `{}` which {}" , target_ty, trait_explanation) ,
1610
+ ) ;
1611
+ err. span_note ( span, & format ! ( "captured value {}" , trait_explanation) ) ;
1612
+ }
1586
1613
}
1587
1614
1588
1615
// Add a note for the item obligation that remains - normally a note pointing to the
0 commit comments