1use rustc_ast::*;
2use rustc_attr_ir::find_attr;
3use rustc_attr_ir::target::{AstTarget, Target};
4use rustc_hir as hir;
5use rustc_hir::HirId;
6use rustc_span::{Span, span_bug};
7
8use super::{LoweringContext, MoveExprState};
9use crate::diagnostics::{ClosureCannotBeStatic, CoroutineTooManyParameters};
10use crate::{DiscardParams, FnDeclKind};
11
12impl<'hir> LoweringContext<'_, 'hir> {
13 pub(super) fn lower_expr_closure_expr(
18 &mut self,
19 e: &Expr,
20 closure: &Closure,
21 ) -> hir::Expr<'hir> {
22 let expr_hir_id = self.lower_node_id(e.id);
23 let attrs = self.lower_attrs(
24 expr_hir_id,
25 &e.attrs,
26 e.span,
27 Target::from_expr(e),
28 AstTarget::Closure(closure),
29 );
30
31 match closure.coroutine_marker {
32 Some(coroutine_marker) => self.lower_expr_coroutine_closure_with_move_exprs(
33 expr_hir_id,
34 attrs,
35 &closure.binder,
36 closure.capture_clause,
37 e.id,
38 coroutine_marker,
39 closure.constness,
40 &closure.fn_decl,
41 &closure.body,
42 closure.fn_decl_span,
43 closure.fn_arg_span,
44 e.span,
45 ),
46 None => self.lower_expr_plain_closure_with_move_exprs(
47 expr_hir_id,
48 attrs,
49 &closure.binder,
50 closure.capture_clause,
51 e.id,
52 closure.constness,
53 closure.movability,
54 &closure.fn_decl,
55 &closure.body,
56 closure.fn_decl_span,
57 closure.fn_arg_span,
58 e.span,
59 ),
60 }
61 }
62
63 fn lower_expr_coroutine_closure_with_move_exprs(
64 &mut self,
65 expr_hir_id: HirId,
66 attrs: &[rustc_attr_ir::Attribute],
67 binder: &ClosureBinder,
68 capture_clause: CaptureBy,
69 closure_id: NodeId,
70 coroutine_marker: CoroutineMarker,
71 constness: Const,
72 decl: &FnDecl,
73 body: &Expr,
74 fn_decl_span: Span,
75 fn_arg_span: Span,
76 whole_span: Span,
77 ) -> hir::Expr<'hir> {
78 let (kind, move_expr_state) =
79 self.with_move_expr_bindings(Some(MoveExprState::default()), |this| {
80 this.lower_expr_coroutine_closure(
81 binder,
82 capture_clause,
83 closure_id,
84 expr_hir_id,
85 coroutine_marker,
86 constness,
87 decl,
88 body,
89 fn_decl_span,
90 fn_arg_span,
91 attrs,
92 )
93 });
94 let Some(move_expr_state) = move_expr_state else {
95 ::rustc_span::macros::bug_impl(Some(fn_decl_span),
format_args!("coroutine closure lowering did not return `move(...)` state"),
Location::caller());span_bug!(fn_decl_span, "coroutine closure lowering did not return `move(...)` state");
96 };
97 let closure_expr =
98 hir::Expr { hir_id: expr_hir_id, kind, span: self.lower_span(whole_span) };
99
100 self.lower_expr_with_move_exprs(closure_expr, move_expr_state, body, whole_span)
101 }
102
103 fn lower_expr_plain_closure_with_move_exprs(
123 &mut self,
124 expr_hir_id: HirId,
125 attrs: &[rustc_attr_ir::Attribute],
126 binder: &ClosureBinder,
127 capture_clause: CaptureBy,
128 closure_id: NodeId,
129 constness: Const,
130 movability: Movability,
131 decl: &FnDecl,
132 body: &Expr,
133 fn_decl_span: Span,
134 fn_arg_span: Span,
135 whole_span: Span,
136 ) -> hir::Expr<'hir> {
137 let (closure_kind, move_expr_state) = self.lower_expr_closure(
138 attrs,
139 binder,
140 capture_clause,
141 closure_id,
142 expr_hir_id,
143 constness,
144 movability,
145 decl,
146 body,
147 fn_decl_span,
148 fn_arg_span,
149 );
150
151 let closure_expr = hir::Expr {
152 hir_id: expr_hir_id,
153 kind: closure_kind,
154 span: self.lower_span(whole_span),
155 };
156
157 self.lower_expr_with_move_exprs(closure_expr, move_expr_state, body, whole_span)
158 }
159
160 fn lower_expr_closure(
164 &mut self,
165 attrs: &[rustc_attr_ir::Attribute],
166 binder: &ClosureBinder,
167 capture_clause: CaptureBy,
168 closure_id: NodeId,
169 closure_hir_id: HirId,
170 constness: Const,
171 movability: Movability,
172 decl: &FnDecl,
173 body: &Expr,
174 fn_decl_span: Span,
175 fn_arg_span: Span,
176 ) -> (hir::ExprKind<'hir>, MoveExprState<'hir>) {
177 let closure_def_id = self.local_def_id(closure_id);
178 let (binder_clause, generic_params) = self.lower_closure_binder(binder);
179
180 let ((body_id, closure_kind), move_expr_state) =
181 self.with_new_scopes(fn_decl_span, move |this| {
182 let mut coroutine_kind = {
'done:
{
for i in attrs {
#[allow(unused_imports)]
use ::rustc_attr_ir::AttributeKind::*;
let i: &::rustc_attr_ir::Attribute = i;
match i {
::rustc_attr_ir::Attribute::Parsed(Coroutine) => {
break 'done
Some(hir::CoroutineKind::Coroutine(Movability::Movable));
}
::rustc_attr_ir::Attribute::Tool(..) |
::rustc_attr_ir::Attribute::DeriveHelper(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}find_attr!(
183 attrs,
184 Coroutine => hir::CoroutineKind::Coroutine(Movability::Movable)
185 );
186
187 this.with_move_expr_bindings(Some(MoveExprState::default()), |this| {
188 let body_id = this.lower_fn_body(decl, None, |this| {
190 this.coroutine_kind = coroutine_kind;
191 let e = this.lower_expr_mut(body);
192 coroutine_kind = this.coroutine_kind;
193 e
194 });
195 let coroutine_option = this.closure_movability_for_fn(
196 decl,
197 fn_decl_span,
198 coroutine_kind,
199 movability,
200 );
201 (body_id, coroutine_option)
202 })
203 });
204 let Some(move_expr_state) = move_expr_state else {
205 ::rustc_span::macros::bug_impl(Some(fn_decl_span),
format_args!("plain closure lowering did not return `move(...)` state"),
Location::caller());span_bug!(fn_decl_span, "plain closure lowering did not return `move(...)` state");
206 };
207 let explicit_captures: &'hir [hir::ExplicitCapture] = self.arena.alloc_from_iter(
208 move_expr_state
209 .occurrences
210 .iter()
211 .map(|occurrence| hir::ExplicitCapture { var_hir_id: occurrence.binding }),
212 );
213
214 let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params);
215 let fn_decl = self.lower_fn_decl(
217 decl,
218 closure_id,
219 closure_hir_id,
220 FnDeclKind::Closure,
221 None,
222 DiscardParams::No,
223 );
224
225 let c = self.arena.alloc(hir::Closure {
226 def_id: closure_def_id,
227 binder: binder_clause,
228 capture_clause: self.lower_capture_clause(capture_clause),
229 bound_generic_params,
230 fn_decl,
231 body: body_id,
232 fn_decl_span: self.lower_span(fn_decl_span),
233 fn_arg_span: Some(self.lower_span(fn_arg_span)),
234 kind: closure_kind,
235 constness: self.lower_constness(attrs, constness),
236 explicit_captures,
237 });
238
239 (hir::ExprKind::Closure(c), move_expr_state)
240 }
241
242 fn closure_movability_for_fn(
243 &mut self,
244 decl: &FnDecl,
245 fn_decl_span: Span,
246 coroutine_kind: Option<hir::CoroutineKind>,
247 movability: Movability,
248 ) -> hir::ClosureKind {
249 match coroutine_kind {
250 Some(hir::CoroutineKind::Coroutine(_)) => {
251 if decl.inputs.len() > 1 {
252 self.dcx().emit_err(CoroutineTooManyParameters { fn_decl_span });
253 }
254 hir::ClosureKind::Coroutine(hir::CoroutineKind::Coroutine(movability))
255 }
256 Some(
257 hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)
258 | hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)
259 | hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _),
260 ) => {
261 {
::core::panicking::panic_fmt(format_args!("non-`async`/`gen` closure body turned `async`/`gen` during lowering"));
};panic!("non-`async`/`gen` closure body turned `async`/`gen` during lowering");
262 }
263 None => {
264 if movability == Movability::Static {
265 self.dcx().emit_err(ClosureCannotBeStatic { fn_decl_span });
266 }
267 hir::ClosureKind::Closure
268 }
269 }
270 }
271
272 fn lower_closure_binder<'c>(
273 &mut self,
274 binder: &'c ClosureBinder,
275 ) -> (hir::ClosureBinder, &'c [GenericParam]) {
276 let (binder, params) = match binder {
277 ClosureBinder::NotPresent => (hir::ClosureBinder::Default, &[][..]),
278 ClosureBinder::For { span, generic_params } => {
279 let span = self.lower_span(*span);
280 (hir::ClosureBinder::For { span }, &**generic_params)
281 }
282 };
283
284 (binder, params)
285 }
286
287 fn lower_expr_coroutine_closure(
292 &mut self,
293 binder: &ClosureBinder,
294 capture_clause: CaptureBy,
295 closure_id: NodeId,
296 closure_hir_id: HirId,
297 coroutine_marker: CoroutineMarker,
298 constness: Const,
299 decl: &FnDecl,
300 body: &Expr,
301 fn_decl_span: Span,
302 fn_arg_span: Span,
303 attrs: &[rustc_attr_ir::Attribute],
304 ) -> hir::ExprKind<'hir> {
305 let closure_def_id = self.local_def_id(closure_id);
306 let (binder_clause, generic_params) = self.lower_closure_binder(binder);
307
308 let coroutine_desugaring = match coroutine_marker.kind {
309 CoroutineKind::Async => hir::CoroutineDesugaring::Async,
310 CoroutineKind::Gen => hir::CoroutineDesugaring::Gen,
311 CoroutineKind::AsyncGen => {
312 ::rustc_span::macros::bug_impl(Some(coroutine_marker.span),
format_args!("only async closures and `iter!` closures are supported currently"),
Location::caller())span_bug!(
313 coroutine_marker.span,
314 "only async closures and `iter!` closures are supported currently"
315 )
316 }
317 };
318
319 let body = self.with_new_scopes(fn_decl_span, |this| {
320 let inner_decl =
321 FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) };
322
323 let body_id = this.lower_body(|this| {
326 let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments(
327 &inner_decl,
328 |this| this.with_new_scopes(fn_decl_span, |this| this.lower_expr_mut(body)),
329 fn_decl_span,
330 body.span,
331 coroutine_marker,
332 hir::CoroutineSource::Closure,
333 );
334
335 this.maybe_forward_track_caller(closure_hir_id, expr.hir_id);
336
337 (parameters, expr)
338 });
339 body_id
340 });
341
342 let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params);
343 let fn_decl = self.lower_fn_decl(
347 &decl,
348 closure_id,
349 closure_hir_id,
350 FnDeclKind::Closure,
351 None,
352 DiscardParams::No,
353 );
354
355 if let Const::Yes(span) = constness {
356 self.dcx().span_err(span, "const coroutines are not supported");
357 }
358
359 let explicit_captures: &'hir [hir::ExplicitCapture] = self.arena.alloc_from_iter(
360 self.move_expr_bindings
361 .last()
362 .and_then(Option::as_ref)
363 .into_iter()
364 .flat_map(|state| &state.occurrences)
365 .map(|occurrence| hir::ExplicitCapture { var_hir_id: occurrence.binding }),
366 );
367
368 let c = self.arena.alloc(hir::Closure {
369 def_id: closure_def_id,
370 binder: binder_clause,
371 capture_clause: self.lower_capture_clause(capture_clause),
372 bound_generic_params,
373 fn_decl,
374 body,
375 fn_decl_span: self.lower_span(fn_decl_span),
376 fn_arg_span: Some(self.lower_span(fn_arg_span)),
377 kind: hir::ClosureKind::CoroutineClosure(coroutine_desugaring),
381 constness: self.lower_constness(attrs, constness),
382 explicit_captures,
383 });
384 hir::ExprKind::Closure(c)
385 }
386}