1use rustc_ast::node_id::NodeMap;
2use rustc_ast::*;
3use rustc_hir as hir;
4use rustc_hir::{HirId, Target, find_attr};
5use rustc_middle::span_bug;
6use rustc_span::Span;
7
8use super::{LoweringContext, MoveExprInitializerFinder, MoveExprState};
9use crate::FnDeclKind;
10use crate::errors::{ClosureCannotBeStatic, CoroutineTooManyParameters};
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(expr_hir_id, &e.attrs, e.span, Target::from_expr(e));
24
25 match closure.coroutine_kind {
26 Some(coroutine_kind) => hir::Expr {
29 hir_id: expr_hir_id,
30 kind: self.lower_expr_coroutine_closure(
31 &closure.binder,
32 closure.capture_clause,
33 e.id,
34 expr_hir_id,
35 coroutine_kind,
36 closure.constness,
37 &closure.fn_decl,
38 &closure.body,
39 closure.fn_decl_span,
40 closure.fn_arg_span,
41 ),
42 span: self.lower_span(e.span),
43 },
44 None => self.lower_expr_plain_closure_with_move_exprs(
45 expr_hir_id,
46 attrs,
47 &closure.binder,
48 closure.capture_clause,
49 e.id,
50 closure.constness,
51 closure.movability,
52 &closure.fn_decl,
53 &closure.body,
54 closure.fn_decl_span,
55 closure.fn_arg_span,
56 e.span,
57 ),
58 }
59 }
60
61 fn lower_expr_plain_closure_with_move_exprs(
92 &mut self,
93 expr_hir_id: HirId,
94 attrs: &[hir::Attribute],
95 binder: &ClosureBinder,
96 capture_clause: CaptureBy,
97 closure_id: NodeId,
98 constness: Const,
99 movability: Movability,
100 decl: &FnDecl,
101 body: &Expr,
102 fn_decl_span: Span,
103 fn_arg_span: Span,
104 whole_span: Span,
105 ) -> hir::Expr<'hir> {
106 let (closure_kind, move_expr_state) = self.lower_expr_closure(
107 attrs,
108 binder,
109 capture_clause,
110 closure_id,
111 constness,
112 movability,
113 decl,
114 body,
115 fn_decl_span,
116 fn_arg_span,
117 );
118
119 if move_expr_state.occurrences.is_empty() {
120 return hir::Expr {
121 hir_id: expr_hir_id,
122 kind: closure_kind,
123 span: self.lower_span(whole_span),
124 };
125 }
126
127 let initializers = MoveExprInitializerFinder::collect(body)
128 .into_iter()
129 .map(|initializer| (initializer.id, initializer.expr))
130 .collect::<NodeMap<_>>();
131 let mut stmts = Vec::with_capacity(move_expr_state.occurrences.len());
132 let mut initializer_bindings = NodeMap::default();
133 for occurrence in &move_expr_state.occurrences {
134 let expr = initializers[&occurrence.id];
139 let init = if initializer_bindings.is_empty() {
140 self.lower_expr(expr)
141 } else {
142 let (init, _) = self.with_move_expr_bindings(
146 Some(MoveExprState {
147 bindings: initializer_bindings.clone(),
148 occurrences: Vec::new(),
149 }),
150 |this| this.lower_expr(expr),
151 );
152 init
153 };
154 stmts.push(self.stmt_let_pat(
155 None,
156 expr.span,
157 Some(init),
158 occurrence.pat,
159 hir::LocalSource::Normal,
160 ));
161 initializer_bindings.insert(occurrence.id, (occurrence.ident, occurrence.binding));
162 }
163
164 let closure_expr = self.arena.alloc(hir::Expr {
165 hir_id: expr_hir_id,
166 kind: closure_kind,
167 span: self.lower_span(whole_span),
168 });
169
170 let stmts = self.arena.alloc_from_iter(stmts);
171 let block = self.block_all(whole_span, stmts, Some(closure_expr));
172 self.expr(whole_span, hir::ExprKind::Block(block, None))
173 }
174
175 fn lower_expr_closure(
179 &mut self,
180 attrs: &[hir::Attribute],
181 binder: &ClosureBinder,
182 capture_clause: CaptureBy,
183 closure_id: NodeId,
184 constness: Const,
185 movability: Movability,
186 decl: &FnDecl,
187 body: &Expr,
188 fn_decl_span: Span,
189 fn_arg_span: Span,
190 ) -> (hir::ExprKind<'hir>, MoveExprState<'hir>) {
191 let closure_def_id = self.local_def_id(closure_id);
192 let (binder_clause, generic_params) = self.lower_closure_binder(binder);
193
194 let ((body_id, closure_kind), move_expr_state) =
195 self.with_new_scopes(fn_decl_span, move |this| {
196 let mut coroutine_kind = {
'done:
{
for i in attrs {
#[allow(unused_imports)]
use rustc_hir::attrs::AttributeKind::*;
let i: &rustc_hir::Attribute = i;
match i {
rustc_hir::Attribute::Parsed(Coroutine) => {
break 'done
Some(hir::CoroutineKind::Coroutine(Movability::Movable));
}
rustc_hir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}find_attr!(
197 attrs,
198 Coroutine => hir::CoroutineKind::Coroutine(Movability::Movable)
199 );
200
201 this.with_move_expr_bindings(Some(MoveExprState::default()), |this| {
202 let body_id = this.lower_fn_body(decl, None, |this| {
204 this.coroutine_kind = coroutine_kind;
205 let e = this.lower_expr_mut(body);
206 coroutine_kind = this.coroutine_kind;
207 e
208 });
209 let coroutine_option = this.closure_movability_for_fn(
210 decl,
211 fn_decl_span,
212 coroutine_kind,
213 movability,
214 );
215 (body_id, coroutine_option)
216 })
217 });
218 let Some(move_expr_state) = move_expr_state else {
219 ::rustc_middle::util::bug::span_bug_fmt(fn_decl_span,
format_args!("plain closure lowering did not return `move(...)` state"));span_bug!(fn_decl_span, "plain closure lowering did not return `move(...)` state");
220 };
221 let explicit_captures: &'hir [hir::ExplicitCapture] = self.arena.alloc_from_iter(
222 move_expr_state.occurrences.iter().filter_map(|occurrence| {
223 occurrence
224 .explicit_capture
225 .then_some(hir::ExplicitCapture { var_hir_id: occurrence.binding })
226 }),
227 );
228
229 let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params);
230 let fn_decl = self.lower_fn_decl(decl, closure_id, fn_decl_span, FnDeclKind::Closure, None);
232
233 let c = self.arena.alloc(hir::Closure {
234 def_id: closure_def_id,
235 binder: binder_clause,
236 capture_clause: self.lower_capture_clause(capture_clause),
237 bound_generic_params,
238 fn_decl,
239 body: body_id,
240 fn_decl_span: self.lower_span(fn_decl_span),
241 fn_arg_span: Some(self.lower_span(fn_arg_span)),
242 kind: closure_kind,
243 constness: self.lower_constness(constness),
244 explicit_captures,
245 });
246
247 (hir::ExprKind::Closure(c), move_expr_state)
248 }
249
250 fn closure_movability_for_fn(
251 &mut self,
252 decl: &FnDecl,
253 fn_decl_span: Span,
254 coroutine_kind: Option<hir::CoroutineKind>,
255 movability: Movability,
256 ) -> hir::ClosureKind {
257 match coroutine_kind {
258 Some(hir::CoroutineKind::Coroutine(_)) => {
259 if decl.inputs.len() > 1 {
260 self.dcx().emit_err(CoroutineTooManyParameters { fn_decl_span });
261 }
262 hir::ClosureKind::Coroutine(hir::CoroutineKind::Coroutine(movability))
263 }
264 Some(
265 hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)
266 | hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)
267 | hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _),
268 ) => {
269 {
::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");
270 }
271 None => {
272 if movability == Movability::Static {
273 self.dcx().emit_err(ClosureCannotBeStatic { fn_decl_span });
274 }
275 hir::ClosureKind::Closure
276 }
277 }
278 }
279
280 fn lower_closure_binder<'c>(
281 &mut self,
282 binder: &'c ClosureBinder,
283 ) -> (hir::ClosureBinder, &'c [GenericParam]) {
284 let (binder, params) = match binder {
285 ClosureBinder::NotPresent => (hir::ClosureBinder::Default, &[][..]),
286 ClosureBinder::For { span, generic_params } => {
287 let span = self.lower_span(*span);
288 (hir::ClosureBinder::For { span }, &**generic_params)
289 }
290 };
291
292 (binder, params)
293 }
294
295 fn lower_expr_coroutine_closure(
300 &mut self,
301 binder: &ClosureBinder,
302 capture_clause: CaptureBy,
303 closure_id: NodeId,
304 closure_hir_id: HirId,
305 coroutine_kind: CoroutineKind,
306 constness: Const,
307 decl: &FnDecl,
308 body: &Expr,
309 fn_decl_span: Span,
310 fn_arg_span: Span,
311 ) -> hir::ExprKind<'hir> {
312 let closure_def_id = self.local_def_id(closure_id);
313 let (binder_clause, generic_params) = self.lower_closure_binder(binder);
314
315 let coroutine_desugaring = match coroutine_kind {
316 CoroutineKind::Async { .. } => hir::CoroutineDesugaring::Async,
317 CoroutineKind::Gen { .. } => hir::CoroutineDesugaring::Gen,
318 CoroutineKind::AsyncGen { span, .. } => {
319 ::rustc_middle::util::bug::span_bug_fmt(span,
format_args!("only async closures and `iter!` closures are supported currently"))span_bug!(span, "only async closures and `iter!` closures are supported currently")
320 }
321 };
322
323 let body = self.with_new_scopes(fn_decl_span, |this| {
324 let inner_decl =
325 FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) };
326
327 let body_id = this.lower_body(|this| {
330 let ((parameters, expr), _) = this.with_move_expr_bindings(None, |this| {
331 this.lower_coroutine_body_with_moved_arguments(
332 &inner_decl,
333 |this| this.with_new_scopes(fn_decl_span, |this| this.lower_expr_mut(body)),
334 fn_decl_span,
335 body.span,
336 coroutine_kind,
337 hir::CoroutineSource::Closure,
338 )
339 });
340
341 this.maybe_forward_track_caller(body.span, closure_hir_id, expr.hir_id);
342
343 (parameters, expr)
344 });
345 body_id
346 });
347
348 let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params);
349 let fn_decl =
353 self.lower_fn_decl(&decl, closure_id, fn_decl_span, FnDeclKind::Closure, None);
354
355 if let Const::Yes(span) = constness {
356 self.dcx().span_err(span, "const coroutines are not supported");
357 }
358
359 let c = self.arena.alloc(hir::Closure {
360 def_id: closure_def_id,
361 binder: binder_clause,
362 capture_clause: self.lower_capture_clause(capture_clause),
363 bound_generic_params,
364 fn_decl,
365 body,
366 fn_decl_span: self.lower_span(fn_decl_span),
367 fn_arg_span: Some(self.lower_span(fn_arg_span)),
368 kind: hir::ClosureKind::CoroutineClosure(coroutine_desugaring),
372 constness: self.lower_constness(constness),
373 explicit_captures: &[],
374 });
375 hir::ExprKind::Closure(c)
376 }
377}