Rollup merge of #98705 - WaffleLapkin:closure_binder, r=cjgillot
Implement `for<>` lifetime binder for closures This PR implements RFC 3216 ([TI](https://github.com/rust-lang/rust/issues/97362)) and allows code like the following: ```rust let _f = for<'a, 'b> |a: &'a A, b: &'b B| -> &'b C { b.c(a) }; // ^^^^^^^^^^^--- new! ``` cc ``@Aaron1011`` ``@cjgillot``
This commit is contained in:
commit
e5a86d7358
91 changed files with 843 additions and 208 deletions
|
@ -155,6 +155,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
self.lower_expr_await(span, expr)
|
||||
}
|
||||
ExprKind::Closure(
|
||||
ref binder,
|
||||
capture_clause,
|
||||
asyncness,
|
||||
movability,
|
||||
|
@ -164,6 +165,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
) => {
|
||||
if let Async::Yes { closure_id, .. } = asyncness {
|
||||
self.lower_expr_async_closure(
|
||||
binder,
|
||||
capture_clause,
|
||||
e.id,
|
||||
closure_id,
|
||||
|
@ -173,6 +175,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
)
|
||||
} else {
|
||||
self.lower_expr_closure(
|
||||
binder,
|
||||
capture_clause,
|
||||
e.id,
|
||||
movability,
|
||||
|
@ -605,13 +608,18 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
});
|
||||
|
||||
// `static |_task_context| -> <ret_ty> { body }`:
|
||||
let generator_kind = hir::ExprKind::Closure {
|
||||
capture_clause,
|
||||
bound_generic_params: &[],
|
||||
fn_decl,
|
||||
body,
|
||||
fn_decl_span: self.lower_span(span),
|
||||
movability: Some(hir::Movability::Static),
|
||||
let generator_kind = {
|
||||
let c = self.arena.alloc(hir::Closure {
|
||||
binder: hir::ClosureBinder::Default,
|
||||
capture_clause,
|
||||
bound_generic_params: &[],
|
||||
fn_decl,
|
||||
body,
|
||||
fn_decl_span: self.lower_span(span),
|
||||
movability: Some(hir::Movability::Static),
|
||||
});
|
||||
|
||||
hir::ExprKind::Closure(c)
|
||||
};
|
||||
let generator = hir::Expr {
|
||||
hir_id: self.lower_node_id(closure_node_id),
|
||||
|
@ -831,6 +839,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
|
||||
fn lower_expr_closure(
|
||||
&mut self,
|
||||
binder: &ClosureBinder,
|
||||
capture_clause: CaptureBy,
|
||||
closure_id: NodeId,
|
||||
movability: Movability,
|
||||
|
@ -838,7 +847,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
body: &Expr,
|
||||
fn_decl_span: Span,
|
||||
) -> hir::ExprKind<'hir> {
|
||||
let (body, generator_option) = self.with_new_scopes(move |this| {
|
||||
let (binder_clause, generic_params) = self.lower_closure_binder(binder);
|
||||
|
||||
let (body_id, generator_option) = self.with_new_scopes(move |this| {
|
||||
let prev = this.current_item;
|
||||
this.current_item = Some(fn_decl_span);
|
||||
let mut generator_kind = None;
|
||||
|
@ -853,18 +864,21 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
(body_id, generator_option)
|
||||
});
|
||||
|
||||
self.with_lifetime_binder(closure_id, &[], |this, bound_generic_params| {
|
||||
self.with_lifetime_binder(closure_id, generic_params, |this, bound_generic_params| {
|
||||
// Lower outside new scope to preserve `is_in_loop_condition`.
|
||||
let fn_decl = this.lower_fn_decl(decl, None, FnDeclKind::Closure, None);
|
||||
|
||||
hir::ExprKind::Closure {
|
||||
let c = self.arena.alloc(hir::Closure {
|
||||
binder: binder_clause,
|
||||
capture_clause,
|
||||
bound_generic_params,
|
||||
fn_decl,
|
||||
body,
|
||||
body: body_id,
|
||||
fn_decl_span: this.lower_span(fn_decl_span),
|
||||
movability: generator_option,
|
||||
}
|
||||
});
|
||||
|
||||
hir::ExprKind::Closure(c)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -906,8 +920,24 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
fn lower_closure_binder<'c>(
|
||||
&mut self,
|
||||
binder: &'c ClosureBinder,
|
||||
) -> (hir::ClosureBinder, &'c [GenericParam]) {
|
||||
let (binder, params) = match binder {
|
||||
ClosureBinder::NotPresent => (hir::ClosureBinder::Default, &[][..]),
|
||||
&ClosureBinder::For { span, ref generic_params } => {
|
||||
let span = self.lower_span(span);
|
||||
(hir::ClosureBinder::For { span }, &**generic_params)
|
||||
}
|
||||
};
|
||||
|
||||
(binder, params)
|
||||
}
|
||||
|
||||
fn lower_expr_async_closure(
|
||||
&mut self,
|
||||
binder: &ClosureBinder,
|
||||
capture_clause: CaptureBy,
|
||||
closure_id: NodeId,
|
||||
inner_closure_id: NodeId,
|
||||
|
@ -915,6 +945,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
body: &Expr,
|
||||
fn_decl_span: Span,
|
||||
) -> hir::ExprKind<'hir> {
|
||||
if let &ClosureBinder::For { span, .. } = binder {
|
||||
self.tcx.sess.span_err(
|
||||
span,
|
||||
"`for<...>` binders on `async` closures are not currently supported",
|
||||
);
|
||||
}
|
||||
|
||||
let (binder_clause, generic_params) = self.lower_closure_binder(binder);
|
||||
|
||||
let outer_decl =
|
||||
FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) };
|
||||
|
||||
|
@ -952,20 +991,22 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
body_id
|
||||
});
|
||||
|
||||
self.with_lifetime_binder(closure_id, &[], |this, bound_generic_params| {
|
||||
self.with_lifetime_binder(closure_id, generic_params, |this, bound_generic_params| {
|
||||
// We need to lower the declaration outside the new scope, because we
|
||||
// have to conserve the state of being inside a loop condition for the
|
||||
// closure argument types.
|
||||
let fn_decl = this.lower_fn_decl(&outer_decl, None, FnDeclKind::Closure, None);
|
||||
|
||||
hir::ExprKind::Closure {
|
||||
let c = self.arena.alloc(hir::Closure {
|
||||
binder: binder_clause,
|
||||
capture_clause,
|
||||
bound_generic_params,
|
||||
fn_decl,
|
||||
body,
|
||||
fn_decl_span: this.lower_span(fn_decl_span),
|
||||
movability: None,
|
||||
}
|
||||
});
|
||||
hir::ExprKind::Closure(c)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue