Skip to content

Commit 40ae7b5

Browse files
committed
Parse closure binders
This is first step in implementing RFC 3216. - Parse `for<'a>` before closures in ast - Error in lowering - Add `closure_lifetime_binder` feature
1 parent fbdb07f commit 40ae7b5

File tree

24 files changed

+287
-38
lines changed

24 files changed

+287
-38
lines changed

compiler/rustc_ast/src/ast.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1390,7 +1390,7 @@ pub enum ExprKind {
13901390
/// A closure (e.g., `move |a, b, c| a + b + c`).
13911391
///
13921392
/// The final span is the span of the argument block `|...|`.
1393-
Closure(CaptureBy, Async, Movability, P<FnDecl>, P<Expr>, Span),
1393+
Closure(ClosureBinder, CaptureBy, Async, Movability, P<FnDecl>, P<Expr>, Span),
13941394
/// A block (`'label: { ... }`).
13951395
Block(P<Block>, Option<Label>),
13961396
/// An async block (`async move { ... }`).
@@ -1518,6 +1518,31 @@ pub enum Movability {
15181518
Movable,
15191519
}
15201520

1521+
/// Closure lifetime binder, `for<'a, 'b>` in `for<'a, 'b> |_: &'a (), _: &'b ()|`.
1522+
#[derive(Clone, Encodable, Decodable, Debug)]
1523+
pub enum ClosureBinder {
1524+
/// The binder is not present, all closure lifetimes are inferred.
1525+
NotPresent,
1526+
/// The binder is present.
1527+
For {
1528+
/// Span of the whole `for<>` clause
1529+
///
1530+
/// ```text
1531+
/// for<'a, 'b> |_: &'a (), _: &'b ()| { ... }
1532+
/// ^^^^^^^^^^^ -- this
1533+
/// ```
1534+
span: Span,
1535+
1536+
/// Lifetimes in the `for<>` closure
1537+
///
1538+
/// ```text
1539+
/// for<'a, 'b> |_: &'a (), _: &'b ()| { ... }
1540+
/// ^^^^^^ -- this
1541+
/// ```
1542+
generic_params: P<[GenericParam]>,
1543+
},
1544+
}
1545+
15211546
/// Represents a macro invocation. The `path` indicates which macro
15221547
/// is being invoked, and the `args` are arguments passed to it.
15231548
#[derive(Clone, Encodable, Decodable, Debug)]

compiler/rustc_ast/src/mut_visit.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,10 @@ pub trait MutVisitor: Sized {
125125
noop_visit_asyncness(a, self);
126126
}
127127

128+
fn visit_closure_binder(&mut self, b: &mut ClosureBinder) {
129+
noop_visit_closure_binder(b, self);
130+
}
131+
128132
fn visit_block(&mut self, b: &mut P<Block>) {
129133
noop_visit_block(b, self);
130134
}
@@ -825,6 +829,17 @@ pub fn visit_constness<T: MutVisitor>(constness: &mut Const, vis: &mut T) {
825829
}
826830
}
827831

