@@ -125,19 +125,15 @@ pub trait InferCtxtExt<'tcx> {
125125 fn note_obligation_cause_for_async_await (
126126 & self ,
127127 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 ) > ,
133130 inner_generator_body : Option < & hir:: Body < ' _ > > ,
134131 outer_generator : Option < DefId > ,
135132 trait_ref : ty:: TraitRef < ' _ > ,
136133 target_ty : Ty < ' tcx > ,
137134 tables : & ty:: TypeckTables < ' _ > ,
138135 obligation : & PredicateObligation < ' tcx > ,
139136 next_code : Option < & ObligationCauseCode < ' tcx > > ,
140- from_awaited_ty : Option < Span > ,
141137 ) ;
142138
143139 fn note_obligation_cause_code < T > (
@@ -1136,7 +1132,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
11361132 obligation.cause.span={:?}",
11371133 obligation. predicate, obligation. cause. span
11381134 ) ;
1139- let source_map = self . tcx . sess . source_map ( ) ;
11401135 let hir = self . tcx . hir ( ) ;
11411136
11421137 // 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> {
11731168 } ;
11741169 let mut generator = None ;
11751170 let mut outer_generator = None ;
1171+ let mut generator_substs = None ;
11761172 let mut next_code = Some ( & obligation. cause . code ) ;
11771173 while let Some ( code) = next_code {
11781174 debug ! ( "maybe_note_obligation_cause_for_async_await: code={:?}" , code) ;
@@ -1188,8 +1184,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
11881184 ) ;
11891185
11901186 match ty. kind {
1191- ty:: Generator ( did, ..) => {
1187+ ty:: Generator ( did, substs , ..) => {
11921188 generator = generator. or ( Some ( did) ) ;
1189+ generator_substs = generator_substs. or ( Some ( substs) ) ;
11931190 outer_generator = Some ( did) ;
11941191 }
11951192 ty:: GeneratorWitness ( ..) => { }
@@ -1212,12 +1209,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
12121209 target_ty={:?}",
12131210 generator, trait_ref, target_ty
12141211 ) ;
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+ } ;
12211219
12221220 let span = self . tcx . def_span ( generator_did) ;
12231221
@@ -1285,7 +1283,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
12851283 ) ;
12861284 eq
12871285 } ;
1288- let target_span = tables
1286+ let interior = tables
12891287 . generator_interior_types
12901288 . iter ( )
12911289 . find ( |ty:: GeneratorInteriorTypeCause { ty, .. } | ty_matches ( ty) )
@@ -1306,39 +1304,36 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
13061304 . map ( |expr| expr. span ) ;
13071305 let ty:: GeneratorInteriorTypeCause { span, scope_span, yield_span, expr, .. } =
13081306 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)
13171308 } ) ;
13181309
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+
13191320 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
13231324 ) ;
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 ( ) {
13271326 self . note_obligation_cause_for_async_await (
13281327 err,
1329- * target_span,
1330- scope_span,
1331- * yield_span,
1332- * expr,
1333- snippet,
1328+ interior,
1329+ upvar,
13341330 generator_body,
13351331 outer_generator,
13361332 trait_ref,
13371333 target_ty,
13381334 tables,
13391335 obligation,
13401336 next_code,
1341- from_awaited_ty,
13421337 ) ;
13431338 true
13441339 } else {
@@ -1351,19 +1346,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
13511346 fn note_obligation_cause_for_async_await (
13521347 & self ,
13531348 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 ) > ,
13591351 inner_generator_body : Option < & hir:: Body < ' _ > > ,
13601352 outer_generator : Option < DefId > ,
13611353 trait_ref : ty:: TraitRef < ' _ > ,
13621354 target_ty : Ty < ' tcx > ,
13631355 tables : & ty:: TypeckTables < ' _ > ,
13641356 obligation : & PredicateObligation < ' tcx > ,
13651357 next_code : Option < & ObligationCauseCode < ' tcx > > ,
1366- from_awaited_ty : Option < Span > ,
13671358 ) {
13681359 let source_map = self . tcx . sess . source_map ( ) ;
13691360
@@ -1424,99 +1415,122 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
14241415 format ! ( "does not implement `{}`" , trait_ref. print_only_trait_path( ) )
14251416 } ;
14261417
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) ;
14351422
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) ;
14521423 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+ ) ,
14601429 ) ;
14611430
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-
14701431 err. span_note (
14711432 span,
14721433 & 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
14751436 ) ,
14761437 ) ;
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+ ) ;
14791444
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+ ) ;
15091467
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+ ) ,
15171474 ) ;
15181475 }
15191476 }
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+ }
15201534 }
15211535
15221536 // Add a note for the item obligation that remains - normally a note pointing to the
0 commit comments