From 4fb10c0ce45673264d5dd428f4d5a4a389a2f1de Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Tue, 20 Dec 2022 16:15:55 +0000 Subject: [PATCH] parse const closures --- compiler/rustc_ast/src/ast.rs | 1 + compiler/rustc_ast/src/mut_visit.rs | 2 ++ compiler/rustc_ast/src/visit.rs | 1 + compiler/rustc_ast_lowering/src/expr.rs | 6 ++++++ compiler/rustc_ast_lowering/src/item.rs | 2 +- .../rustc_ast_pretty/src/pprust/state/expr.rs | 2 ++ compiler/rustc_expand/src/build.rs | 1 + compiler/rustc_hir/src/hir.rs | 1 + compiler/rustc_hir/src/intravisit.rs | 1 + compiler/rustc_hir_pretty/src/lib.rs | 14 ++++++++++---- compiler/rustc_parse/src/parser/expr.rs | 8 +++++++- compiler/rustc_parse/src/parser/mod.rs | 10 ++++++++++ src/tools/rustfmt/src/closures.rs | 19 ++++++++++++++++--- src/tools/rustfmt/src/expr.rs | 1 + tests/ui/parser/recover-quantified-closure.rs | 2 +- .../parser/recover-quantified-closure.stderr | 4 ++-- 16 files changed, 63 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index e656fb3740b..7de594719dd 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1307,6 +1307,7 @@ pub fn is_approximately_pattern(&self) -> bool { pub struct Closure { pub binder: ClosureBinder, pub capture_clause: CaptureBy, + pub constness: Const, pub asyncness: Async, pub movability: Movability, pub fn_decl: P, diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index c572171e8f4..77f342d1eb3 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1362,6 +1362,7 @@ pub fn noop_visit_expr( ExprKind::Closure(box Closure { binder, capture_clause: _, + constness, asyncness, movability: _, fn_decl, @@ -1370,6 +1371,7 @@ pub fn noop_visit_expr( fn_arg_span: _, }) => { vis.visit_closure_binder(binder); + visit_constness(constness, vis); vis.visit_asyncness(asyncness); vis.visit_fn_decl(fn_decl); vis.visit_expr(body); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index df7145a722a..e8823eff83a 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -836,6 +836,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { binder, capture_clause: _, asyncness: _, + constness: _, movability: _, fn_decl, body, diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 14f082be9ba..c3611b2f522 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -209,6 +209,7 @@ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> { ExprKind::Closure(box Closure { binder, capture_clause, + constness, asyncness, movability, fn_decl, @@ -233,6 +234,7 @@ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> { binder, *capture_clause, e.id, + *constness, *movability, fn_decl, body, @@ -651,6 +653,7 @@ pub(super) fn make_async_expr( fn_decl_span: self.lower_span(span), fn_arg_span: None, movability: Some(hir::Movability::Static), + constness: hir::Constness::NotConst, }); hir::ExprKind::Closure(c) @@ -890,6 +893,7 @@ fn lower_expr_closure( binder: &ClosureBinder, capture_clause: CaptureBy, closure_id: NodeId, + constness: Const, movability: Movability, decl: &FnDecl, body: &Expr, @@ -927,6 +931,7 @@ fn lower_expr_closure( fn_decl_span: self.lower_span(fn_decl_span), fn_arg_span: Some(self.lower_span(fn_arg_span)), movability: generator_option, + constness: self.lower_constness(constness), }); hir::ExprKind::Closure(c) @@ -1041,6 +1046,7 @@ fn lower_expr_async_closure( fn_decl_span: self.lower_span(fn_decl_span), fn_arg_span: Some(self.lower_span(fn_arg_span)), movability: None, + constness: hir::Constness::NotConst, }); hir::ExprKind::Closure(c) } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index ea30bed5ace..065779d0670 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1239,7 +1239,7 @@ fn lower_asyncness(&mut self, a: Async) -> hir::IsAsync { } } - fn lower_constness(&mut self, c: Const) -> hir::Constness { + pub(super) fn lower_constness(&mut self, c: Const) -> hir::Constness { match c { Const::Yes(_) => hir::Constness::Const, Const::No => hir::Constness::NotConst, diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index 3b17f6dd627..b125c6407d0 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -399,6 +399,7 @@ pub(super) fn print_expr_outer_attr_style(&mut self, expr: &ast::Expr, is_inline ast::ExprKind::Closure(box ast::Closure { binder, capture_clause, + constness, asyncness, movability, fn_decl, @@ -407,6 +408,7 @@ pub(super) fn print_expr_outer_attr_style(&mut self, expr: &ast::Expr, is_inline fn_arg_span: _, }) => { self.print_closure_binder(binder); + self.print_constness(*constness); self.print_movability(*movability); self.print_asyncness(*asyncness); self.print_capture_clause(*capture_clause); diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 93b3af4ab97..9b16e79d49a 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -533,6 +533,7 @@ pub fn lambda(&self, span: Span, ids: Vec, body: P) -> P { pub struct Closure<'hir> { pub def_id: LocalDefId, pub binder: ClosureBinder, + pub constness: Constness, pub capture_clause: CaptureBy, pub bound_generic_params: &'hir [GenericParam<'hir>], pub fn_decl: &'hir FnDecl<'hir>, diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 6c475b659eb..02641b7cf8f 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -742,6 +742,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) fn_decl_span: _, fn_arg_span: _, movability: _, + constness: _, }) => { walk_list!(visitor, visit_generic_param, bound_generic_params); visitor.visit_fn(FnKind::Closure, fn_decl, body, expression.span, expression.hir_id) diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 3e3af8395a1..f74c551a45b 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1464,6 +1464,7 @@ pub fn print_expr(&mut self, expr: &hir::Expr<'_>) { } hir::ExprKind::Closure(&hir::Closure { binder, + constness, capture_clause, bound_generic_params, fn_decl, @@ -1474,6 +1475,7 @@ pub fn print_expr(&mut self, expr: &hir::Expr<'_>) { def_id: _, }) => { self.print_closure_binder(binder, bound_generic_params); + self.print_constness(constness); self.print_capture_clause(capture_clause); self.print_closure_params(fn_decl, body); @@ -2272,10 +2274,7 @@ pub fn print_ty_fn( } pub fn print_fn_header_info(&mut self, header: hir::FnHeader) { - match header.constness { - hir::Constness::NotConst => {} - hir::Constness::Const => self.word_nbsp("const"), - } + self.print_constness(header.constness); match header.asyncness { hir::IsAsync::NotAsync => {} @@ -2292,6 +2291,13 @@ pub fn print_fn_header_info(&mut self, header: hir::FnHeader) { self.word("fn") } + pub fn print_constness(&mut self, s: hir::Constness) { + match s { + hir::Constness::NotConst => {} + hir::Constness::Const => self.word_nbsp("const"), + } + } + pub fn print_unsafety(&mut self, s: hir::Unsafety) { match s { hir::Unsafety::Normal => {} diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index f5093fb02a8..dd2b03988c3 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1325,7 +1325,10 @@ fn parse_bottom_expr(&mut self) -> PResult<'a, P> { self.parse_array_or_repeat_expr(Delimiter::Bracket) } else if self.check_path() { self.parse_path_start_expr() - } else if self.check_keyword(kw::Move) || self.check_keyword(kw::Static) { + } else if self.check_keyword(kw::Move) + || self.check_keyword(kw::Static) + || self.check_const_closure() + { self.parse_closure_expr() } else if self.eat_keyword(kw::If) { self.parse_if_expr() @@ -2065,6 +2068,8 @@ fn parse_closure_expr(&mut self) -> PResult<'a, P> { ClosureBinder::NotPresent }; + let constness = self.parse_constness(Case::Sensitive); + let movability = if self.eat_keyword(kw::Static) { Movability::Static } else { Movability::Movable }; @@ -2111,6 +2116,7 @@ fn parse_closure_expr(&mut self) -> PResult<'a, P> { ExprKind::Closure(Box::new(ast::Closure { binder, capture_clause, + constness, asyncness, movability, fn_decl, diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 49d31981539..2fd2a4e5154 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -736,6 +736,16 @@ fn check_const_arg(&mut self) -> bool { self.check_or_expected(self.token.can_begin_const_arg(), TokenType::Const) } + fn check_const_closure(&self) -> bool { + self.is_keyword_ahead(0, &[kw::Const]) + && self.look_ahead(1, |t| match &t.kind { + token::Ident(kw::Move | kw::Static | kw::Async, _) + | token::OrOr + | token::BinOp(token::Or) => true, + _ => false, + }) + } + fn check_inline_const(&self, dist: usize) -> bool { self.is_keyword_ahead(dist, &[kw::Const]) && self.look_ahead(dist + 1, |t| match &t.kind { diff --git a/src/tools/rustfmt/src/closures.rs b/src/tools/rustfmt/src/closures.rs index 244d4427c56..8fd0fcf8f5c 100644 --- a/src/tools/rustfmt/src/closures.rs +++ b/src/tools/rustfmt/src/closures.rs @@ -26,6 +26,7 @@ pub(crate) fn rewrite_closure( binder: &ast::ClosureBinder, + constness: ast::Const, capture: ast::CaptureBy, is_async: &ast::Async, movability: ast::Movability, @@ -38,7 +39,7 @@ pub(crate) fn rewrite_closure( debug!("rewrite_closure {:?}", body); let (prefix, extra_offset) = rewrite_closure_fn_decl( - binder, capture, is_async, movability, fn_decl, body, span, context, shape, + binder, constness, capture, is_async, movability, fn_decl, body, span, context, shape, )?; // 1 = space between `|...|` and body. let body_shape = shape.offset_left(extra_offset)?; @@ -230,6 +231,7 @@ fn rewrite_closure_block( // Return type is (prefix, extra_offset) fn rewrite_closure_fn_decl( binder: &ast::ClosureBinder, + constness: ast::Const, capture: ast::CaptureBy, asyncness: &ast::Async, movability: ast::Movability, @@ -250,6 +252,12 @@ fn rewrite_closure_fn_decl( ast::ClosureBinder::NotPresent => "".to_owned(), }; + let const_ = if matches!(constness, ast::Const::Yes(_)) { + "const " + } else { + "" + }; + let immovable = if movability == ast::Movability::Static { "static " } else { @@ -264,7 +272,7 @@ fn rewrite_closure_fn_decl( // 4 = "|| {".len(), which is overconservative when the closure consists of // a single expression. let nested_shape = shape - .shrink_left(binder.len() + immovable.len() + is_async.len() + mover.len())? + .shrink_left(binder.len() + const_.len() + immovable.len() + is_async.len() + mover.len())? .sub_width(4)?; // 1 = | @@ -302,7 +310,10 @@ fn rewrite_closure_fn_decl( .tactic(tactic) .preserve_newline(true); let list_str = write_list(&item_vec, &fmt)?; - let mut prefix = format!("{}{}{}{}|{}|", binder, immovable, is_async, mover, list_str); + let mut prefix = format!( + "{}{}{}{}{}|{}|", + binder, const_, immovable, is_async, mover, list_str + ); if !ret_str.is_empty() { if prefix.contains('\n') { @@ -329,6 +340,7 @@ pub(crate) fn rewrite_last_closure( if let ast::ExprKind::Closure(ref closure) = expr.kind { let ast::Closure { ref binder, + constness, capture_clause, ref asyncness, movability, @@ -349,6 +361,7 @@ pub(crate) fn rewrite_last_closure( }; let (prefix, extra_offset) = rewrite_closure_fn_decl( binder, + constness, capture_clause, asyncness, movability, diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs index 414e767690b..868ff045ab7 100644 --- a/src/tools/rustfmt/src/expr.rs +++ b/src/tools/rustfmt/src/expr.rs @@ -205,6 +205,7 @@ pub(crate) fn format_expr( } ast::ExprKind::Closure(ref cl) => closures::rewrite_closure( &cl.binder, + cl.constness, cl.capture_clause, &cl.asyncness, cl.movability, diff --git a/tests/ui/parser/recover-quantified-closure.rs b/tests/ui/parser/recover-quantified-closure.rs index 10af39b7007..df22f5e065c 100644 --- a/tests/ui/parser/recover-quantified-closure.rs +++ b/tests/ui/parser/recover-quantified-closure.rs @@ -7,6 +7,6 @@ fn main() { enum Foo { Bar } fn foo(x: impl Iterator) { for ::Bar in x {} - //~^ ERROR expected one of `move`, `static`, `|` + //~^ ERROR expected one of `const`, `move`, `static`, `|` //~^^ ERROR `for<...>` binders for closures are experimental } diff --git a/tests/ui/parser/recover-quantified-closure.stderr b/tests/ui/parser/recover-quantified-closure.stderr index 39eec80f658..9ec4d2c034d 100644 --- a/tests/ui/parser/recover-quantified-closure.stderr +++ b/tests/ui/parser/recover-quantified-closure.stderr @@ -1,8 +1,8 @@ -error: expected one of `move`, `static`, `|`, or `||`, found `::` +error: expected one of `const`, `move`, `static`, `|`, or `||`, found `::` --> $DIR/recover-quantified-closure.rs:9:14 | LL | for ::Bar in x {} - | ^^ expected one of `move`, `static`, `|`, or `||` + | ^^ expected one of `const`, `move`, `static`, `|`, or `||` error[E0658]: `for<...>` binders for closures are experimental --> $DIR/recover-quantified-closure.rs:2:5