832+
pub fn noop_visit_closure_binder<T: MutVisitor>(binder: &mut ClosureBinder, vis: &mut T) {
833+
match binder {
834+
ClosureBinder::NotPresent => {}
835+
ClosureBinder::For { span: _, generic_params } => {
836+
let mut vec = std::mem::take(generic_params).into_vec();
837+
vec.flat_map_in_place(|param| vis.flat_map_generic_param(param));
838+
*generic_params = P::from_vec(vec);
839+
}
840+
}
841+
}
842+
828843
pub fn noop_visit_asyncness<T: MutVisitor>(asyncness: &mut Async, vis: &mut T) {
829844
match asyncness {
830845
Async::Yes { span: _, closure_id, return_impl_trait_id } => {
@@ -1336,7 +1351,8 @@ pub fn noop_visit_expr<T: MutVisitor>(
13361351
vis.visit_expr(expr);
13371352
arms.flat_map_in_place(|arm| vis.flat_map_arm(arm));
13381353
}
1339-
ExprKind::Closure(_capture_by, asyncness, _movability, decl, body, span) => {
1354+
ExprKind::Closure(binder, _capture_by, asyncness, _movability, decl, body, span) => {
1355+
vis.visit_closure_binder(binder);
13401356
vis.visit_asyncness(asyncness);
13411357
vis.visit_fn_decl(decl);
13421358
vis.visit_expr(body);

compiler/rustc_ast/src/visit.rs

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,14 @@ pub enum FnKind<'a> {
5656
Fn(FnCtxt, Ident, &'a FnSig, &'a Visibility, &'a Generics, Option<&'a Block>),
5757

5858
/// E.g., `|x, y| body`.
59-
Closure(&'a FnDecl, &'a Expr),
59+
Closure(&'a ClosureBinder, &'a FnDecl, &'a Expr),
6060
}
6161

6262
impl<'a> FnKind<'a> {
6363
pub fn header(&self) -> Option<&'a FnHeader> {
6464
match *self {
6565
FnKind::Fn(_, _, sig, _, _, _) => Some(&sig.header),
66-
FnKind::Closure(_, _) => None,
66+
FnKind::Closure(_, _, _) => None,
6767
}
6868
}
6969

@@ -77,7 +77,7 @@ impl<'a> FnKind<'a> {
7777
pub fn decl(&self) -> &'a FnDecl {
7878
match self {
7979
FnKind::Fn(_, _, sig, _, _, _) => &sig.decl,
80-
FnKind::Closure(decl, _) => decl,
80+
FnKind::Closure(_, decl, _) => decl,
8181
}
8282
}
8383

@@ -155,6 +155,9 @@ pub trait Visitor<'ast>: Sized {
155155
fn visit_generics(&mut self, g: &'ast Generics) {
156156
walk_generics(self, g)
157157
}
158+
fn visit_closure_binder(&mut self, b: &'ast ClosureBinder) {
159+
walk_closure_binder(self, b)
160+
}
158161
fn visit_where_predicate(&mut self, p: &'ast WherePredicate) {
159162
walk_where_predicate(self, p)
160163
}
@@ -636,6 +639,15 @@ pub fn walk_generics<'a, V: Visitor<'a>>(visitor: &mut V, generics: &'a Generics
636639
walk_list!(visitor, visit_where_predicate, &generics.where_clause.predicates);
637640
}
638641

642+
pub fn walk_closure_binder<'a, V: Visitor<'a>>(visitor: &mut V, binder: &'a ClosureBinder) {
643+
match binder {
644+
ClosureBinder::NotPresent => {}
645+
ClosureBinder::For { span: _, generic_params } => {
646+
walk_list!(visitor, visit_generic_param, generic_params)
647+
}
648+
}
649+
}
650+
639651
pub fn walk_where_predicate<'a, V: Visitor<'a>>(visitor: &mut V, predicate: &'a WherePredicate) {
640652
match *predicate {
641653
WherePredicate::BoundPredicate(WhereBoundPredicate {
@@ -682,7 +694,8 @@ pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>, _span: Spa
682694
walk_fn_decl(visitor, &sig.decl);
683695
walk_list!(visitor, visit_block, body);
684696
}
685-
FnKind::Closure(decl, body) => {
697+
FnKind::Closure(binder, decl, body) => {
698+
visitor.visit_closure_binder(binder);
686699
walk_fn_decl(visitor, decl);
687700
visitor.visit_expr(body);
688701
}
@@ -856,8 +869,8 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
856869
visitor.visit_expr(subexpression);
857870
walk_list!(visitor, visit_arm, arms);
858871
}
859-
ExprKind::Closure(_, _, _, ref decl, ref body, _decl_span) => {
860-
visitor.visit_fn(FnKind::Closure(decl, body), expression.span, expression.id)
872+
ExprKind::Closure(ref binder, _, _, _, ref decl, ref body, _decl_span) => {
873+
visitor.visit_fn(FnKind::Closure(binder, decl, body), expression.span, expression.id)
861874
}
862875
ExprKind::Block(ref block, ref opt_label) => {
863876
walk_list!(visitor, visit_label, opt_label);

compiler/rustc_ast_lowering/src/expr.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
155155
self.lower_expr_await(span, expr)
156156
}
157157
ExprKind::Closure(
158+
ref binder,
158159
capture_clause,
159160
asyncness,
160161
movability,
@@ -164,6 +165,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
164165
) => {
165166
if let Async::Yes { closure_id, .. } = asyncness {
166167
self.lower_expr_async_closure(
168+
binder,
167169
capture_clause,
168170
e.id,
169171
closure_id,
@@ -173,6 +175,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
173175
)
174176
} else {
175177
self.lower_expr_closure(
178+
binder,
176179
capture_clause,
177180
e.id,
178181
movability,
@@ -831,13 +834,22 @@ impl<'hir> LoweringContext<'_, 'hir> {
831834

832835
fn lower_expr_closure(
833836
&mut self,
837+
binder: &ClosureBinder,
834838
capture_clause: CaptureBy,
835839
closure_id: NodeId,
836840
movability: Movability,
837841
decl: &FnDecl,
838842
body: &Expr,
839843
fn_decl_span: Span,
840844
) -> hir::ExprKind<'hir> {
845+
// FIXME(waffle): lower binder
846+
if let &ClosureBinder::For { span, .. } = binder {
847+
self.sess
848+
.struct_span_err(span, "`for<...>` binders for closures are not yet supported")
849+
.help("consider removing `for<...>`")
850+
.emit();
851+
}
852+
841853
let (body, generator_option) = self.with_new_scopes(move |this| {
842854
let prev = this.current_item;
843855
this.current_item = Some(fn_decl_span);
@@ -908,13 +920,25 @@ impl<'hir> LoweringContext<'_, 'hir> {
908920

909921
fn lower_expr_async_closure(
910922
&mut self,
923+
binder: &ClosureBinder,
911924
capture_clause: CaptureBy,
912925
closure_id: NodeId,
913926
inner_closure_id: NodeId,
914927
decl: &FnDecl,
915928
body: &Expr,
916929
fn_decl_span: Span,
917930
) -> hir::ExprKind<'hir> {
931+
// FIXME(waffle): lower binder
932+
if let &ClosureBinder::For { span, .. } = binder {
933+
self.sess
934+
.struct_span_err(
935+
span,
936+
"`for<...>` binders for async closures are not yet supported",
937+
)
938+
.help("consider removing `for<...>`")
939+
.emit();
940+
}
941+
918942
let outer_decl =
919943
FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) };
920944

compiler/rustc_ast_passes/src/ast_validation.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1597,6 +1597,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
15971597
.emit();
15981598
}
15991599

1600+
if let FnKind::Closure(ClosureBinder::For { generic_params, .. }, ..) = fk {
1601+
self.check_late_bound_lifetime_defs(generic_params);
1602+
}
1603+
16001604
if let FnKind::Fn(
16011605
_,
16021606
_,

compiler/rustc_ast_passes/src/feature_gate.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -744,6 +744,11 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
744744
"async closures are unstable",
745745
"to use an async block, remove the `||`: `async {`"
746746
);
747+
gate_all!(
748+
closure_lifetime_binder,
749+
"`for<...>` binders for closures are experimental",
750+
"consider removing `for<...>`"
751+
);
747752
gate_all!(more_qualified_paths, "usage of qualified paths in this context is experimental");
748753
gate_all!(generators, "yield syntax is experimental");
749754
gate_all!(raw_ref_op, "raw address of syntax is experimental");

compiler/rustc_ast_pretty/src/pprust/state/expr.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,13 +389,15 @@ impl<'a> State<'a> {
389389
self.bclose(expr.span, empty);
390390
}
391391
ast::ExprKind::Closure(
392+
ref binder,
392393
capture_clause,
393394
asyncness,
394395
movability,
395396
ref decl,
396397
ref body,
397398
_,
398399
) => {
400+
self.print_closure_binder(binder);
399401
self.print_movability(movability);
400402
self.print_asyncness(asyncness);
401403
self.print_capture_clause(capture_clause);
@@ -594,6 +596,15 @@ impl<'a> State<'a> {
594596
self.end(); // Close enclosing cbox.
595597
}
596598

599+
fn print_closure_binder(&mut self, binder: &ast::ClosureBinder) {
600+
match binder {
601+
ast::ClosureBinder::NotPresent => {}
602+
ast::ClosureBinder::For { generic_params, .. } => {
603+
self.print_formal_generic_params(&generic_params)
604+
}
605+
}
606+
}
607+
597608
fn print_movability(&mut self, movability: ast::Movability) {
598609
match movability {
599610
ast::Movability::Static => self.word_space("static"),

compiler/rustc_builtin_macros/src/assert/context.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
294294
| ExprKind::Block(_, _)
295295
| ExprKind::Box(_)
296296
| ExprKind::Break(_, _)
297-
| ExprKind::Closure(_, _, _, _, _, _)
297+
| ExprKind::Closure(_, _, _, _, _, _, _)
298298
| ExprKind::ConstBlock(_)
299299
| ExprKind::Continue(_)
300300
| ExprKind::Err

compiler/rustc_expand/src/build.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,7 @@ impl<'a> ExtCtxt<'a> {
520520
self.expr(
521521
span,
522522
ast::ExprKind::Closure(
523+
ast::ClosureBinder::NotPresent,
523524
ast::CaptureBy::Ref,
524525
ast::Async::No,
525526
ast::Movability::Movable,

compiler/rustc_feature/src/active.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,8 @@ declare_features! (
331331
(active, cfg_target_thread_local, "1.7.0", Some(29594), None),
332332
/// Allow conditional compilation depending on rust version
333333
(active, cfg_version, "1.45.0", Some(64796), None),
334+
/// Allows `for<...>` on closures and generators.
335+
(active, closure_lifetime_binder, "1.64.0", Some(97362), None),
334336
/// Allows `#[track_caller]` on closures and generators.
335337
(active, closure_track_caller, "1.57.0", Some(87417), None),
336338
/// Allows to use the `#[cmse_nonsecure_entry]` attribute.

0 commit comments

Comments
 (0)