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