@@ -127,13 +127,14 @@ pub trait InferCtxtExt<'tcx> {
127127 scope_span : & Option < Span > ,
128128 expr : Option < hir:: HirId > ,
129129 snippet : String ,
130- inner_generator : DefId ,
130+ inner_generator_body : Option < & hir :: Body < ' _ > > ,
131131 outer_generator : Option < DefId > ,
132132 trait_ref : ty:: TraitRef < ' _ > ,
133133 target_ty : Ty < ' tcx > ,
134134 tables : & ty:: TypeckTables < ' _ > ,
135135 obligation : & PredicateObligation < ' tcx > ,
136136 next_code : Option < & ObligationCauseCode < ' tcx > > ,
137+ from_awaited_ty : Option < Span > ,
137138 ) ;
138139
139140 fn note_obligation_cause_code < T > (
@@ -1203,6 +1204,17 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
12031204 }
12041205 } ;
12051206
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+
12061218 // Look for a type inside the generator interior that matches the target type to get
12071219 // a span.
12081220 let target_ty_erased = self . tcx . erase_regions ( & target_ty) ;
@@ -1232,29 +1244,48 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
12321244 ) ;
12331245 eq
12341246 } )
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)
12371267 } ) ;
12381268
12391269 debug ! (
12401270 "maybe_note_obligation_cause_for_async_await: target_ty={:?} \
12411271 generator_interior_types={:?} target_span={:?}",
12421272 target_ty, tables. generator_interior_types, target_span
12431273 ) ;
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 {
12451275 self . note_obligation_cause_for_async_await (
12461276 err,
12471277 * target_span,
12481278 scope_span,
12491279 * expr,
12501280 snippet,
1251- generator_did ,
1281+ generator_body ,
12521282 outer_generator,
12531283 trait_ref,
12541284 target_ty,
12551285 tables,
12561286 obligation,
12571287 next_code,
1288+ from_awaited_ty,
12581289 ) ;
12591290 true
12601291 } else {
@@ -1271,22 +1302,18 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
12711302 scope_span : & Option < Span > ,
12721303 expr : Option < hir:: HirId > ,
12731304 snippet : String ,
1274- inner_generator : DefId ,
1305+ inner_generator_body : Option < & hir :: Body < ' _ > > ,
12751306 outer_generator : Option < DefId > ,
12761307 trait_ref : ty:: TraitRef < ' _ > ,
12771308 target_ty : Ty < ' tcx > ,
12781309 tables : & ty:: TypeckTables < ' _ > ,
12791310 obligation : & PredicateObligation < ' tcx > ,
12801311 next_code : Option < & ObligationCauseCode < ' tcx > > ,
1312+ from_awaited_ty : Option < Span > ,
12811313 ) {
12821314 let source_map = self . tcx . sess . source_map ( ) ;
12831315
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
12901317 . and_then ( |body| body. generator_kind ( ) )
12911318 . map ( |generator_kind| match generator_kind {
12921319 hir:: GeneratorKind :: Async ( ..) => true ,
@@ -1345,33 +1372,57 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
13451372 )
13461373 } ;
13471374
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+ } ;
13551383
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) ;
13621393
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) ;
13651406 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) ,
13681409 ) ;
1369- }
13701410
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+ }
13751426
13761427 if let Some ( expr_id) = expr {
13771428 let expr = hir. expect_expr ( expr_id) ;
@@ -1716,6 +1767,29 @@ impl<'v> Visitor<'v> for ReturnsVisitor<'v> {
17161767 }
17171768}
17181769
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+
17191793pub trait NextTypeParamName {
17201794 fn next_type_param_name ( & self , name : Option < & str > ) -> String ;
17211795}
0 commit comments