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