@@ -126,13 +126,14 @@ crate trait InferCtxtExt<'tcx> {
126
126
scope_span : & Option < Span > ,
127
127
expr : Option < hir:: HirId > ,
128
128
snippet : String ,
129
- inner_generator : DefId ,
129
+ inner_generator_body : Option < & hir :: Body < ' _ > > ,
130
130
outer_generator : Option < DefId > ,
131
131
trait_ref : ty:: TraitRef < ' _ > ,
132
132
target_ty : Ty < ' tcx > ,
133
133
tables : & ty:: TypeckTables < ' _ > ,
134
134
obligation : & PredicateObligation < ' tcx > ,
135
135
next_code : Option < & ObligationCauseCode < ' tcx > > ,
136
+ from_awaited_ty : Option < Span > ,
136
137
) ;
137
138
138
139
fn note_obligation_cause_code < T > (
@@ -1088,6 +1089,17 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
1088
1089
}
1089
1090
} ;
1090
1091
1092
+ let generator_body = self . tcx
1093
+ . hir ( )
1094
+ . as_local_hir_id ( generator_did)
1095
+ . and_then ( |hir_id| self . tcx . hir ( ) . maybe_body_owned_by ( hir_id) )
1096
+ . map ( |body_id| self . tcx . hir ( ) . body ( body_id) ) ;
1097
+ let mut visitor = AwaitsVisitor :: default ( ) ;
1098
+ if let Some ( body) = generator_body {
1099
+ visitor. visit_body ( body) ;
1100
+ }
1101
+ debug ! ( "maybe_note_obligation_cause_for_async_await: awaits = {:?}" , visitor. awaits) ;
1102
+
1091
1103
// Look for a type inside the generator interior that matches the target type to get
1092
1104
// a span.
1093
1105
let target_ty_erased = self . tcx . erase_regions ( & target_ty) ;
@@ -1117,29 +1129,48 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
1117
1129
) ;
1118
1130
eq
1119
1131
} )
1120
- . map ( |ty:: GeneratorInteriorTypeCause { span, scope_span, expr, .. } | {
1121
- ( span, source_map. span_to_snippet ( * span) , scope_span, expr)
1132
+ . map ( |cause| {
1133
+ // Check to see if any awaited expressions have the target type.
1134
+ let from_awaited_ty = visitor. awaits . into_iter ( )
1135
+ . map ( |id| self . tcx . hir ( ) . expect_expr ( id) )
1136
+ . find ( |expr| {
1137
+ let ty = tables. expr_ty_adjusted ( & expr) ;
1138
+ // Compare types using the same logic as above.
1139
+ let ty_erased = self . tcx . erase_late_bound_regions ( & ty:: Binder :: bind ( ty) ) ;
1140
+ let ty_erased = self . tcx . erase_regions ( & ty_erased) ;
1141
+ let eq = ty:: TyS :: same_type ( ty_erased, target_ty_erased) ;
1142
+ debug ! (
1143
+ "maybe_note_obligation_cause_for_async_await: await_expr={:?} \
1144
+ await_ty_erased={:?} target_ty_erased={:?} eq={:?}",
1145
+ expr, ty_erased, target_ty_erased, eq
1146
+ ) ;
1147
+ eq
1148
+ } )
1149
+ . map ( |expr| expr. span ) ;
1150
+ let ty:: GeneratorInteriorTypeCause { span, scope_span, expr, .. } = cause;
1151
+ ( span, source_map. span_to_snippet ( * span) , scope_span, expr, from_awaited_ty)
1122
1152
} ) ;
1123
1153
1124
1154
debug ! (
1125
1155
"maybe_note_obligation_cause_for_async_await: target_ty={:?} \
1126
1156
generator_interior_types={:?} target_span={:?}",
1127
1157
target_ty, tables. generator_interior_types, target_span
1128
1158
) ;
1129
- if let Some ( ( target_span, Ok ( snippet) , scope_span, expr) ) = target_span {
1159
+ if let Some ( ( target_span, Ok ( snippet) , scope_span, expr, from_awaited_ty ) ) = target_span {
1130
1160
self . note_obligation_cause_for_async_await (
1131
1161
err,
1132
1162
* target_span,
1133
1163
scope_span,
1134
1164
* expr,
1135
1165
snippet,
1136
- generator_did ,
1166
+ generator_body ,
1137
1167
outer_generator,
1138
1168
trait_ref,
1139
1169
target_ty,
1140
1170
tables,
1141
1171
obligation,
1142
1172
next_code,
1173
+ from_awaited_ty,
1143
1174
) ;
1144
1175
true
1145
1176
} else {
@@ -1156,22 +1187,18 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
1156
1187
scope_span : & Option < Span > ,
1157
1188
expr : Option < hir:: HirId > ,
1158
1189
snippet : String ,
1159
- inner_generator : DefId ,
1190
+ inner_generator_body : Option < & hir :: Body < ' _ > > ,
1160
1191
outer_generator : Option < DefId > ,
1161
1192
trait_ref : ty:: TraitRef < ' _ > ,
1162
1193
target_ty : Ty < ' tcx > ,
1163
1194
tables : & ty:: TypeckTables < ' _ > ,
1164
1195
obligation : & PredicateObligation < ' tcx > ,
1165
1196
next_code : Option < & ObligationCauseCode < ' tcx > > ,
1197
+ from_awaited_ty : Option < Span > ,
1166
1198
) {
1167
1199
let source_map = self . tcx . sess . source_map ( ) ;
1168
1200
1169
- let is_async = self
1170
- . tcx
1171
- . hir ( )
1172
- . as_local_hir_id ( inner_generator)
1173
- . and_then ( |hir_id| self . tcx . hir ( ) . maybe_body_owned_by ( hir_id) )
1174
- . map ( |body_id| self . tcx . hir ( ) . body ( body_id) )
1201
+ let is_async = inner_generator_body
1175
1202
. and_then ( |body| body. generator_kind ( ) )
1176
1203
. map ( |generator_kind| match generator_kind {
1177
1204
hir:: GeneratorKind :: Async ( ..) => true ,
@@ -1230,33 +1257,57 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
1230
1257
)
1231
1258
} ;
1232
1259
1233
- // Look at the last interior type to get a span for the `.await`.
1234
- let await_span = tables. generator_interior_types . iter ( ) . map ( |t| t. span ) . last ( ) . unwrap ( ) ;
1235
- let mut span = MultiSpan :: from_span ( await_span) ;
1236
- span. push_span_label (
1237
- await_span,
1238
- format ! ( "{} occurs here, with `{}` maybe used later" , await_or_yield, snippet) ,
1239
- ) ;
1260
+ let push_target_span = |span : & mut MultiSpan | {
1261
+ if target_ty. is_impl_trait ( ) {
1262
+ // It's not very useful to tell the user the type if it's opaque.
1263
+ span. push_span_label ( target_span, "created here" . to_string ( ) ) ;
1264
+ } else {
1265
+ span. push_span_label ( target_span, format ! ( "has type `{}`" , target_ty) ) ;
1266
+ }
1267
+ } ;
1240
1268
1241
- if target_ty. is_impl_trait ( ) {
1242
- // It's not very useful to tell the user the type if it's opaque.
1243
- span. push_span_label ( target_span, "created here" . to_string ( ) ) ;
1244
- } else {
1245
- span. push_span_label ( target_span, format ! ( "has type `{}`" , target_ty) ) ;
1246
- }
1269
+ if let Some ( await_span) = from_awaited_ty {
1270
+ // The type causing this obligation is one being awaited at await_span.
1271
+ let mut span = MultiSpan :: from_span ( await_span) ;
1272
+ span. push_span_label (
1273
+ await_span,
1274
+ "await occurs here" . to_string ( ) ,
1275
+ ) ;
1276
+
1277
+ push_target_span ( & mut span) ;
1247
1278
1248
- // If available, use the scope span to annotate the drop location.
1249
- if let Some ( scope_span) = scope_span {
1279
+ err. span_note (
1280
+ span,
1281
+ & format ! ( "{} as this value is used in an await" , trait_explanation) ,
1282
+ ) ;
1283
+ } else {
1284
+ // Look at the last interior type to get a span for the `.await`.
1285
+ debug ! (
1286
+ "note_obligation_cause_for_async_await generator_interior_types: {:#?}" ,
1287
+ tables. generator_interior_types
1288
+ ) ;
1289
+ let await_span = tables. generator_interior_types . iter ( ) . map ( |t| t. span ) . last ( ) . unwrap ( ) ;
1290
+ let mut span = MultiSpan :: from_span ( await_span) ;
1250
1291
span. push_span_label (
1251
- source_map . end_point ( * scope_span ) ,
1252
- format ! ( "`{}` is later dropped here" , snippet) ,
1292
+ await_span ,
1293
+ format ! ( "{} occurs here, with `{}` maybe used later" , await_or_yield , snippet) ,
1253
1294
) ;
1254
- }
1255
1295
1256
- err. span_note (
1257
- span,
1258
- & format ! ( "{} as this value is used across an {}" , trait_explanation, await_or_yield) ,
1259
- ) ;
1296
+ push_target_span ( & mut span) ;
1297
+
1298
+ // If available, use the scope span to annotate the drop location.
1299
+ if let Some ( scope_span) = scope_span {
1300
+ span. push_span_label (
1301
+ source_map. end_point ( * scope_span) ,
1302
+ format ! ( "`{}` is later dropped here" , snippet) ,
1303
+ ) ;
1304
+ }
1305
+
1306
+ err. span_note (
1307
+ span,
1308
+ & format ! ( "{} as this value is used across an {}" , trait_explanation, await_or_yield) ,
1309
+ ) ;
1310
+ }
1260
1311
1261
1312
if let Some ( expr_id) = expr {
1262
1313
let expr = hir. expect_expr ( expr_id) ;
@@ -1593,3 +1644,26 @@ impl<'v> Visitor<'v> for ReturnsVisitor<'v> {
1593
1644
hir:: intravisit:: walk_body ( self , body) ;
1594
1645
}
1595
1646
}
1647
+
1648
+ /// Collect all the awaited expressions within the input expression.
1649
+ #[ derive( Default ) ]
1650
+ struct AwaitsVisitor {
1651
+ awaits : Vec < hir:: HirId > ,
1652
+ }
1653
+
1654
+ impl < ' v > Visitor < ' v > for AwaitsVisitor {
1655
+ type Map = hir:: intravisit:: ErasedMap < ' v > ;
1656
+
1657
+ fn nested_visit_map ( & mut self ) -> hir:: intravisit:: NestedVisitorMap < Self :: Map > {
1658
+ hir:: intravisit:: NestedVisitorMap :: None
1659
+ }
1660
+
1661
+ fn visit_expr ( & mut self , ex : & ' v hir:: Expr < ' v > ) {
1662
+ match ex. kind {
1663
+ hir:: ExprKind :: Yield ( _, hir:: YieldSource :: Await { expr : Some ( id) } ) =>
1664
+ self . awaits . push ( id) ,
1665
+ _ => ( ) ,
1666
+ }
1667
+ hir:: intravisit:: walk_expr ( self , ex)
1668
+ }
1669
+ }
0 commit comments