diff options
| author | Eric Huss <eric@huss.org> | 2022-01-31 20:13:00 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-01-31 20:13:00 -0800 |
| commit | 2e39a3f6ec38f7671e10355bba2bb8a78a78b100 (patch) | |
| tree | 230c4de16377c731c76b5015a8a1bb028d02b8f9 | |
| parent | 8a70ea2394a1d431bc7ee70957afbf3979d176a0 (diff) | |
| parent | 7739fcab3062fdd71cf0d7377c86a5487e3638c1 (diff) | |
| download | rust-2e39a3f6ec38f7671e10355bba2bb8a78a78b100.tar.gz rust-2e39a3f6ec38f7671e10355bba2bb8a78a78b100.zip | |
Rollup merge of #93513 - dtolnay:linewidth, r=nagisa
Allow any pretty printed line to have at least 60 chars
Follow-up to #93155. The rustc AST pretty printer has a tendency to get stuck in "vertical smear mode" when formatting highly nested code, where it puts a linebreak at *every possible* linebreak opportunity once the indentation goes beyond the pretty printer's target line width:
```rust
...
((&([("test"
as
&str)]
as
[&str; 1])
as
&[&str; 1]),
(&([]
as
[ArgumentV1; 0])
as
&[ArgumentV1; 0]))
...
```
```rust
...
[(1
as
i32),
(2
as
i32),
(3
as
i32)]
as
[i32; 3]
...
```
This is less common after #93155 because that PR greatly reduced the total amount of indentation, but the "vertical smear mode" failure mode is still just as present when you have deeply nested modules, functions, or trait impls, such as in the case of macro-expanded code from `-Zunpretty=expanded`.
Vertical smear mode is never the best way to format highly indented code though. It does not prevent the target line width from being exceeded, and it produces output that is less readable than just a longer line.
This PR makes the pretty printing algorithm allow a minimum of 60 chars on every line independent of indentation. So as code gets more indented, the right margin eventually recedes to make room for formatting without vertical smear.
```console
├─────────────────────────────────────┤
├─────────────────────────────────────┤
├─────────────────────────────────────┤
├───────────────────────────────────┤
├─────────────────────────────────┤
├───────────────────────────────┤
├─────────────────────────────┤
├───────────────────────────┤
├───────────────────────────┤
├───────────────────────────┤
├───────────────────────────┤
├───────────────────────────┤
├─────────────────────────────┤
├───────────────────────────────┤
├─────────────────────────────────┤
├───────────────────────────────────┤
├─────────────────────────────────────┤
```
| -rw-r--r-- | compiler/rustc_ast_pretty/src/pp.rs | 16 | ||||
| -rw-r--r-- | src/test/pretty/issue-4264.pp | 3 | ||||
| -rw-r--r-- | src/test/ui/match/issue-82392.stdout | 5 | ||||
| -rw-r--r-- | src/test/ui/proc-macro/quote-debug.stdout | 3 |
4 files changed, 13 insertions, 14 deletions
diff --git a/compiler/rustc_ast_pretty/src/pp.rs b/compiler/rustc_ast_pretty/src/pp.rs index e1f43cb20dc..26d600cefc7 100644 --- a/compiler/rustc_ast_pretty/src/pp.rs +++ b/compiler/rustc_ast_pretty/src/pp.rs @@ -136,6 +136,7 @@ mod ring; use ring::RingBuffer; use std::borrow::Cow; +use std::cmp; use std::collections::VecDeque; use std::iter; @@ -199,10 +200,13 @@ enum PrintFrame { const SIZE_INFINITY: isize = 0xffff; +/// Target line width. +const MARGIN: isize = 78; +/// Every line is allowed at least this much space, even if highly indented. +const MIN_SPACE: isize = 60; + pub struct Printer { out: String, - /// Width of lines we're constrained to - margin: isize, /// Number of spaces left on line space: isize, /// Ring-buffer of tokens and calculated sizes @@ -237,11 +241,9 @@ struct BufEntry { impl Printer { pub fn new() -> Self { - let linewidth = 78; Printer { out: String::new(), - margin: linewidth as isize, - space: linewidth as isize, + space: MARGIN, buf: RingBuffer::new(), left_total: 0, right_total: 0, @@ -395,7 +397,7 @@ impl Printer { self.print_stack.push(PrintFrame::Broken { indent: self.indent, breaks: token.breaks }); self.indent = match token.indent { IndentStyle::Block { offset } => (self.indent as isize + offset) as usize, - IndentStyle::Visual => (self.margin - self.space) as usize, + IndentStyle::Visual => (MARGIN - self.space) as usize, }; } else { self.print_stack.push(PrintFrame::Fits); @@ -421,7 +423,7 @@ impl Printer { self.out.push('\n'); let indent = self.indent as isize + token.offset; self.pending_indentation = indent; - self.space = self.margin - indent; + self.space = cmp::max(MARGIN - indent, MIN_SPACE); } } diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp index 3830c3aa6c9..ea74a267be8 100644 --- a/src/test/pretty/issue-4264.pp +++ b/src/test/pretty/issue-4264.pp @@ -35,8 +35,7 @@ pub fn bar() ({ for<'r> fn(Arguments<'r>) -> String {format})(((::core::fmt::Arguments::new_v1 as fn(&[&'static str], &[ArgumentV1]) -> Arguments {Arguments::new_v1})((&([("test" - as &str)] as [&str; 1]) as - &[&str; 1]), + as &str)] as [&str; 1]) as &[&str; 1]), (&([] as [ArgumentV1; 0]) as &[ArgumentV1; 0])) as Arguments)) as String); (res as String) diff --git a/src/test/ui/match/issue-82392.stdout b/src/test/ui/match/issue-82392.stdout index 2054d43c409..bcab76b7c6b 100644 --- a/src/test/ui/match/issue-82392.stdout +++ b/src/test/ui/match/issue-82392.stdout @@ -11,7 +11,6 @@ pub fn main() ({ ({ } as ()) else if (let Some(a) = ((Some as - fn(i32) -> Option<i32> {Option::<i32>::Some})((3 - as i32)) as Option<i32>) as bool) ({ } as ()) - as ()) + fn(i32) -> Option<i32> {Option::<i32>::Some})((3 as i32)) as + Option<i32>) as bool) ({ } as ()) as ()) } as ()) diff --git a/src/test/ui/proc-macro/quote-debug.stdout b/src/test/ui/proc-macro/quote-debug.stdout index 79651f01b95..a648d6b6d4b 100644 --- a/src/test/ui/proc-macro/quote-debug.stdout +++ b/src/test/ui/proc-macro/quote-debug.stdout @@ -27,8 +27,7 @@ fn main() { crate::TokenStream::from(crate::TokenTree::Literal({ let mut iter = "\"world\"".parse::<crate::TokenStream>().unwrap().into_iter(); - if let (Some(crate::TokenTree::Literal(mut lit)), - None) = + if let (Some(crate::TokenTree::Literal(mut lit)), None) = (iter.next(), iter.next()) { lit.set_span(crate::Span::recover_proc_macro_span(2)); lit |
