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