@@ -1082,194 +1082,215 @@ impl<'hir> LoweringContext<'_, 'hir> {
1082
1082
let ( Some ( coroutine_kind) , Some ( body) ) = ( coroutine_kind, body) else {
1083
1083
return self . lower_fn_body_block ( span, decl, body) ;
1084
1084
} ;
1085
- let closure_id = coroutine_kind. closure_id ( ) ;
1086
-
1087
1085
self . lower_body ( |this| {
1088
- let mut parameters: Vec < hir:: Param < ' _ > > = Vec :: new ( ) ;
1089
- let mut statements: Vec < hir:: Stmt < ' _ > > = Vec :: new ( ) ;
1090
-
1091
- // Async function parameters are lowered into the closure body so that they are
1092
- // captured and so that the drop order matches the equivalent non-async functions.
1093
- //
1094
- // from:
1095
- //
1096
- // async fn foo(<pattern>: <ty>, <pattern>: <ty>, <pattern>: <ty>) {
1097
- // <body>
1098
- // }
1099
- //
1100
- // into:
1101
- //
1102
- // fn foo(__arg0: <ty>, __arg1: <ty>, __arg2: <ty>) {
1103
- // async move {
1104
- // let __arg2 = __arg2;
1105
- // let <pattern> = __arg2;
1106
- // let __arg1 = __arg1;
1107
- // let <pattern> = __arg1;
1108
- // let __arg0 = __arg0;
1109
- // let <pattern> = __arg0;
1110
- // drop-temps { <body> } // see comments later in fn for details
1111
- // }
1112
- // }
1113
- //
1114
- // If `<pattern>` is a simple ident, then it is lowered to a single
1115
- // `let <pattern> = <pattern>;` statement as an optimization.
1116
- //
1117
- // Note that the body is embedded in `drop-temps`; an
1118
- // equivalent desugaring would be `return { <body>
1119
- // };`. The key point is that we wish to drop all the
1120
- // let-bound variables and temporaries created in the body
1121
- // (and its tail expression!) before we drop the
1122
- // parameters (c.f. rust-lang/rust#64512).
1123
- for ( index, parameter) in decl. inputs . iter ( ) . enumerate ( ) {
1124
- let parameter = this. lower_param ( parameter) ;
1125
- let span = parameter. pat . span ;
1126
-
1127
- // Check if this is a binding pattern, if so, we can optimize and avoid adding a
1128
- // `let <pat> = __argN;` statement. In this case, we do not rename the parameter.
1129
- let ( ident, is_simple_parameter) = match parameter. pat . kind {
1130
- hir:: PatKind :: Binding ( hir:: BindingAnnotation ( ByRef :: No , _) , _, ident, _) => {
1131
- ( ident, true )
1132
- }
1133
- // For `ref mut` or wildcard arguments, we can't reuse the binding, but
1134
- // we can keep the same name for the parameter.
1135
- // This lets rustdoc render it correctly in documentation.
1136
- hir:: PatKind :: Binding ( _, _, ident, _) => ( ident, false ) ,
1137
- hir:: PatKind :: Wild => {
1138
- ( Ident :: with_dummy_span ( rustc_span:: symbol:: kw:: Underscore ) , false )
1139
- }
1140
- _ => {
1141
- // Replace the ident for bindings that aren't simple.
1142
- let name = format ! ( "__arg{index}" ) ;
1143
- let ident = Ident :: from_str ( & name) ;
1144
-
1145
- ( ident, false )
1146
- }
1147
- } ;
1148
-
1149
- let desugared_span = this. mark_span_with_reason ( DesugaringKind :: Async , span, None ) ;
1150
-
1151
- // Construct a parameter representing `__argN: <ty>` to replace the parameter of the
1152
- // async function.
1153
- //
1154
- // If this is the simple case, this parameter will end up being the same as the
1155
- // original parameter, but with a different pattern id.
1156
- let stmt_attrs = this. attrs . get ( & parameter. hir_id . local_id ) . copied ( ) ;
1157
- let ( new_parameter_pat, new_parameter_id) = this. pat_ident ( desugared_span, ident) ;
1158
- let new_parameter = hir:: Param {
1159
- hir_id : parameter. hir_id ,
1160
- pat : new_parameter_pat,
1161
- ty_span : this. lower_span ( parameter. ty_span ) ,
1162
- span : this. lower_span ( parameter. span ) ,
1163
- } ;
1086
+ let ( parameters, expr) = this. lower_coroutine_body_with_moved_arguments (
1087
+ decl,
1088
+ body,
1089
+ coroutine_kind,
1090
+ CaptureBy :: Value { move_kw : rustc_span:: DUMMY_SP } ,
1091
+ ) ;
1164
1092
1165
- if is_simple_parameter {
1166
- // If this is the simple case, then we only insert one statement that is
1167
- // `let <pat> = <pat>;`. We re-use the original argument's pattern so that
1168
- // `HirId`s are densely assigned.
1169
- let expr = this. expr_ident ( desugared_span, ident, new_parameter_id) ;
1170
- let stmt = this. stmt_let_pat (
1171
- stmt_attrs,
1172
- desugared_span,
1173
- Some ( expr) ,
1174
- parameter. pat ,
1175
- hir:: LocalSource :: AsyncFn ,
1176
- ) ;
1177
- statements. push ( stmt) ;
1178
- } else {
1179
- // If this is not the simple case, then we construct two statements:
1180
- //
1181
- // ```
1182
- // let __argN = __argN;
1183
- // let <pat> = __argN;
1184
- // ```
1185
- //
1186
- // The first statement moves the parameter into the closure and thus ensures
1187
- // that the drop order is correct.
1188
- //
1189
- // The second statement creates the bindings that the user wrote.
1190
-
1191
- // Construct the `let mut __argN = __argN;` statement. It must be a mut binding
1192
- // because the user may have specified a `ref mut` binding in the next
1193
- // statement.
1194
- let ( move_pat, move_id) = this. pat_ident_binding_mode (
1195
- desugared_span,
1196
- ident,
1197
- hir:: BindingAnnotation :: MUT ,
1198
- ) ;
1199
- let move_expr = this. expr_ident ( desugared_span, ident, new_parameter_id) ;
1200
- let move_stmt = this. stmt_let_pat (
1201
- None ,
1202
- desugared_span,
1203
- Some ( move_expr) ,
1204
- move_pat,
1205
- hir:: LocalSource :: AsyncFn ,
1206
- ) ;
1093
+ // FIXME(async_fn_track_caller): Can this be moved above?
1094
+ let hir_id = this. lower_node_id ( coroutine_kind. closure_id ( ) ) ;
1095
+ this. maybe_forward_track_caller ( body. span , fn_id, hir_id) ;
1207
1096
1208
- // Construct the `let <pat> = __argN;` statement. We re-use the original
1209
- // parameter's pattern so that `HirId`s are densely assigned.
1210
- let pattern_expr = this. expr_ident ( desugared_span, ident, move_id) ;
1211
- let pattern_stmt = this. stmt_let_pat (
1212
- stmt_attrs,
1213
- desugared_span,
1214
- Some ( pattern_expr) ,
1215
- parameter. pat ,
1216
- hir:: LocalSource :: AsyncFn ,
1217
- ) ;
1097
+ ( parameters, expr)
1098
+ } )
1099
+ }
1218
1100
1219
- statements. push ( move_stmt) ;
1220
- statements. push ( pattern_stmt) ;
1221
- } ;
1101
+ /// Lowers a desugared coroutine body after moving all of the arguments
1102
+ /// into the body. This makes sure that
1103
+ fn lower_coroutine_body_with_moved_arguments (
1104
+ & mut self ,
1105
+ decl : & FnDecl ,
1106
+ body : & Block ,
1107
+ coroutine_kind : CoroutineKind ,
1108
+ capture_clause : CaptureBy ,
1109
+ ) -> ( & ' hir [ hir:: Param < ' hir > ] , hir:: Expr < ' hir > ) {
1110
+ let mut parameters: Vec < hir:: Param < ' _ > > = Vec :: new ( ) ;
1111
+ let mut statements: Vec < hir:: Stmt < ' _ > > = Vec :: new ( ) ;
1112
+
1113
+ // Async function parameters are lowered into the closure body so that they are
1114
+ // captured and so that the drop order matches the equivalent non-async functions.
1115
+ //
1116
+ // from:
1117
+ //
1118
+ // async fn foo(<pattern>: <ty>, <pattern>: <ty>, <pattern>: <ty>) {
1119
+ // <body>
1120
+ // }
1121
+ //
1122
+ // into:
1123
+ //
1124
+ // fn foo(__arg0: <ty>, __arg1: <ty>, __arg2: <ty>) {
1125
+ // async move {
1126
+ // let __arg2 = __arg2;
1127
+ // let <pattern> = __arg2;
1128
+ // let __arg1 = __arg1;
1129
+ // let <pattern> = __arg1;
1130
+ // let __arg0 = __arg0;
1131
+ // let <pattern> = __arg0;
1132
+ // drop-temps { <body> } // see comments later in fn for details
1133
+ // }
1134
+ // }
1135
+ //
1136
+ // If `<pattern>` is a simple ident, then it is lowered to a single
1137
+ // `let <pattern> = <pattern>;` statement as an optimization.
1138
+ //
1139
+ // Note that the body is embedded in `drop-temps`; an
1140
+ // equivalent desugaring would be `return { <body>
1141
+ // };`. The key point is that we wish to drop all the
1142
+ // let-bound variables and temporaries created in the body
1143
+ // (and its tail expression!) before we drop the
1144
+ // parameters (c.f. rust-lang/rust#64512).
1145
+ for ( index, parameter) in decl. inputs . iter ( ) . enumerate ( ) {
1146
+ let parameter = self . lower_param ( parameter) ;
1147
+ let span = parameter. pat . span ;
1148
+
1149
+ // Check if this is a binding pattern, if so, we can optimize and avoid adding a
1150
+ // `let <pat> = __argN;` statement. In this case, we do not rename the parameter.
1151
+ let ( ident, is_simple_parameter) = match parameter. pat . kind {
1152
+ hir:: PatKind :: Binding ( hir:: BindingAnnotation ( ByRef :: No , _) , _, ident, _) => {
1153
+ ( ident, true )
1154
+ }
1155
+ // For `ref mut` or wildcard arguments, we can't reuse the binding, but
1156
+ // we can keep the same name for the parameter.
1157
+ // This lets rustdoc render it correctly in documentation.
1158
+ hir:: PatKind :: Binding ( _, _, ident, _) => ( ident, false ) ,
1159
+ hir:: PatKind :: Wild => {
1160
+ ( Ident :: with_dummy_span ( rustc_span:: symbol:: kw:: Underscore ) , false )
1161
+ }
1162
+ _ => {
1163
+ // Replace the ident for bindings that aren't simple.
1164
+ let name = format ! ( "__arg{index}" ) ;
1165
+ let ident = Ident :: from_str ( & name) ;
1222
1166
1223
- parameters. push ( new_parameter) ;
1224
- }
1167
+ ( ident, false )
1168
+ }
1169
+ } ;
1225
1170
1226
- let mkbody = |this : & mut LoweringContext < ' _ , ' hir > | {
1227
- // Create a block from the user's function body:
1228
- let user_body = this. lower_block_expr ( body) ;
1171
+ let desugared_span = self . mark_span_with_reason ( DesugaringKind :: Async , span, None ) ;
1229
1172
1230
- // Transform into `drop-temps { <user-body> }`, an expression:
1231
- let desugared_span =
1232
- this. mark_span_with_reason ( DesugaringKind :: Async , user_body. span , None ) ;
1233
- let user_body = this. expr_drop_temps ( desugared_span, this. arena . alloc ( user_body) ) ;
1173
+ // Construct a parameter representing `__argN: <ty>` to replace the parameter of the
1174
+ // async function.
1175
+ //
1176
+ // If this is the simple case, this parameter will end up being the same as the
1177
+ // original parameter, but with a different pattern id.
1178
+ let stmt_attrs = self . attrs . get ( & parameter. hir_id . local_id ) . copied ( ) ;
1179
+ let ( new_parameter_pat, new_parameter_id) = self . pat_ident ( desugared_span, ident) ;
1180
+ let new_parameter = hir:: Param {
1181
+ hir_id : parameter. hir_id ,
1182
+ pat : new_parameter_pat,
1183
+ ty_span : self . lower_span ( parameter. ty_span ) ,
1184
+ span : self . lower_span ( parameter. span ) ,
1185
+ } ;
1234
1186
1235
- // As noted above, create the final block like
1187
+ if is_simple_parameter {
1188
+ // If this is the simple case, then we only insert one statement that is
1189
+ // `let <pat> = <pat>;`. We re-use the original argument's pattern so that
1190
+ // `HirId`s are densely assigned.
1191
+ let expr = self . expr_ident ( desugared_span, ident, new_parameter_id) ;
1192
+ let stmt = self . stmt_let_pat (
1193
+ stmt_attrs,
1194
+ desugared_span,
1195
+ Some ( expr) ,
1196
+ parameter. pat ,
1197
+ hir:: LocalSource :: AsyncFn ,
1198
+ ) ;
1199
+ statements. push ( stmt) ;
1200
+ } else {
1201
+ // If this is not the simple case, then we construct two statements:
1236
1202
//
1237
1203
// ```
1238
- // {
1239
- // let $param_pattern = $raw_param;
1240
- // ...
1241
- // drop-temps { <user-body> }
1242
- // }
1204
+ // let __argN = __argN;
1205
+ // let <pat> = __argN;
1243
1206
// ```
1244
- let body = this. block_all (
1207
+ //
1208
+ // The first statement moves the parameter into the closure and thus ensures
1209
+ // that the drop order is correct.
1210
+ //
1211
+ // The second statement creates the bindings that the user wrote.
1212
+
1213
+ // Construct the `let mut __argN = __argN;` statement. It must be a mut binding
1214
+ // because the user may have specified a `ref mut` binding in the next
1215
+ // statement.
1216
+ let ( move_pat, move_id) =
1217
+ self . pat_ident_binding_mode ( desugared_span, ident, hir:: BindingAnnotation :: MUT ) ;
1218
+ let move_expr = self . expr_ident ( desugared_span, ident, new_parameter_id) ;
1219
+ let move_stmt = self . stmt_let_pat (
1220
+ None ,
1245
1221
desugared_span,
1246
- this. arena . alloc_from_iter ( statements) ,
1247
- Some ( user_body) ,
1222
+ Some ( move_expr) ,
1223
+ move_pat,
1224
+ hir:: LocalSource :: AsyncFn ,
1248
1225
) ;
1249
1226
1250
- this. expr_block ( body)
1251
- } ;
1252
- let desugaring_kind = match coroutine_kind {
1253
- CoroutineKind :: Async { .. } => hir:: CoroutineDesugaring :: Async ,
1254
- CoroutineKind :: Gen { .. } => hir:: CoroutineDesugaring :: Gen ,
1255
- CoroutineKind :: AsyncGen { .. } => hir:: CoroutineDesugaring :: AsyncGen ,
1227
+ // Construct the `let <pat> = __argN;` statement. We re-use the original
1228
+ // parameter's pattern so that `HirId`s are densely assigned.
1229
+ let pattern_expr = self . expr_ident ( desugared_span, ident, move_id) ;
1230
+ let pattern_stmt = self . stmt_let_pat (
1231
+ stmt_attrs,
1232
+ desugared_span,
1233
+ Some ( pattern_expr) ,
1234
+ parameter. pat ,
1235
+ hir:: LocalSource :: AsyncFn ,
1236
+ ) ;
1237
+
1238
+ statements. push ( move_stmt) ;
1239
+ statements. push ( pattern_stmt) ;
1256
1240
} ;
1257
- let coroutine_expr = this. make_desugared_coroutine_expr (
1258
- CaptureBy :: Value { move_kw : rustc_span:: DUMMY_SP } ,
1259
- closure_id,
1260
- None ,
1261
- body. span ,
1262
- desugaring_kind,
1263
- hir:: CoroutineSource :: Fn ,
1264
- mkbody,
1241
+
1242
+ parameters. push ( new_parameter) ;
1243
+ }
1244
+
1245
+ let mkbody = |this : & mut LoweringContext < ' _ , ' hir > | {
1246
+ // Create a block from the user's function body:
1247
+ let user_body = this. lower_block_expr ( body) ;
1248
+
1249
+ // Transform into `drop-temps { <user-body> }`, an expression:
1250
+ let desugared_span =
1251
+ this. mark_span_with_reason ( DesugaringKind :: Async , user_body. span , None ) ;
1252
+ let user_body = this. expr_drop_temps ( desugared_span, this. arena . alloc ( user_body) ) ;
1253
+
1254
+ // As noted above, create the final block like
1255
+ //
1256
+ // ```
1257
+ // {
1258
+ // let $param_pattern = $raw_param;
1259
+ // ...
1260
+ // drop-temps { <user-body> }
1261
+ // }
1262
+ // ```
1263
+ let body = this. block_all (
1264
+ desugared_span,
1265
+ this. arena . alloc_from_iter ( statements) ,
1266
+ Some ( user_body) ,
1265
1267
) ;
1266
1268
1267
- let hir_id = this. lower_node_id ( closure_id) ;
1268
- this. maybe_forward_track_caller ( body. span , fn_id, hir_id) ;
1269
- let expr = hir:: Expr { hir_id, kind : coroutine_expr, span : this. lower_span ( body. span ) } ;
1269
+ this. expr_block ( body)
1270
+ } ;
1271
+ let desugaring_kind = match coroutine_kind {
1272
+ CoroutineKind :: Async { .. } => hir:: CoroutineDesugaring :: Async ,
1273
+ CoroutineKind :: Gen { .. } => hir:: CoroutineDesugaring :: Gen ,
1274
+ CoroutineKind :: AsyncGen { .. } => hir:: CoroutineDesugaring :: AsyncGen ,
1275
+ } ;
1276
+ let closure_id = coroutine_kind. closure_id ( ) ;
1277
+ let coroutine_expr = self . make_desugared_coroutine_expr (
1278
+ capture_clause,
1279
+ closure_id,
1280
+ None ,
1281
+ body. span ,
1282
+ desugaring_kind,
1283
+ hir:: CoroutineSource :: Fn ,
1284
+ mkbody,
1285
+ ) ;
1270
1286
1271
- ( this. arena . alloc_from_iter ( parameters) , expr)
1272
- } )
1287
+ let expr = hir:: Expr {
1288
+ hir_id : self . lower_node_id ( closure_id) ,
1289
+ kind : coroutine_expr,
1290
+ span : self . lower_span ( body. span ) ,
1291
+ } ;
1292
+
1293
+ ( self . arena . alloc_from_iter ( parameters) , expr)
1273
1294
}
1274
1295
1275
1296
fn lower_method_sig (
0 commit comments