summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_ast_pretty
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_ast_pretty')
-rw-r--r--compiler/rustc_ast_pretty/Cargo.toml1
-rw-r--r--compiler/rustc_ast_pretty/src/lib.rs8
-rw-r--r--compiler/rustc_ast_pretty/src/pp.rs17
-rw-r--r--compiler/rustc_ast_pretty/src/pp/convenience.rs2
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs404
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/delimited.rs41
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/expr.rs211
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/item.rs24
8 files changed, 379 insertions, 329 deletions
diff --git a/compiler/rustc_ast_pretty/Cargo.toml b/compiler/rustc_ast_pretty/Cargo.toml
index af1524c8b..12a08f065 100644
--- a/compiler/rustc_ast_pretty/Cargo.toml
+++ b/compiler/rustc_ast_pretty/Cargo.toml
@@ -5,6 +5,7 @@ edition = "2021"
[dependencies]
# tidy-alphabetical-start
+itertools = "0.11"
rustc_ast = { path = "../rustc_ast" }
rustc_span = { path = "../rustc_span" }
thin-vec = "0.2.12"
diff --git a/compiler/rustc_ast_pretty/src/lib.rs b/compiler/rustc_ast_pretty/src/lib.rs
index 475bdb023..670f2a458 100644
--- a/compiler/rustc_ast_pretty/src/lib.rs
+++ b/compiler/rustc_ast_pretty/src/lib.rs
@@ -1,11 +1,9 @@
-#![cfg_attr(not(bootstrap), allow(internal_features))]
-#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
-#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![allow(internal_features)]
+#![feature(rustdoc_internals)]
+#![doc(rust_logo)]
#![deny(rustc::untranslatable_diagnostic)]
#![deny(rustc::diagnostic_outside_of_impl)]
-#![feature(associated_type_bounds)]
#![feature(box_patterns)]
-#![feature(with_negative_coherence)]
#![recursion_limit = "256"]
mod helpers;
diff --git a/compiler/rustc_ast_pretty/src/pp.rs b/compiler/rustc_ast_pretty/src/pp.rs
index 7ab8c3eab..96f5eff68 100644
--- a/compiler/rustc_ast_pretty/src/pp.rs
+++ b/compiler/rustc_ast_pretty/src/pp.rs
@@ -165,20 +165,20 @@ enum IndentStyle {
}
#[derive(Clone, Copy, Default, PartialEq)]
-pub struct BreakToken {
+pub(crate) struct BreakToken {
offset: isize,
blank_space: isize,
pre_break: Option<char>,
}
#[derive(Clone, Copy, PartialEq)]
-pub struct BeginToken {
+pub(crate) struct BeginToken {
indent: IndentStyle,
breaks: Breaks,
}
-#[derive(Clone, PartialEq)]
-pub enum Token {
+#[derive(PartialEq)]
+pub(crate) enum Token {
// In practice a string token contains either a `&'static str` or a
// `String`. `Cow` is overkill for this because we never modify the data,
// but it's more convenient than rolling our own more specialized type.
@@ -229,7 +229,6 @@ pub struct Printer {
last_printed: Option<Token>,
}
-#[derive(Clone)]
struct BufEntry {
token: Token,
size: isize,
@@ -251,16 +250,16 @@ impl Printer {
}
}
- pub fn last_token(&self) -> Option<&Token> {
+ pub(crate) fn last_token(&self) -> Option<&Token> {
self.last_token_still_buffered().or_else(|| self.last_printed.as_ref())
}
- pub fn last_token_still_buffered(&self) -> Option<&Token> {
+ pub(crate) fn last_token_still_buffered(&self) -> Option<&Token> {
self.buf.last().map(|last| &last.token)
}
/// Be very careful with this!
- pub fn replace_last_token_still_buffered(&mut self, token: Token) {
+ pub(crate) fn replace_last_token_still_buffered(&mut self, token: Token) {
self.buf.last_mut().unwrap().token = token;
}
@@ -314,7 +313,7 @@ impl Printer {
}
}
- pub fn offset(&mut self, offset: isize) {
+ pub(crate) fn offset(&mut self, offset: isize) {
if let Some(BufEntry { token: Token::Break(token), .. }) = &mut self.buf.last_mut() {
token.offset += offset;
}
diff --git a/compiler/rustc_ast_pretty/src/pp/convenience.rs b/compiler/rustc_ast_pretty/src/pp/convenience.rs
index 93310dd45..c4c4fdce7 100644
--- a/compiler/rustc_ast_pretty/src/pp/convenience.rs
+++ b/compiler/rustc_ast_pretty/src/pp/convenience.rs
@@ -66,7 +66,7 @@ impl Printer {
}
}
- pub fn hardbreak_tok_offset(off: isize) -> Token {
+ pub(crate) fn hardbreak_tok_offset(off: isize) -> Token {
Token::Break(BreakToken {
offset: off,
blank_space: SIZE_INFINITY,
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))
+ }
}
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/delimited.rs b/compiler/rustc_ast_pretty/src/pprust/state/delimited.rs
deleted file mode 100644
index fe0640baa..000000000
--- a/compiler/rustc_ast_pretty/src/pprust/state/delimited.rs
+++ /dev/null
@@ -1,41 +0,0 @@
-use std::iter::Peekable;
-use std::mem;
-use std::ops::Deref;
-
-pub struct Delimited<I: Iterator> {
- is_first: bool,
- iter: Peekable<I>,
-}
-
-pub trait IterDelimited: Iterator + Sized {
- fn delimited(self) -> Delimited<Self> {
- Delimited { is_first: true, iter: self.peekable() }
- }
-}
-
-impl<I: Iterator> IterDelimited for I {}
-
-pub struct IteratorItem<T> {
- value: T,
- pub is_first: bool,
- pub is_last: bool,
-}
-
-impl<I: Iterator> Iterator for Delimited<I> {
- type Item = IteratorItem<I::Item>;
-
- fn next(&mut self) -> Option<Self::Item> {
- let value = self.iter.next()?;
- let is_first = mem::replace(&mut self.is_first, false);
- let is_last = self.iter.peek().is_none();
- Some(IteratorItem { value, is_first, is_last })
- }
-}
-
-impl<T> Deref for IteratorItem<T> {
- type Target = T;
-
- fn deref(&self) -> &Self::Target {
- &self.value
- }
-}
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
index edbc35003..f5ffcddb8 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
@@ -1,6 +1,6 @@
use crate::pp::Breaks::Inconsistent;
-use crate::pprust::state::{AnnNode, IterDelimited, PrintState, State, INDENT_UNIT};
-
+use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT};
+use itertools::{Itertools, Position};
use rustc_ast::ptr::P;
use rustc_ast::token;
use rustc_ast::util::literal::escape_byte_str_symbol;
@@ -12,6 +12,19 @@ use rustc_ast::{
};
use std::fmt::Write;
+#[derive(Copy, Clone, Debug)]
+pub(crate) struct FixupContext {
+ pub parenthesize_exterior_struct_lit: bool,
+}
+
+/// The default amount of fixing is minimal fixing. Fixups should be turned on
+/// in a targetted fashion where needed.
+impl Default for FixupContext {
+ fn default() -> Self {
+ FixupContext { parenthesize_exterior_struct_lit: false }
+ }
+}
+
impl<'a> State<'a> {
fn print_else(&mut self, els: Option<&ast::Expr>) {
if let Some(_else) = els {
@@ -55,21 +68,22 @@ impl<'a> State<'a> {
self.pclose()
}
- fn print_expr_maybe_paren(&mut self, expr: &ast::Expr, prec: i8) {
- self.print_expr_cond_paren(expr, expr.precedence().order() < prec)
+ fn print_expr_maybe_paren(&mut self, expr: &ast::Expr, prec: i8, fixup: FixupContext) {
+ self.print_expr_cond_paren(expr, expr.precedence().order() < prec, fixup);
}
/// Prints an expr using syntax that's acceptable in a condition position, such as the `cond` in
/// `if cond { ... }`.
fn print_expr_as_cond(&mut self, expr: &ast::Expr) {
- self.print_expr_cond_paren(expr, Self::cond_needs_par(expr))
+ let fixup = FixupContext { parenthesize_exterior_struct_lit: true };
+ self.print_expr_cond_paren(expr, Self::cond_needs_par(expr), fixup)
}
/// Does `expr` need parentheses when printed in a condition position?
///
/// These cases need parens due to the parse error observed in #26461: `if return {}`
/// parses as the erroneous construct `if (return {})`, not `if (return) {}`.
- pub(super) fn cond_needs_par(expr: &ast::Expr) -> bool {
+ fn cond_needs_par(expr: &ast::Expr) -> bool {
match expr.kind {
ast::ExprKind::Break(..)
| ast::ExprKind::Closure(..)
@@ -80,11 +94,32 @@ impl<'a> State<'a> {
}
/// Prints `expr` or `(expr)` when `needs_par` holds.
- pub(super) fn print_expr_cond_paren(&mut self, expr: &ast::Expr, needs_par: bool) {
+ pub(super) fn print_expr_cond_paren(
+ &mut self,
+ expr: &ast::Expr,
+ needs_par: bool,
+ fixup: FixupContext,
+ ) {
if needs_par {
self.popen();
}
- self.print_expr(expr);
+
+ // If we are surrounding the whole cond in parentheses, such as:
+ //
+ // if (return Struct {}) {}
+ //
+ // then there is no need for parenthesizing the individual struct
+ // expressions within. On the other hand if the whole cond is not
+ // parenthesized, then print_expr must parenthesize exterior struct
+ // literals.
+ //
+ // if x == (Struct {}) {}
+ //
+ let fixup = FixupContext {
+ parenthesize_exterior_struct_lit: fixup.parenthesize_exterior_struct_lit && !needs_par,
+ };
+ self.print_expr(expr, fixup);
+
if needs_par {
self.pclose();
}
@@ -111,7 +146,7 @@ impl<'a> State<'a> {
self.ibox(0);
self.print_block_with_attrs(block, attrs);
} else {
- self.print_expr(&expr.value);
+ self.print_expr(&expr.value, FixupContext::default());
}
self.end();
}
@@ -119,9 +154,9 @@ impl<'a> State<'a> {
fn print_expr_repeat(&mut self, element: &ast::Expr, count: &ast::AnonConst) {
self.ibox(INDENT_UNIT);
self.word("[");
- self.print_expr(element);
+ self.print_expr(element, FixupContext::default());
self.word_space(";");
- self.print_expr(&count.value);
+ self.print_expr(&count.value, FixupContext::default());
self.word("]");
self.end();
}
@@ -149,18 +184,20 @@ impl<'a> State<'a> {
return;
}
self.cbox(0);
- for field in fields.iter().delimited() {
+ for (pos, field) in fields.iter().with_position() {
+ let is_first = matches!(pos, Position::First | Position::Only);
+ let is_last = matches!(pos, Position::Last | Position::Only);
self.maybe_print_comment(field.span.hi());
self.print_outer_attributes(&field.attrs);
- if field.is_first {
+ if is_first {
self.space_if_not_bol();
}
if !field.is_shorthand {
self.print_ident(field.ident);
self.word_nbsp(":");
}
- self.print_expr(&field.expr);
- if !field.is_last || has_rest {
+ self.print_expr(&field.expr, FixupContext::default());
+ if !is_last || has_rest {
self.word_space(",");
} else {
self.trailing_comma_or_space();
@@ -172,7 +209,7 @@ impl<'a> State<'a> {
}
self.word("..");
if let ast::StructRest::Base(expr) = rest {
- self.print_expr(expr);
+ self.print_expr(expr, FixupContext::default());
}
self.space();
}
@@ -190,13 +227,13 @@ impl<'a> State<'a> {
self.pclose()
}
- fn print_expr_call(&mut self, func: &ast::Expr, args: &[P<ast::Expr>]) {
+ fn print_expr_call(&mut self, func: &ast::Expr, args: &[P<ast::Expr>], fixup: FixupContext) {
let prec = match func.kind {
ast::ExprKind::Field(..) => parser::PREC_FORCE_PAREN,
_ => parser::PREC_POSTFIX,
};
- self.print_expr_maybe_paren(func, prec);
+ self.print_expr_maybe_paren(func, prec, fixup);
self.print_call_post(args)
}
@@ -205,8 +242,9 @@ impl<'a> State<'a> {
segment: &ast::PathSegment,
receiver: &ast::Expr,
base_args: &[P<ast::Expr>],
+ fixup: FixupContext,
) {
- self.print_expr_maybe_paren(receiver, parser::PREC_POSTFIX);
+ self.print_expr_maybe_paren(receiver, parser::PREC_POSTFIX, fixup);
self.word(".");
self.print_ident(segment.ident);
if let Some(args) = &segment.args {
@@ -215,7 +253,13 @@ impl<'a> State<'a> {
self.print_call_post(base_args)
}
- fn print_expr_binary(&mut self, op: ast::BinOp, lhs: &ast::Expr, rhs: &ast::Expr) {
+ fn print_expr_binary(
+ &mut self,
+ op: ast::BinOp,
+ lhs: &ast::Expr,
+ rhs: &ast::Expr,
+ fixup: FixupContext,
+ ) {
let assoc_op = AssocOp::from_ast_binop(op.node);
let prec = assoc_op.precedence() as i8;
let fixity = assoc_op.fixity();
@@ -251,15 +295,15 @@ impl<'a> State<'a> {
_ => left_prec,
};
- self.print_expr_maybe_paren(lhs, left_prec);
+ self.print_expr_maybe_paren(lhs, left_prec, fixup);
self.space();
- self.word_space(op.node.to_string());
- self.print_expr_maybe_paren(rhs, right_prec)
+ self.word_space(op.node.as_str());
+ self.print_expr_maybe_paren(rhs, right_prec, fixup)
}
- fn print_expr_unary(&mut self, op: ast::UnOp, expr: &ast::Expr) {
- self.word(ast::UnOp::to_string(op));
- self.print_expr_maybe_paren(expr, parser::PREC_PREFIX)
+ fn print_expr_unary(&mut self, op: ast::UnOp, expr: &ast::Expr, fixup: FixupContext) {
+ self.word(op.as_str());
+ self.print_expr_maybe_paren(expr, parser::PREC_PREFIX, fixup)
}
fn print_expr_addr_of(
@@ -267,6 +311,7 @@ impl<'a> State<'a> {
kind: ast::BorrowKind,
mutability: ast::Mutability,
expr: &ast::Expr,
+ fixup: FixupContext,
) {
self.word("&");
match kind {
@@ -276,14 +321,19 @@ impl<'a> State<'a> {
self.print_mutability(mutability, true);
}
}
- self.print_expr_maybe_paren(expr, parser::PREC_PREFIX)
+ self.print_expr_maybe_paren(expr, parser::PREC_PREFIX, fixup)
}
- pub fn print_expr(&mut self, expr: &ast::Expr) {
- self.print_expr_outer_attr_style(expr, true)
+ pub(super) fn print_expr(&mut self, expr: &ast::Expr, fixup: FixupContext) {
+ self.print_expr_outer_attr_style(expr, true, fixup)
}
- pub(super) fn print_expr_outer_attr_style(&mut self, expr: &ast::Expr, is_inline: bool) {
+ pub(super) fn print_expr_outer_attr_style(
+ &mut self,
+ expr: &ast::Expr,
+ is_inline: bool,
+ fixup: FixupContext,
+ ) {
self.maybe_print_comment(expr.span.lo());
let attrs = &expr.attrs;
@@ -312,19 +362,19 @@ impl<'a> State<'a> {
self.print_expr_tup(exprs);
}
ast::ExprKind::Call(func, args) => {
- self.print_expr_call(func, args);
+ self.print_expr_call(func, args, fixup);
}
ast::ExprKind::MethodCall(box ast::MethodCall { seg, receiver, args, .. }) => {
- self.print_expr_method_call(seg, receiver, args);
+ self.print_expr_method_call(seg, receiver, args, fixup);
}
ast::ExprKind::Binary(op, lhs, rhs) => {
- self.print_expr_binary(*op, lhs, rhs);
+ self.print_expr_binary(*op, lhs, rhs, fixup);
}
ast::ExprKind::Unary(op, expr) => {
- self.print_expr_unary(*op, expr);
+ self.print_expr_unary(*op, expr, fixup);
}
ast::ExprKind::AddrOf(k, m, expr) => {
- self.print_expr_addr_of(*k, *m, expr);
+ self.print_expr_addr_of(*k, *m, expr, fixup);
}
ast::ExprKind::Lit(token_lit) => {
self.print_token_literal(*token_lit, expr.span);
@@ -335,7 +385,7 @@ impl<'a> State<'a> {
}
ast::ExprKind::Cast(expr, ty) => {
let prec = AssocOp::As.precedence() as i8;
- self.print_expr_maybe_paren(expr, prec);
+ self.print_expr_maybe_paren(expr, prec, fixup);
self.space();
self.word_space("as");
self.print_type(ty);
@@ -343,7 +393,7 @@ impl<'a> State<'a> {
ast::ExprKind::Type(expr, ty) => {
self.word("type_ascribe!(");
self.ibox(0);
- self.print_expr(expr);
+ self.print_expr(expr, FixupContext::default());
self.word(",");
self.space_if_not_bol();
@@ -353,7 +403,7 @@ impl<'a> State<'a> {
self.word(")");
}
ast::ExprKind::Let(pat, scrutinee, _, _) => {
- self.print_let(pat, scrutinee);
+ self.print_let(pat, scrutinee, fixup);
}
ast::ExprKind::If(test, blk, elseopt) => self.print_if(test, blk, elseopt.as_deref()),
ast::ExprKind::While(test, blk, opt_label) => {
@@ -411,7 +461,7 @@ impl<'a> State<'a> {
binder,
capture_clause,
constness,
- asyncness,
+ coroutine_kind,
movability,
fn_decl,
body,
@@ -421,12 +471,12 @@ impl<'a> State<'a> {
self.print_closure_binder(binder);
self.print_constness(*constness);
self.print_movability(*movability);
- self.print_asyncness(*asyncness);
+ coroutine_kind.map(|coroutine_kind| self.print_coroutine_kind(coroutine_kind));
self.print_capture_clause(*capture_clause);
self.print_fn_params_and_ret(fn_decl, true);
self.space();
- self.print_expr(body);
+ self.print_expr(body, FixupContext::default());
self.end(); // need to close a box
// a box will be closed by print_expr, but we didn't want an overall
@@ -454,33 +504,33 @@ impl<'a> State<'a> {
self.print_block_with_attrs(blk, attrs);
}
ast::ExprKind::Await(expr, _) => {
- self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
+ self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX, fixup);
self.word(".await");
}
ast::ExprKind::Assign(lhs, rhs, _) => {
let prec = AssocOp::Assign.precedence() as i8;
- self.print_expr_maybe_paren(lhs, prec + 1);
+ self.print_expr_maybe_paren(lhs, prec + 1, fixup);
self.space();
self.word_space("=");
- self.print_expr_maybe_paren(rhs, prec);
+ self.print_expr_maybe_paren(rhs, prec, fixup);
}
ast::ExprKind::AssignOp(op, lhs, rhs) => {
let prec = AssocOp::Assign.precedence() as i8;
- self.print_expr_maybe_paren(lhs, prec + 1);
+ self.print_expr_maybe_paren(lhs, prec + 1, fixup);
self.space();
- self.word(op.node.to_string());
+ self.word(op.node.as_str());
self.word_space("=");
- self.print_expr_maybe_paren(rhs, prec);
+ self.print_expr_maybe_paren(rhs, prec, fixup);
}
ast::ExprKind::Field(expr, ident) => {
- self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
+ self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX, fixup);
self.word(".");
self.print_ident(*ident);
}
ast::ExprKind::Index(expr, index, _) => {
- self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
+ self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX, fixup);
self.word("[");
- self.print_expr(index);
+ self.print_expr(index, FixupContext::default());
self.word("]");
}
ast::ExprKind::Range(start, end, limits) => {
@@ -490,14 +540,14 @@ impl<'a> State<'a> {
// a "normal" binop gets parenthesized. (`LOr` is the lowest-precedence binop.)
let fake_prec = AssocOp::LOr.precedence() as i8;
if let Some(e) = start {
- self.print_expr_maybe_paren(e, fake_prec);
+ self.print_expr_maybe_paren(e, fake_prec, fixup);
}
match limits {
ast::RangeLimits::HalfOpen => self.word(".."),
ast::RangeLimits::Closed => self.word("..="),
}
if let Some(e) = end {
- self.print_expr_maybe_paren(e, fake_prec);
+ self.print_expr_maybe_paren(e, fake_prec, fixup);
}
}
ast::ExprKind::Underscore => self.word("_"),
@@ -511,7 +561,7 @@ impl<'a> State<'a> {
}
if let Some(expr) = opt_expr {
self.space();
- self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
+ self.print_expr_maybe_paren(expr, parser::PREC_JUMP, fixup);
}
}
ast::ExprKind::Continue(opt_label) => {
@@ -525,7 +575,7 @@ impl<'a> State<'a> {
self.word("return");
if let Some(expr) = result {
self.word(" ");
- self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
+ self.print_expr_maybe_paren(expr, parser::PREC_JUMP, fixup);
}
}
ast::ExprKind::Yeet(result) => {
@@ -534,13 +584,13 @@ impl<'a> State<'a> {
self.word("yeet");
if let Some(expr) = result {
self.word(" ");
- self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
+ self.print_expr_maybe_paren(expr, parser::PREC_JUMP, fixup);
}
}
ast::ExprKind::Become(result) => {
self.word("become");
self.word(" ");
- self.print_expr_maybe_paren(result, parser::PREC_JUMP);
+ self.print_expr_maybe_paren(result, parser::PREC_JUMP, fixup);
}
ast::ExprKind::InlineAsm(a) => {
// FIXME: This should have its own syntax, distinct from a macro invocation.
@@ -555,7 +605,7 @@ impl<'a> State<'a> {
self.word(reconstruct_format_args_template_string(&fmt.template));
for arg in fmt.arguments.all_args() {
self.word_space(",");
- self.print_expr(&arg.expr);
+ self.print_expr(&arg.expr, FixupContext::default());
}
self.end();
self.pclose();
@@ -582,7 +632,7 @@ impl<'a> State<'a> {
ast::ExprKind::MacCall(m) => self.print_mac(m),
ast::ExprKind::Paren(e) => {
self.popen();
- self.print_expr(e);
+ self.print_expr(e, FixupContext::default());
self.pclose();
}
ast::ExprKind::Yield(e) => {
@@ -590,11 +640,11 @@ impl<'a> State<'a> {
if let Some(expr) = e {
self.space();
- self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
+ self.print_expr_maybe_paren(expr, parser::PREC_JUMP, fixup);
}
}
ast::ExprKind::Try(e) => {
- self.print_expr_maybe_paren(e, parser::PREC_POSTFIX);
+ self.print_expr_maybe_paren(e, parser::PREC_POSTFIX, fixup);
self.word("?")
}
ast::ExprKind::TryBlock(blk) => {
@@ -626,31 +676,36 @@ impl<'a> State<'a> {
self.space();
if let Some(e) = &arm.guard {
self.word_space("if");
- self.print_expr(e);
+ self.print_expr(e, FixupContext::default());
self.space();
}
- self.word_space("=>");
- match &arm.body.kind {
- ast::ExprKind::Block(blk, opt_label) => {
- if let Some(label) = opt_label {
- self.print_ident(label.ident);
- self.word_space(":");
- }
+ if let Some(body) = &arm.body {
+ self.word_space("=>");
+
+ match &body.kind {
+ ast::ExprKind::Block(blk, opt_label) => {
+ if let Some(label) = opt_label {
+ self.print_ident(label.ident);
+ self.word_space(":");
+ }
- // The block will close the pattern's ibox.
- self.print_block_unclosed_indent(blk);
+ // The block will close the pattern's ibox.
+ self.print_block_unclosed_indent(blk);
- // If it is a user-provided unsafe block, print a comma after it.
- if let BlockCheckMode::Unsafe(ast::UserProvided) = blk.rules {
+ // If it is a user-provided unsafe block, print a comma after it.
+ if let BlockCheckMode::Unsafe(ast::UserProvided) = blk.rules {
+ self.word(",");
+ }
+ }
+ _ => {
+ self.end(); // Close the ibox for the pattern.
+ self.print_expr(body, FixupContext::default());
self.word(",");
}
}
- _ => {
- self.end(); // Close the ibox for the pattern.
- self.print_expr(&arm.body);
- self.word(",");
- }
+ } else {
+ self.word(",");
}
self.end(); // Close enclosing cbox.
}
@@ -679,7 +734,7 @@ impl<'a> State<'a> {
}
}
-pub fn reconstruct_format_args_template_string(pieces: &[FormatArgsPiece]) -> String {
+fn reconstruct_format_args_template_string(pieces: &[FormatArgsPiece]) -> String {
let mut template = "\"".to_string();
for piece in pieces {
match piece {
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
index 3393f034b..405ccc722 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
@@ -1,8 +1,9 @@
use crate::pp::Breaks::Inconsistent;
-use crate::pprust::state::delimited::IterDelimited;
+use crate::pprust::state::expr::FixupContext;
use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT};
use ast::StaticItem;
+use itertools::{Itertools, Position};
use rustc_ast as ast;
use rustc_ast::GenericBound;
use rustc_ast::ModKind;
@@ -20,7 +21,7 @@ impl<'a> State<'a> {
}
}
- pub(crate) fn print_foreign_item(&mut self, item: &ast::ForeignItem) {
+ fn print_foreign_item(&mut self, item: &ast::ForeignItem) {
let ast::Item { id, span, ident, ref attrs, ref kind, ref vis, tokens: _ } = *item;
self.ann.pre(self, AnnNode::SubItem(id));
self.hardbreak_if_not_bol();
@@ -97,7 +98,7 @@ impl<'a> State<'a> {
self.end(); // end the head-ibox
if let Some(body) = body {
self.word_space("=");
- self.print_expr(body);
+ self.print_expr(body, FixupContext::default());
}
self.print_where_clause(&generics.where_clause);
self.word(";");
@@ -368,7 +369,7 @@ impl<'a> State<'a> {
self.nbsp();
if !bounds.is_empty() {
self.word_nbsp("=");
- self.print_type_bounds(&bounds);
+ self.print_type_bounds(bounds);
}
self.print_where_clause(&generics.where_clause);
self.word(";");
@@ -499,7 +500,7 @@ impl<'a> State<'a> {
self.end();
self.end(); // Close the outer-box.
}
- ast::VariantData::Struct(fields, ..) => {
+ ast::VariantData::Struct { fields, .. } => {
self.print_where_clause(&generics.where_clause);
self.print_record_struct_body(fields, span);
}
@@ -514,11 +515,11 @@ impl<'a> State<'a> {
if let Some(d) = &v.disr_expr {
self.space();
self.word_space("=");
- self.print_expr(&d.value)
+ self.print_expr(&d.value, FixupContext::default())
}
}
- pub(crate) fn print_assoc_item(&mut self, item: &ast::AssocItem) {
+ fn print_assoc_item(&mut self, item: &ast::AssocItem) {
let ast::Item { id, span, ident, ref attrs, ref kind, ref vis, tokens: _ } = *item;
self.ann.pre(self, AnnNode::SubItem(id));
self.hardbreak_if_not_bol();
@@ -621,7 +622,7 @@ impl<'a> State<'a> {
self.print_where_clause_parts(where_clause.has_where_token, &where_clause.predicates);
}
- pub(crate) fn print_where_clause_parts(
+ fn print_where_clause_parts(
&mut self,
has_where_token: bool,
predicates: &[ast::WherePredicate],
@@ -668,7 +669,7 @@ impl<'a> State<'a> {
}
}
- pub fn print_where_bound_predicate(
+ pub(crate) fn print_where_bound_predicate(
&mut self,
where_bound_predicate: &ast::WhereBoundPredicate,
) {
@@ -712,9 +713,10 @@ impl<'a> State<'a> {
self.word("{");
self.zerobreak();
self.ibox(0);
- for use_tree in items.iter().delimited() {
+ for (pos, use_tree) in items.iter().with_position() {
+ let is_last = matches!(pos, Position::Last | Position::Only);
self.print_use_tree(&use_tree.0);
- if !use_tree.is_last {
+ if !is_last {
self.word(",");
if let ast::UseTreeKind::Nested(_) = use_tree.0.kind {
self.hardbreak();