diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-19 09:26:03 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-19 09:26:03 +0000 |
commit | 9918693037dce8aa4bb6f08741b6812923486c18 (patch) | |
tree | 21d2b40bec7e6a7ea664acee056eb3d08e15a1cf /compiler/rustc_ast_pretty/src/pprust/state.rs | |
parent | Releasing progress-linux version 1.75.0+dfsg1-5~progress7.99u1. (diff) | |
download | rustc-9918693037dce8aa4bb6f08741b6812923486c18.tar.xz rustc-9918693037dce8aa4bb6f08741b6812923486c18.zip |
Merging upstream version 1.76.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_ast_pretty/src/pprust/state.rs')
-rw-r--r-- | compiler/rustc_ast_pretty/src/pprust/state.rs | 404 |
1 files changed, 220 insertions, 184 deletions
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 48421ff71..d6c15ec35 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1,13 +1,17 @@ -mod delimited; +//! AST pretty printing. +//! +//! Note that HIR pretty printing is layered on top of this crate. + mod expr; mod item; use crate::pp::Breaks::{Consistent, Inconsistent}; use crate::pp::{self, Breaks}; +use crate::pprust::state::expr::FixupContext; use rustc_ast::attr::AttrIdGenerator; use rustc_ast::ptr::P; use rustc_ast::token::{self, BinOpToken, CommentKind, Delimiter, Nonterminal, Token, TokenKind}; -use rustc_ast::tokenstream::{TokenStream, TokenTree}; +use rustc_ast::tokenstream::{Spacing, TokenStream, TokenTree}; use rustc_ast::util::classify; use rustc_ast::util::comments::{gather_comments, Comment, CommentStyle}; use rustc_ast::util::parser; @@ -23,8 +27,6 @@ use rustc_span::{BytePos, FileName, Span, DUMMY_SP}; use std::borrow::Cow; use thin_vec::ThinVec; -pub use self::delimited::IterDelimited; - pub enum MacHeader<'a> { Path(&'a ast::Path), Keyword(&'static str), @@ -46,8 +48,7 @@ pub trait PpAnn { fn post(&self, _state: &mut State<'_>, _node: AnnNode<'_>) {} } -#[derive(Copy, Clone)] -pub struct NoAnn; +struct NoAnn; impl PpAnn for NoAnn {} @@ -64,11 +65,11 @@ impl<'a> Comments<'a> { } // FIXME: This shouldn't probably clone lmao - pub fn next(&self) -> Option<Comment> { + fn next(&self) -> Option<Comment> { self.comments.get(self.current).cloned() } - pub fn trailing_comment( + fn trailing_comment( &self, span: rustc_span::Span, next_pos: Option<BytePos>, @@ -95,7 +96,7 @@ pub struct State<'a> { ann: &'a (dyn PpAnn + 'a), } -pub(crate) const INDENT_UNIT: isize = 4; +const INDENT_UNIT: isize = 4; /// Requires you to pass an input filename and reader so that /// it can scan the input text for comments to copy forward. @@ -151,7 +152,7 @@ pub fn print_crate<'a>( /// Note: some old proc macros parse pretty-printed output, so changes here can /// break old code. For example: /// - #63896: `#[allow(unused,` must be printed rather than `#[allow(unused ,` -/// - #73345: `#[allow(unused)] must be printed rather than `# [allow(unused)] +/// - #73345: `#[allow(unused)]` must be printed rather than `# [allow(unused)]` /// fn space_between(tt1: &TokenTree, tt2: &TokenTree) -> bool { use token::*; @@ -183,10 +184,10 @@ fn space_between(tt1: &TokenTree, tt2: &TokenTree) -> bool { // // FIXME: Incorrect cases: // - Let: `let(a, b) = (1, 2)` - (Tok(Token { kind: Ident(..), .. }, _), Del(_, Parenthesis, _)) => false, + (Tok(Token { kind: Ident(..), .. }, _), Del(_, _, Parenthesis, _)) => false, // `#` + `[`: `#[attr]` - (Tok(Token { kind: Pound, .. }, _), Del(_, Bracket, _)) => false, + (Tok(Token { kind: Pound, .. }, _), Del(_, _, Bracket, _)) => false, _ => true, } @@ -220,7 +221,7 @@ fn doc_comment_to_string( } } -pub fn literal_to_string(lit: token::Lit) -> String { +fn literal_to_string(lit: token::Lit) -> String { let token::Lit { kind, symbol, suffix } = lit; let mut out = match kind { token::Byte => format!("b'{symbol}'"), @@ -260,11 +261,17 @@ impl std::ops::DerefMut for State<'_> { } } +/// This trait is used for both AST and HIR pretty-printing. pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::DerefMut { fn comments(&mut self) -> &mut Option<Comments<'a>>; - fn print_ident(&mut self, ident: Ident); + fn ann_post(&mut self, ident: Ident); fn print_generic_args(&mut self, args: &ast::GenericArgs, colons_before_params: bool); + fn print_ident(&mut self, ident: Ident) { + self.word(IdentPrinter::for_ast_ident(ident, ident.is_raw_guess()).to_string()); + self.ann_post(ident) + } + fn strsep<T, F>( &mut self, sep: &'static str, @@ -401,15 +408,6 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere } } - fn print_meta_item_lit(&mut self, lit: &ast::MetaItemLit) { - self.print_token_literal(lit.as_token_lit(), lit.span) - } - - fn print_token_literal(&mut self, token_lit: token::Lit, span: Span) { - self.maybe_print_comment(span.lo()); - self.word(token_lit.to_string()) - } - fn print_string(&mut self, st: &str, style: ast::StrStyle) { let st = match style { ast::StrStyle::Cooked => format!("\"{}\"", st.escape_debug()), @@ -420,30 +418,14 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere self.word(st) } - fn print_symbol(&mut self, sym: Symbol, style: ast::StrStyle) { - self.print_string(sym.as_str(), style); - } - fn print_inner_attributes(&mut self, attrs: &[ast::Attribute]) -> bool { self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, true) } - fn print_inner_attributes_no_trailing_hardbreak(&mut self, attrs: &[ast::Attribute]) -> bool { - self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, false) - } - fn print_outer_attributes(&mut self, attrs: &[ast::Attribute]) -> bool { self.print_either_attributes(attrs, ast::AttrStyle::Outer, false, true) } - fn print_inner_attributes_inline(&mut self, attrs: &[ast::Attribute]) -> bool { - self.print_either_attributes(attrs, ast::AttrStyle::Inner, true, true) - } - - fn print_outer_attributes_inline(&mut self, attrs: &[ast::Attribute]) -> bool { - self.print_either_attributes(attrs, ast::AttrStyle::Outer, true, true) - } - fn print_either_attributes( &mut self, attrs: &[ast::Attribute], @@ -467,10 +449,6 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere printed } - fn print_attribute(&mut self, attr: &ast::Attribute) { - self.print_attribute_inline(attr, false) - } - fn print_attribute_inline(&mut self, attr: &ast::Attribute, is_inline: bool) { if !is_inline { self.hardbreak_if_not_bol(); @@ -525,33 +503,6 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere self.end(); } - fn print_meta_list_item(&mut self, item: &ast::NestedMetaItem) { - match item { - ast::NestedMetaItem::MetaItem(mi) => self.print_meta_item(mi), - ast::NestedMetaItem::Lit(lit) => self.print_meta_item_lit(lit), - } - } - - fn print_meta_item(&mut self, item: &ast::MetaItem) { - self.ibox(INDENT_UNIT); - match &item.kind { - ast::MetaItemKind::Word => self.print_path(&item.path, false, 0), - ast::MetaItemKind::NameValue(value) => { - self.print_path(&item.path, false, 0); - self.space(); - self.word_space("="); - self.print_meta_item_lit(value); - } - ast::MetaItemKind::List(items) => { - self.print_path(&item.path, false, 0); - self.popen(); - self.commasep(Consistent, items, |s, i| s.print_meta_list_item(i)); - self.pclose(); - } - } - self.end(); - } - /// This doesn't deserve to be called "pretty" printing, but it should be /// meaning-preserving. A quick hack that might help would be to look at the /// spans embedded in the TTs to decide where to put spaces and newlines. @@ -559,16 +510,17 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere /// appropriate macro, transcribe back into the grammar we just parsed from, /// and then pretty-print the resulting AST nodes (so, e.g., we print /// expression arguments as expressions). It can be done! I think. - fn print_tt(&mut self, tt: &TokenTree, convert_dollar_crate: bool) { + fn print_tt(&mut self, tt: &TokenTree, convert_dollar_crate: bool) -> Spacing { match tt { - TokenTree::Token(token, _) => { + TokenTree::Token(token, spacing) => { let token_str = self.token_to_string_ext(token, convert_dollar_crate); self.word(token_str); if let token::DocComment(..) = token.kind { self.hardbreak() } + *spacing } - TokenTree::Delimited(dspan, delim, tts) => { + TokenTree::Delimited(dspan, spacing, delim, tts) => { self.print_mac_common( None, false, @@ -578,6 +530,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere convert_dollar_crate, dspan.entire(), ); + spacing.close } } } @@ -585,9 +538,20 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere fn print_tts(&mut self, tts: &TokenStream, convert_dollar_crate: bool) { let mut iter = tts.trees().peekable(); while let Some(tt) = iter.next() { - self.print_tt(tt, convert_dollar_crate); + let spacing = self.print_tt(tt, convert_dollar_crate); if let Some(next) = iter.peek() { - if space_between(tt, next) { + // Should we print a space after `tt`? There are two guiding + // factors. + // - `spacing` is the more important and accurate one. Most + // tokens have good spacing information, and + // `Joint`/`JointHidden` get used a lot. + // - `space_between` is the backup. Code produced by proc + // macros has worse spacing information, with no + // `JointHidden` usage and too much `Alone` usage, which + // would result in over-spaced output such as + // `( x () , y . z )`. `space_between` avoids some of the + // excess whitespace. + if spacing == Spacing::Alone && space_between(tt, next) { self.space(); } } @@ -825,7 +789,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere } token::Eof => "<eof>".into(), - token::Interpolated(ref nt) => self.nonterminal_to_string(nt).into(), + token::Interpolated(ref nt) => self.nonterminal_to_string(&nt.0).into(), } } @@ -843,37 +807,18 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere Self::to_string(|s| s.print_type(ty)) } - fn bounds_to_string(&self, bounds: &[ast::GenericBound]) -> String { - Self::to_string(|s| s.print_type_bounds(bounds)) - } - - fn where_bound_predicate_to_string( - &self, - where_bound_predicate: &ast::WhereBoundPredicate, - ) -> String { - Self::to_string(|s| s.print_where_bound_predicate(where_bound_predicate)) - } - fn pat_to_string(&self, pat: &ast::Pat) -> String { Self::to_string(|s| s.print_pat(pat)) } fn expr_to_string(&self, e: &ast::Expr) -> String { - Self::to_string(|s| s.print_expr(e)) + Self::to_string(|s| s.print_expr(e, FixupContext::default())) } fn meta_item_lit_to_string(&self, lit: &ast::MetaItemLit) -> String { Self::to_string(|s| s.print_meta_item_lit(lit)) } - fn tt_to_string(&self, tt: &TokenTree) -> String { - Self::to_string(|s| s.print_tt(tt, false)) - } - - fn tts_to_string(&self, tokens: &TokenStream) -> String { - Self::to_string(|s| s.print_tts(tokens, false)) - } - fn stmt_to_string(&self, stmt: &ast::Stmt) -> String { Self::to_string(|s| s.print_stmt(stmt)) } @@ -882,26 +827,10 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere Self::to_string(|s| s.print_item(i)) } - fn assoc_item_to_string(&self, i: &ast::AssocItem) -> String { - Self::to_string(|s| s.print_assoc_item(i)) - } - - fn foreign_item_to_string(&self, i: &ast::ForeignItem) -> String { - Self::to_string(|s| s.print_foreign_item(i)) - } - - fn generic_params_to_string(&self, generic_params: &[ast::GenericParam]) -> String { - Self::to_string(|s| s.print_generic_params(generic_params)) - } - fn path_to_string(&self, p: &ast::Path) -> String { Self::to_string(|s| s.print_path(p, false, 0)) } - fn path_segment_to_string(&self, p: &ast::PathSegment) -> String { - Self::to_string(|s| s.print_path_segment(p, false)) - } - fn vis_to_string(&self, v: &ast::Visibility) -> String { Self::to_string(|s| s.print_visibility(v)) } @@ -916,22 +845,10 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere }) } - fn meta_list_item_to_string(&self, li: &ast::NestedMetaItem) -> String { - Self::to_string(|s| s.print_meta_list_item(li)) - } - fn attr_item_to_string(&self, ai: &ast::AttrItem) -> String { Self::to_string(|s| s.print_attr_item(ai, ai.path.span)) } - fn attribute_to_string(&self, attr: &ast::Attribute) -> String { - Self::to_string(|s| s.print_attribute(attr)) - } - - fn param_to_string(&self, arg: &ast::Param) -> String { - Self::to_string(|s| s.print_param(arg, false)) - } - fn to_string(f: impl FnOnce(&mut State<'_>)) -> String { let mut printer = State::new(); f(&mut printer); @@ -944,9 +861,8 @@ impl<'a> PrintState<'a> for State<'a> { &mut self.comments } - fn print_ident(&mut self, ident: Ident) { - self.word(IdentPrinter::for_ast_ident(ident, ident.is_raw_guess()).to_string()); - self.ann.post(self, AnnNode::Ident(&ident)) + fn ann_post(&mut self, ident: Ident) { + self.ann.post(self, AnnNode::Ident(&ident)); } fn print_generic_args(&mut self, args: &ast::GenericArgs, colons_before_params: bool) { @@ -979,13 +895,8 @@ impl<'a> State<'a> { State { s: pp::Printer::new(), comments: None, ann: &NoAnn } } - pub(crate) fn commasep_cmnt<T, F, G>( - &mut self, - b: Breaks, - elts: &[T], - mut op: F, - mut get_span: G, - ) where + fn commasep_cmnt<T, F, G>(&mut self, b: Breaks, elts: &[T], mut op: F, mut get_span: G) + where F: FnMut(&mut State<'_>, &T), G: FnMut(&T) -> rustc_span::Span, { @@ -1005,8 +916,8 @@ impl<'a> State<'a> { self.end(); } - pub(crate) fn commasep_exprs(&mut self, b: Breaks, exprs: &[P<ast::Expr>]) { - self.commasep_cmnt(b, exprs, |s, e| s.print_expr(e), |e| e.span) + fn commasep_exprs(&mut self, b: Breaks, exprs: &[P<ast::Expr>]) { + self.commasep_cmnt(b, exprs, |s, e| s.print_expr(e, FixupContext::default()), |e| e.span) } pub fn print_opt_lifetime(&mut self, lifetime: &Option<ast::Lifetime>) { @@ -1043,7 +954,7 @@ impl<'a> State<'a> { match generic_arg { GenericArg::Lifetime(lt) => self.print_lifetime(*lt), GenericArg::Type(ty) => self.print_type(ty), - GenericArg::Const(ct) => self.print_expr(&ct.value), + GenericArg::Const(ct) => self.print_expr(&ct.value, FixupContext::default()), } } @@ -1078,11 +989,11 @@ impl<'a> State<'a> { } ast::TyKind::AnonStruct(fields) => { self.head("struct"); - self.print_record_struct_body(&fields, ty.span); + self.print_record_struct_body(fields, ty.span); } ast::TyKind::AnonUnion(fields) => { self.head("union"); - self.print_record_struct_body(&fields, ty.span); + self.print_record_struct_body(fields, ty.span); } ast::TyKind::Paren(typ) => { self.popen(); @@ -1110,12 +1021,12 @@ impl<'a> State<'a> { self.word("["); self.print_type(ty); self.word("; "); - self.print_expr(&length.value); + self.print_expr(&length.value, FixupContext::default()); self.word("]"); } ast::TyKind::Typeof(e) => { self.word("typeof("); - self.print_expr(&e.value); + self.print_expr(&e.value, FixupContext::default()); self.word(")"); } ast::TyKind::Infer => { @@ -1156,7 +1067,7 @@ impl<'a> State<'a> { self.print_trait_ref(&t.trait_ref) } - pub(crate) fn print_stmt(&mut self, st: &ast::Stmt) { + fn print_stmt(&mut self, st: &ast::Stmt) { self.maybe_print_comment(st.span.lo()); match &st.kind { ast::StmtKind::Local(loc) => { @@ -1171,7 +1082,7 @@ impl<'a> State<'a> { if let Some((init, els)) = loc.kind.init_else_opt() { self.nbsp(); self.word_space("="); - self.print_expr(init); + self.print_expr(init, FixupContext::default()); if let Some(els) = els { self.cbox(INDENT_UNIT); self.ibox(INDENT_UNIT); @@ -1185,14 +1096,14 @@ impl<'a> State<'a> { ast::StmtKind::Item(item) => self.print_item(item), ast::StmtKind::Expr(expr) => { self.space_if_not_bol(); - self.print_expr_outer_attr_style(expr, false); + self.print_expr_outer_attr_style(expr, false, FixupContext::default()); if classify::expr_requires_semi_to_be_stmt(expr) { self.word(";"); } } ast::StmtKind::Semi(expr) => { self.space_if_not_bol(); - self.print_expr_outer_attr_style(expr, false); + self.print_expr_outer_attr_style(expr, false, FixupContext::default()); self.word(";"); } ast::StmtKind::Empty => { @@ -1211,19 +1122,19 @@ impl<'a> State<'a> { self.maybe_print_trailing_comment(st.span, None) } - pub(crate) fn print_block(&mut self, blk: &ast::Block) { + fn print_block(&mut self, blk: &ast::Block) { self.print_block_with_attrs(blk, &[]) } - pub(crate) fn print_block_unclosed_indent(&mut self, blk: &ast::Block) { + fn print_block_unclosed_indent(&mut self, blk: &ast::Block) { self.print_block_maybe_unclosed(blk, &[], false) } - pub(crate) fn print_block_with_attrs(&mut self, blk: &ast::Block, attrs: &[ast::Attribute]) { + fn print_block_with_attrs(&mut self, blk: &ast::Block, attrs: &[ast::Attribute]) { self.print_block_maybe_unclosed(blk, attrs, true) } - pub(crate) fn print_block_maybe_unclosed( + fn print_block_maybe_unclosed( &mut self, blk: &ast::Block, attrs: &[ast::Attribute], @@ -1244,7 +1155,7 @@ impl<'a> State<'a> { ast::StmtKind::Expr(expr) if i == blk.stmts.len() - 1 => { self.maybe_print_comment(st.span.lo()); self.space_if_not_bol(); - self.print_expr_outer_attr_style(expr, false); + self.print_expr_outer_attr_style(expr, false, FixupContext::default()); self.maybe_print_trailing_comment(expr.span, Some(blk.span.hi())); } _ => self.print_stmt(st), @@ -1257,16 +1168,44 @@ impl<'a> State<'a> { } /// Print a `let pat = expr` expression. - pub(crate) fn print_let(&mut self, pat: &ast::Pat, expr: &ast::Expr) { + /// + /// Parentheses are inserted surrounding `expr` if a round-trip through the + /// parser would otherwise work out the wrong way in a condition position. + /// + /// For example each of the following would mean the wrong thing without + /// parentheses. + /// + /// ```ignore (illustrative) + /// if let _ = (Struct {}) {} + /// + /// if let _ = (true && false) {} + /// ``` + /// + /// In a match guard, the second case still requires parens, but the first + /// case no longer does because anything until `=>` is considered part of + /// the match guard expression. Parsing of the expression is not terminated + /// by `{` in that position. + /// + /// ```ignore (illustrative) + /// match () { + /// () if let _ = Struct {} => {} + /// () if let _ = (true && false) => {} + /// } + /// ``` + fn print_let(&mut self, pat: &ast::Pat, expr: &ast::Expr, fixup: FixupContext) { self.word("let "); self.print_pat(pat); self.space(); self.word_space("="); - let npals = || parser::needs_par_as_let_scrutinee(expr.precedence().order()); - self.print_expr_cond_paren(expr, Self::cond_needs_par(expr) || npals()) + self.print_expr_cond_paren( + expr, + fixup.parenthesize_exterior_struct_lit && parser::contains_exterior_struct_lit(expr) + || parser::needs_par_as_let_scrutinee(expr.precedence().order()), + FixupContext::default(), + ); } - pub(crate) fn print_mac(&mut self, m: &ast::MacCall) { + fn print_mac(&mut self, m: &ast::MacCall) { self.print_mac_common( Some(MacHeader::Path(&m.path)), true, @@ -1310,7 +1249,7 @@ impl<'a> State<'a> { print_reg_or_class(s, reg); s.pclose(); s.space(); - s.print_expr(expr); + s.print_expr(expr, FixupContext::default()); } InlineAsmOperand::Out { reg, late, expr } => { s.word(if *late { "lateout" } else { "out" }); @@ -1319,7 +1258,7 @@ impl<'a> State<'a> { s.pclose(); s.space(); match expr { - Some(expr) => s.print_expr(expr), + Some(expr) => s.print_expr(expr, FixupContext::default()), None => s.word("_"), } } @@ -1329,7 +1268,7 @@ impl<'a> State<'a> { print_reg_or_class(s, reg); s.pclose(); s.space(); - s.print_expr(expr); + s.print_expr(expr, FixupContext::default()); } InlineAsmOperand::SplitInOut { reg, late, in_expr, out_expr } => { s.word(if *late { "inlateout" } else { "inout" }); @@ -1337,18 +1276,18 @@ impl<'a> State<'a> { print_reg_or_class(s, reg); s.pclose(); s.space(); - s.print_expr(in_expr); + s.print_expr(in_expr, FixupContext::default()); s.space(); s.word_space("=>"); match out_expr { - Some(out_expr) => s.print_expr(out_expr), + Some(out_expr) => s.print_expr(out_expr, FixupContext::default()), None => s.word("_"), } } InlineAsmOperand::Const { anon_const } => { s.word("const"); s.space(); - s.print_expr(&anon_const.value); + s.print_expr(&anon_const.value, FixupContext::default()); } InlineAsmOperand::Sym { sym } => { s.word("sym"); @@ -1407,7 +1346,7 @@ impl<'a> State<'a> { self.pclose(); } - pub(crate) fn print_local_decl(&mut self, loc: &ast::Local) { + fn print_local_decl(&mut self, loc: &ast::Local) { self.print_pat(&loc.pat); if let Some(ty) = &loc.ty { self.word_space(":"); @@ -1415,7 +1354,7 @@ impl<'a> State<'a> { } } - pub(crate) fn print_name(&mut self, name: Symbol) { + fn print_name(&mut self, name: Symbol) { self.word(name.to_string()); self.ann.post(self, AnnNode::Name(&name)) } @@ -1439,13 +1378,14 @@ impl<'a> State<'a> { } } - pub(crate) fn print_pat(&mut self, pat: &ast::Pat) { + fn print_pat(&mut self, pat: &ast::Pat) { self.maybe_print_comment(pat.span.lo()); self.ann.pre(self, AnnNode::Pat(pat)); /* Pat isn't normalized, but the beauty of it is that it doesn't matter */ match &pat.kind { PatKind::Wild => self.word("_"), + PatKind::Never => self.word("!"), PatKind::Ident(BindingAnnotation(by_ref, mutbl), ident, sub) => { if *by_ref == ByRef::Yes { self.word_nbsp("ref"); @@ -1541,10 +1481,10 @@ impl<'a> State<'a> { self.print_pat(inner); } } - PatKind::Lit(e) => self.print_expr(e), + PatKind::Lit(e) => self.print_expr(e, FixupContext::default()), PatKind::Range(begin, end, Spanned { node: end_kind, .. }) => { if let Some(e) = begin { - self.print_expr(e); + self.print_expr(e, FixupContext::default()); } match end_kind { RangeEnd::Included(RangeSyntax::DotDotDot) => self.word("..."), @@ -1552,7 +1492,7 @@ impl<'a> State<'a> { RangeEnd::Excluded => self.word(".."), } if let Some(e) = end { - self.print_expr(e); + self.print_expr(e, FixupContext::default()); } } PatKind::Slice(elts) => { @@ -1592,9 +1532,18 @@ impl<'a> State<'a> { } } - pub(crate) fn print_asyncness(&mut self, asyncness: ast::Async) { - if asyncness.is_async() { - self.word_nbsp("async"); + fn print_coroutine_kind(&mut self, coroutine_kind: ast::CoroutineKind) { + match coroutine_kind { + ast::CoroutineKind::Gen { .. } => { + self.word_nbsp("gen"); + } + ast::CoroutineKind::Async { .. } => { + self.word_nbsp("async"); + } + ast::CoroutineKind::AsyncGen { .. } => { + self.word_nbsp("async"); + self.word_nbsp("gen"); + } } } @@ -1618,7 +1567,7 @@ impl<'a> State<'a> { TraitBoundModifier::Maybe => { self.word("?"); } - TraitBoundModifier::MaybeConst => { + TraitBoundModifier::MaybeConst(_) => { self.word_space("~const"); } TraitBoundModifier::MaybeConstNegative => { @@ -1637,23 +1586,25 @@ impl<'a> State<'a> { } } - pub(crate) fn print_lifetime(&mut self, lifetime: ast::Lifetime) { + fn print_lifetime(&mut self, lifetime: ast::Lifetime) { self.print_name(lifetime.ident.name) } - pub(crate) fn print_lifetime_bounds(&mut self, bounds: &ast::GenericBounds) { + fn print_lifetime_bounds(&mut self, bounds: &ast::GenericBounds) { for (i, bound) in bounds.iter().enumerate() { if i != 0 { self.word(" + "); } match bound { ast::GenericBound::Outlives(lt) => self.print_lifetime(*lt), - _ => panic!(), + _ => { + panic!("expected a lifetime bound, found a trait bound") + } } } } - pub(crate) fn print_generic_params(&mut self, generic_params: &[ast::GenericParam]) { + fn print_generic_params(&mut self, generic_params: &[ast::GenericParam]) { if generic_params.is_empty() { return; } @@ -1697,7 +1648,7 @@ impl<'a> State<'a> { if let Some(default) = default { s.space(); s.word_space("="); - s.print_expr(&default.value); + s.print_expr(&default.value, FixupContext::default()); } } } @@ -1717,12 +1668,12 @@ impl<'a> State<'a> { } } - pub(crate) fn print_mt(&mut self, mt: &ast::MutTy, print_const: bool) { + fn print_mt(&mut self, mt: &ast::MutTy, print_const: bool) { self.print_mutability(mt.mutbl, print_const); self.print_type(&mt.ty) } - pub(crate) fn print_param(&mut self, input: &ast::Param, is_closure: bool) { + fn print_param(&mut self, input: &ast::Param, is_closure: bool) { self.ibox(INDENT_UNIT); self.print_outer_attributes_inline(&input.attrs); @@ -1750,7 +1701,7 @@ impl<'a> State<'a> { self.end(); } - pub(crate) fn print_fn_ret_ty(&mut self, fn_ret_ty: &ast::FnRetTy) { + fn print_fn_ret_ty(&mut self, fn_ret_ty: &ast::FnRetTy) { if let ast::FnRetTy::Ty(ty) = fn_ret_ty { self.space_if_not_bol(); self.ibox(INDENT_UNIT); @@ -1761,7 +1712,7 @@ impl<'a> State<'a> { } } - pub(crate) fn print_ty_fn( + fn print_ty_fn( &mut self, ext: ast::Extern, unsafety: ast::Unsafe, @@ -1785,9 +1736,9 @@ impl<'a> State<'a> { self.end(); } - pub(crate) fn print_fn_header_info(&mut self, header: ast::FnHeader) { + fn print_fn_header_info(&mut self, header: ast::FnHeader) { self.print_constness(header.constness); - self.print_asyncness(header.asyncness); + header.coroutine_kind.map(|coroutine_kind| self.print_coroutine_kind(coroutine_kind)); self.print_unsafety(header.unsafety); match header.ext { @@ -1805,24 +1756,109 @@ impl<'a> State<'a> { self.word("fn") } - pub(crate) fn print_unsafety(&mut self, s: ast::Unsafe) { + fn print_unsafety(&mut self, s: ast::Unsafe) { match s { ast::Unsafe::No => {} ast::Unsafe::Yes(_) => self.word_nbsp("unsafe"), } } - pub(crate) fn print_constness(&mut self, s: ast::Const) { + fn print_constness(&mut self, s: ast::Const) { match s { ast::Const::No => {} ast::Const::Yes(_) => self.word_nbsp("const"), } } - pub(crate) fn print_is_auto(&mut self, s: ast::IsAuto) { + fn print_is_auto(&mut self, s: ast::IsAuto) { match s { ast::IsAuto::Yes => self.word_nbsp("auto"), ast::IsAuto::No => {} } } + + fn print_meta_item_lit(&mut self, lit: &ast::MetaItemLit) { + self.print_token_literal(lit.as_token_lit(), lit.span) + } + + fn print_token_literal(&mut self, token_lit: token::Lit, span: Span) { + self.maybe_print_comment(span.lo()); + self.word(token_lit.to_string()) + } + + fn print_symbol(&mut self, sym: Symbol, style: ast::StrStyle) { + self.print_string(sym.as_str(), style); + } + + fn print_inner_attributes_no_trailing_hardbreak(&mut self, attrs: &[ast::Attribute]) -> bool { + self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, false) + } + + fn print_outer_attributes_inline(&mut self, attrs: &[ast::Attribute]) -> bool { + self.print_either_attributes(attrs, ast::AttrStyle::Outer, true, true) + } + + fn print_attribute(&mut self, attr: &ast::Attribute) { + self.print_attribute_inline(attr, false) + } + + fn print_meta_list_item(&mut self, item: &ast::NestedMetaItem) { + match item { + ast::NestedMetaItem::MetaItem(mi) => self.print_meta_item(mi), + ast::NestedMetaItem::Lit(lit) => self.print_meta_item_lit(lit), + } + } + + fn print_meta_item(&mut self, item: &ast::MetaItem) { + self.ibox(INDENT_UNIT); + match &item.kind { + ast::MetaItemKind::Word => self.print_path(&item.path, false, 0), + ast::MetaItemKind::NameValue(value) => { + self.print_path(&item.path, false, 0); + self.space(); + self.word_space("="); + self.print_meta_item_lit(value); + } + ast::MetaItemKind::List(items) => { + self.print_path(&item.path, false, 0); + self.popen(); + self.commasep(Consistent, items, |s, i| s.print_meta_list_item(i)); + self.pclose(); + } + } + self.end(); + } + + pub(crate) fn bounds_to_string(&self, bounds: &[ast::GenericBound]) -> String { + Self::to_string(|s| s.print_type_bounds(bounds)) + } + + pub(crate) fn where_bound_predicate_to_string( + &self, + where_bound_predicate: &ast::WhereBoundPredicate, + ) -> String { + Self::to_string(|s| s.print_where_bound_predicate(where_bound_predicate)) + } + + pub(crate) fn tt_to_string(&self, tt: &TokenTree) -> String { + Self::to_string(|s| { + s.print_tt(tt, false); + }) + } + + pub(crate) fn tts_to_string(&self, tokens: &TokenStream) -> String { + Self::to_string(|s| s.print_tts(tokens, false)) + } + + pub(crate) fn path_segment_to_string(&self, p: &ast::PathSegment) -> String { + Self::to_string(|s| s.print_path_segment(p, false)) + } + + pub(crate) fn meta_list_item_to_string(&self, li: &ast::NestedMetaItem) -> String { + Self::to_string(|s| s.print_meta_list_item(li)) + } + + pub(crate) fn attribute_to_string(&self, attr: &ast::Attribute) -> String { + Self::to_string(|s| s.print_attribute(attr)) + } } |