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