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