@@ -25,6 +25,14 @@ use std::fmt;
2525use super :: InferCtxtPrivExt ;
2626use crate :: traits:: query:: evaluate_obligation:: InferCtxtExt as _;
2727
28+ #[ derive( Debug ) ]
29+ pub enum GeneratorInteriorOrUpvar {
30+ // span of interior type
31+ Interior ( Span ) ,
32+ // span of upvar
33+ Upvar ( Span ) ,
34+ }
35+
2836// This trait is public to expose the diagnostics methods to clippy.
2937pub trait InferCtxtExt < ' tcx > {
3038 fn suggest_restricting_param_bound (
@@ -128,19 +136,15 @@ pub trait InferCtxtExt<'tcx> {
128136 fn note_obligation_cause_for_async_await (
129137 & self ,
130138 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 > ) > ,
136141 inner_generator_body : Option < & hir:: Body < ' _ > > ,
137142 outer_generator : Option < DefId > ,
138143 trait_ref : ty:: TraitRef < ' _ > ,
139144 target_ty : Ty < ' tcx > ,
140145 tables : & ty:: TypeckTables < ' _ > ,
141146 obligation : & PredicateObligation < ' tcx > ,
142147 next_code : Option < & ObligationCauseCode < ' tcx > > ,
143- from_awaited_ty : Option < Span > ,
144148 ) ;
145149
146150 fn note_obligation_cause_code < T > (
@@ -1205,7 +1209,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
12051209 obligation.cause.span={:?}",
12061210 obligation. predicate, obligation. cause. span
12071211 ) ;
1208- let source_map = self . tcx . sess . source_map ( ) ;
12091212 let hir = self . tcx . hir ( ) ;
12101213
12111214 // 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> {
13541357 ) ;
13551358 eq
13561359 } ;
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
13581377 . generator_interior_types
13591378 . iter ( )
13601379 . find ( |ty:: GeneratorInteriorTypeCause { ty, .. } | ty_matches ( ty) )
@@ -1375,39 +1394,28 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
13751394 . map ( |expr| expr. span ) ;
13761395 let ty:: GeneratorInteriorTypeCause { span, scope_span, yield_span, expr, .. } =
13771396 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) ) ;
13861400 } ) ;
13871401
13881402 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
13921406 ) ;
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 {
13961408 self . note_obligation_cause_for_async_await (
13971409 err,
1398- * target_span,
1399- scope_span,
1400- * yield_span,
1401- * expr,
1402- snippet,
1410+ interior_or_upvar_span,
1411+ interior_extra_info,
14031412 generator_body,
14041413 outer_generator,
14051414 trait_ref,
14061415 target_ty,
14071416 tables,
14081417 obligation,
14091418 next_code,
1410- from_awaited_ty,
14111419 ) ;
14121420 true
14131421 } else {
@@ -1420,19 +1428,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
14201428 fn note_obligation_cause_for_async_await (
14211429 & self ,
14221430 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 > ) > ,
14281433 inner_generator_body : Option < & hir:: Body < ' _ > > ,
14291434 outer_generator : Option < DefId > ,
14301435 trait_ref : ty:: TraitRef < ' _ > ,
14311436 target_ty : Ty < ' tcx > ,
14321437 tables : & ty:: TypeckTables < ' _ > ,
14331438 obligation : & PredicateObligation < ' tcx > ,
14341439 next_code : Option < & ObligationCauseCode < ' tcx > > ,
1435- from_awaited_ty : Option < Span > ,
14361440 ) {
14371441 let source_map = self . tcx . sess . source_map ( ) ;
14381442
@@ -1493,46 +1497,27 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
14931497 format ! ( "does not implement `{}`" , trait_ref. print_only_trait_path( ) )
14941498 } ;
14951499
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 > | {
15181503 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) {
15311505 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) ,
15341508 ) ;
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+ }
15351516 }
1517+ span. push_span_label (
1518+ interior_span,
1519+ format ! ( "has type `{}` which {}" , target_ty, trait_explanation) ,
1520+ ) ;
15361521
15371522 err. span_note (
15381523 span,
@@ -1541,48 +1526,90 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
15411526 future_or_generator, trait_explanation, an_await_or_yield
15421527 ) ,
15431528 ) ;
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+ }
15751558
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` \
15821598 binding to create a shorter lived borrow",
1583- ) ;
1599+ ) ;
1600+ }
1601+ }
1602+ }
15841603 }
15851604 }
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+ }
15861613 }
15871614
15881615 // Add a note for the item obligation that remains - normally a note pointing to the
0 commit comments