From 1d78004575bea3b958b199d50a8491ae3fd65679 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 17 Jun 2024 15:14:07 +0000 Subject: [PATCH 1/2] Add Unicode block-drawing compiler output support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add nightly-only theming support to rustc output using Unicode box drawing characters instead of ASCII-art to draw the terminal UI: After: ``` error: foo ╭▸ test.rs:3:3 │ 3 │ X0 Y0 Z0 │ ┌───╿──│──┘ │ ┌│───│──┘ │ ┏││━━━┙ │ ┃││ 4 │ ┃││ X1 Y1 Z1 5 │ ┃││ X2 Y2 Z2 │ ┃│└────╿──│──┘ `Z` label │ ┃└─────│──┤ │ ┗━━━━━━┥ `Y` is a good letter too │ `X` is a good letter ╰╴ note: bar ╭▸ test.rs:4:3 │ 4 │ ┏ X1 Y1 Z1 5 │ ┃ X2 Y2 Z2 6 │ ┃ X3 Y3 Z3 │ ┗━━━━━━━━━━┛ ├ note: bar ╰ note: baz note: qux ╭▸ test.rs:4:3 │ 4 │ X1 Y1 Z1 ╰╴ ━━━━━━━━ ``` Before: ``` error: foo --> test.rs:3:3 | 3 | X0 Y0 Z0 | ___^__-__- | |___|__| | ||___| | ||| 4 | ||| X1 Y1 Z1 5 | ||| X2 Y2 Z2 | |||____^__-__- `Z` label | ||_____|__| | |______| `Y` is a good letter too | `X` is a good letter | note: bar --> test.rs:4:3 | 4 | / X1 Y1 Z1 5 | | X2 Y2 Z2 6 | | X3 Y3 Z3 | |__________^ = note: bar = note: baz note: qux --> test.rs:4:3 | 4 | X1 Y1 Z1 | ^^^^^^^^ ``` --- compiler/rustc_errors/src/emitter.rs | 703 +++++++-- compiler/rustc_errors/src/json.rs | 7 +- compiler/rustc_parse/src/parser/tests.rs | 1401 +++++++++++++++-- compiler/rustc_session/src/config.rs | 9 + compiler/rustc_session/src/session.rs | 14 +- src/librustdoc/core.rs | 9 +- src/librustdoc/doctest.rs | 5 + .../ui/empty_line_after/doc_comments.stderr | 20 +- .../empty_line_after/outer_attribute.stderr | 18 +- .../tests/ui/four_forward_slashes.stderr | 10 +- .../ui/four_forward_slashes_first_line.stderr | 2 +- .../too_long_first_doc_paragraph-fix.stderr | 2 +- .../ui/too_long_first_doc_paragraph.stderr | 4 +- tests/rustdoc-ui/invalid-syntax.stderr | 2 +- ...svg => huge_multispan_highlight.ascii.svg} | 14 +- .../codemap_tests/huge_multispan_highlight.rs | 5 +- .../huge_multispan_highlight.unicode.svg | 116 ++ .../{E0271.stderr => E0271.ascii.stderr} | 4 +- tests/ui/diagnostic-width/E0271.rs | 6 +- .../ui/diagnostic-width/E0271.unicode.stderr | 22 + ...g-human.stderr => flag-human.ascii.stderr} | 2 +- tests/ui/diagnostic-width/flag-human.rs | 6 +- .../flag-human.unicode.stderr | 11 + ...g-E0308.stderr => long-E0308.ascii.stderr} | 16 +- tests/ui/diagnostic-width/long-E0308.rs | 4 +- .../long-E0308.unicode.stderr | 82 + ...idth-unicode-multiline-label.ascii.stderr} | 2 +- .../non-1-width-unicode-multiline-label.rs | 4 +- ...dth-unicode-multiline-label.unicode.stderr | 18 + ...=> non-whitespace-trimming-2.ascii.stderr} | 2 +- .../non-whitespace-trimming-2.rs | 4 +- .../non-whitespace-trimming-2.unicode.stderr | 11 + tests/ui/error-emitter/highlighting.svg | 2 +- .../ui/error-emitter/highlighting.windows.svg | 2 +- tests/ui/error-emitter/unicode-output.rs | 21 + tests/ui/error-emitter/unicode-output.svg | 72 + tests/ui/parser/bad-char-literals.stderr | 2 +- 37 files changed, 2339 insertions(+), 295 deletions(-) rename tests/ui/codemap_tests/{huge_multispan_highlight.svg => huge_multispan_highlight.ascii.svg} (94%) create mode 100644 tests/ui/codemap_tests/huge_multispan_highlight.unicode.svg rename tests/ui/diagnostic-width/{E0271.stderr => E0271.ascii.stderr} (94%) create mode 100644 tests/ui/diagnostic-width/E0271.unicode.stderr rename tests/ui/diagnostic-width/{flag-human.stderr => flag-human.ascii.stderr} (89%) create mode 100644 tests/ui/diagnostic-width/flag-human.unicode.stderr rename tests/ui/diagnostic-width/{long-E0308.stderr => long-E0308.ascii.stderr} (88%) create mode 100644 tests/ui/diagnostic-width/long-E0308.unicode.stderr rename tests/ui/diagnostic-width/{non-1-width-unicode-multiline-label.stderr => non-1-width-unicode-multiline-label.ascii.stderr} (97%) create mode 100644 tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.unicode.stderr rename tests/ui/diagnostic-width/{non-whitespace-trimming-2.stderr => non-whitespace-trimming-2.ascii.stderr} (91%) create mode 100644 tests/ui/diagnostic-width/non-whitespace-trimming-2.unicode.stderr create mode 100644 tests/ui/error-emitter/unicode-output.rs create mode 100644 tests/ui/error-emitter/unicode-output.svg diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 0ccc71ae06c45..120f5ba7d4867 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -44,6 +44,7 @@ const DEFAULT_COLUMN_WIDTH: usize = 140; #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum HumanReadableErrorType { Default, + Unicode, AnnotateSnippet, Short, } @@ -595,6 +596,12 @@ impl ColorConfig { } } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum OutputTheme { + Ascii, + Unicode, +} + /// Handles the writing of `HumanReadableErrorType::Default` and `HumanReadableErrorType::Short` #[derive(Setters)] pub struct HumanEmitter { @@ -613,6 +620,7 @@ pub struct HumanEmitter { macro_backtrace: bool, track_diagnostics: bool, terminal_url: TerminalUrl, + theme: OutputTheme, } #[derive(Debug)] @@ -637,6 +645,7 @@ impl HumanEmitter { macro_backtrace: false, track_diagnostics: false, terminal_url: TerminalUrl::No, + theme: OutputTheme::Ascii, } } @@ -680,17 +689,19 @@ impl HumanEmitter { }) .collect(); buffer.puts(line_offset, code_offset, &code, Style::Quotation); + let placeholder = self.margin(); if margin.was_cut_left() { // We have stripped some code/whitespace from the beginning, make it clear. - buffer.puts(line_offset, code_offset, "...", Style::LineNumber); + buffer.puts(line_offset, code_offset, placeholder, Style::LineNumber); } if margin.was_cut_right(line_len) { + let padding: usize = placeholder.chars().map(|ch| char_width(ch)).sum(); // We have stripped some code after the rightmost span end, make it clear we did so. - buffer.puts(line_offset, code_offset + taken - 3, "...", Style::LineNumber); + buffer.puts(line_offset, code_offset + taken - padding, placeholder, Style::LineNumber); } buffer.puts(line_offset, 0, &self.maybe_anonymized(line_index), Style::LineNumber); - draw_col_separator_no_space(buffer, line_offset, width_offset - 2); + self.draw_col_separator_no_space(buffer, line_offset, width_offset - 2); } #[instrument(level = "trace", skip(self), ret)] @@ -702,6 +713,7 @@ impl HumanEmitter { width_offset: usize, code_offset: usize, margin: Margin, + close_window: bool, ) -> Vec<(usize, Style)> { // Draw: // @@ -767,13 +779,10 @@ impl HumanEmitter { for ann in &line.annotations { if let AnnotationType::MultilineStart(depth) = ann.annotation_type { if source_string.chars().take(ann.start_col.display).all(|c| c.is_whitespace()) { - let style = if ann.is_primary { - Style::UnderlinePrimary - } else { - Style::UnderlineSecondary - }; - annotations.push((depth, style)); - buffer_ops.push((line_offset, width_offset + depth - 1, '/', style)); + let uline = self.underline(ann.is_primary); + let chr = uline.multiline_whole_line; + annotations.push((depth, uline.style)); + buffer_ops.push((line_offset, width_offset + depth - 1, chr, uline.style)); } else { short_start = false; break; @@ -970,7 +979,7 @@ impl HumanEmitter { // 3 │ X0 Y0 Z0 // │ ┏━━━━━┛ │ │ < We are writing these lines // │ ┃┌───────┘ │ < by reverting the "depth" of - // │ ┃│┌─────────┘ < their multilne spans. + // │ ┃│┌─────────┘ < their multiline spans. // 4 │ ┃││ X1 Y1 Z1 // 5 │ ┃││ X2 Y2 Z2 // │ ┃│└────╿──│──┘ `Z` label @@ -997,7 +1006,10 @@ impl HumanEmitter { // 4 | } // | for pos in 0..=line_len { - draw_col_separator_no_space(buffer, line_offset + pos + 1, width_offset - 2); + self.draw_col_separator_no_space(buffer, line_offset + pos + 1, width_offset - 2); + } + if close_window { + self.draw_col_separator_end(buffer, line_offset + line_len + 1, width_offset - 2); } // Write the horizontal lines for multiline annotations @@ -1013,21 +1025,17 @@ impl HumanEmitter { // 4 | } // | _ for &(pos, annotation) in &annotations_position { - let style = if annotation.is_primary { - Style::UnderlinePrimary - } else { - Style::UnderlineSecondary - }; + let underline = self.underline(annotation.is_primary); let pos = pos + 1; match annotation.annotation_type { AnnotationType::MultilineStart(depth) | AnnotationType::MultilineEnd(depth) => { - draw_range( + self.draw_range( buffer, - '_', + underline.multiline_horizontal, line_offset + pos, width_offset + depth, (code_offset + annotation.start_col.display).saturating_sub(left), - style, + underline.style, ); } _ if self.teach => { @@ -1035,7 +1043,7 @@ impl HumanEmitter { line_offset, (code_offset + annotation.start_col.display).saturating_sub(left), (code_offset + annotation.end_col.display).saturating_sub(left), - style, + underline.style, annotation.is_primary, ); } @@ -1055,33 +1063,78 @@ impl HumanEmitter { // 4 | | } // | |_ for &(pos, annotation) in &annotations_position { - let style = if annotation.is_primary { - Style::UnderlinePrimary - } else { - Style::UnderlineSecondary - }; + let underline = self.underline(annotation.is_primary); let pos = pos + 1; if pos > 1 && (annotation.has_label() || annotation.takes_space()) { for p in line_offset + 1..=line_offset + pos { + if let AnnotationType::MultilineLine(_) = annotation.annotation_type { + buffer.putc( + p, + (code_offset + annotation.start_col.display).saturating_sub(left), + underline.multiline_vertical, + underline.style, + ); + } else { + buffer.putc( + p, + (code_offset + annotation.start_col.display).saturating_sub(left), + underline.vertical_text_line, + underline.style, + ); + } + } + if let AnnotationType::MultilineStart(_) = annotation.annotation_type { buffer.putc( - p, + line_offset + pos, (code_offset + annotation.start_col.display).saturating_sub(left), - '|', - style, + underline.bottom_right, + underline.style, + ); + } + if let AnnotationType::MultilineEnd(_) = annotation.annotation_type + && annotation.has_label() + { + buffer.putc( + line_offset + pos, + (code_offset + annotation.start_col.display).saturating_sub(left), + underline.multiline_bottom_right_with_text, + underline.style, ); } } match annotation.annotation_type { AnnotationType::MultilineStart(depth) => { + buffer.putc( + line_offset + pos, + width_offset + depth - 1, + underline.top_left, + underline.style, + ); for p in line_offset + pos + 1..line_offset + line_len + 2 { - buffer.putc(p, width_offset + depth - 1, '|', style); + buffer.putc( + p, + width_offset + depth - 1, + underline.multiline_vertical, + underline.style, + ); } } AnnotationType::MultilineEnd(depth) => { - for p in line_offset..=line_offset + pos { - buffer.putc(p, width_offset + depth - 1, '|', style); + for p in line_offset..line_offset + pos { + buffer.putc( + p, + width_offset + depth - 1, + underline.multiline_vertical, + underline.style, + ); } + buffer.putc( + line_offset + pos, + width_offset + depth - 1, + underline.bottom_left, + underline.style, + ); } _ => (), } @@ -1102,7 +1155,11 @@ impl HumanEmitter { let style = if annotation.is_primary { Style::LabelPrimary } else { Style::LabelSecondary }; let (pos, col) = if pos == 0 { - (pos + 1, (annotation.end_col.display + 1).saturating_sub(left)) + if annotation.end_col.display == 0 { + (pos + 1, (annotation.end_col.display + 2).saturating_sub(left)) + } else { + (pos + 1, (annotation.end_col.display + 1).saturating_sub(left)) + } } else { (pos + 2, annotation.start_col.display.saturating_sub(left)) }; @@ -1135,18 +1192,60 @@ impl HumanEmitter { // 3 | // 4 | } // | _^ test - for &(_, annotation) in &annotations_position { - let (underline, style) = if annotation.is_primary { - ('^', Style::UnderlinePrimary) - } else { - ('-', Style::UnderlineSecondary) - }; + for &(pos, annotation) in &annotations_position { + let uline = self.underline(annotation.is_primary); for p in annotation.start_col.display..annotation.end_col.display { + // The default span label underline. buffer.putc( line_offset + 1, (code_offset + p).saturating_sub(left), - underline, - style, + uline.underline, + uline.style, + ); + } + + if pos == 0 + && matches!( + annotation.annotation_type, + AnnotationType::MultilineStart(_) | AnnotationType::MultilineEnd(_) + ) + { + // The beginning of a multiline span with its leftward moving line on the same line. + buffer.putc( + line_offset + 1, + (code_offset + annotation.start_col.display).saturating_sub(left), + match annotation.annotation_type { + AnnotationType::MultilineStart(_) => uline.top_right_flat, + AnnotationType::MultilineEnd(_) => uline.multiline_end_same_line, + _ => panic!("unexpected annotation type: {annotation:?}"), + }, + uline.style, + ); + } else if pos != 0 + && matches!( + annotation.annotation_type, + AnnotationType::MultilineStart(_) | AnnotationType::MultilineEnd(_) + ) + { + // The beginning of a multiline span with its leftward moving line on another line, + // so we start going down first. + buffer.putc( + line_offset + 1, + (code_offset + annotation.start_col.display).saturating_sub(left), + match annotation.annotation_type { + AnnotationType::MultilineStart(_) => uline.multiline_start_down, + AnnotationType::MultilineEnd(_) => uline.multiline_end_up, + _ => panic!("unexpected annotation type: {annotation:?}"), + }, + uline.style, + ); + } else if pos != 0 && annotation.has_label() { + // The beginning of a span label with an actual label, we'll point down. + buffer.putc( + line_offset + 1, + (code_offset + annotation.start_col.display).saturating_sub(left), + uline.label_start, + uline.style, ); } } @@ -1217,7 +1316,7 @@ impl HumanEmitter { padding: usize, label: &str, override_style: Option + + + + + error[E0308]: `match` arms have incompatible types + + ╭▸ $DIR/huge_multispan_highlight.rs:99:18 + + + + LL let _ = match true { + + ────────── `match` arms have incompatible types + + LL true => ( + + ┌─────────────────┘ + + LL // last line shown in multispan header + + + + LL + + LL ), + + └─────────┘ this is found to be of type `()` + + LL false => " + + ┏━━━━━━━━━━━━━━━━━━┛ + + + + LL + + LL ", + + ╰╴┗━━━━━━━━━┛ expected `()`, found `&str` + + + + error[E0308]: `match` arms have incompatible types + + ╭▸ $DIR/huge_multispan_highlight.rs:216:18 + + + + LL let _ = match true { + + ────────── `match` arms have incompatible types + + LL true => ( + + ┌─────────────────┘ + + LL + + LL 1 // last line shown in multispan header + + + + LL + + LL ), + + └─────────┘ this is found to be of type `{integer}` + + LL false => " + + ┏━━━━━━━━━━━━━━━━━━┛ + + LL + + LL + + LL 1 last line shown in multispan + + + + LL + + LL ", + + ╰╴┗━━━━━━━━━┛ expected integer, found `&str` + + + + error: aborting due to 2 previous errors + + + + For more information about this error, try `rustc --explain E0308`. + + + + + + diff --git a/tests/ui/diagnostic-width/E0271.stderr b/tests/ui/diagnostic-width/E0271.ascii.stderr similarity index 94% rename from tests/ui/diagnostic-width/E0271.stderr rename to tests/ui/diagnostic-width/E0271.ascii.stderr index 31ec3fe366f4b..e276299e9e8ef 100644 --- a/tests/ui/diagnostic-width/E0271.stderr +++ b/tests/ui/diagnostic-width/E0271.ascii.stderr @@ -1,5 +1,5 @@ error[E0271]: type mismatch resolving `>, ...>>, ...>>, ...> as Future>::Error == Foo` - --> $DIR/E0271.rs:18:5 + --> $DIR/E0271.rs:20:5 | LL | / Box::new( LL | | Ok::<_, ()>( @@ -11,7 +11,7 @@ LL | | ) | |_____^ type mismatch resolving `, ...>>, ...> as Future>::Error == Foo` | note: expected this to be `Foo` - --> $DIR/E0271.rs:8:18 + --> $DIR/E0271.rs:10:18 | LL | type Error = E; | ^ diff --git a/tests/ui/diagnostic-width/E0271.rs b/tests/ui/diagnostic-width/E0271.rs index d8cb24898ac30..ce41ad2952bc9 100644 --- a/tests/ui/diagnostic-width/E0271.rs +++ b/tests/ui/diagnostic-width/E0271.rs @@ -1,4 +1,6 @@ -//@ compile-flags: --diagnostic-width=40 +//@ revisions: ascii unicode +//@[ascii] compile-flags: --diagnostic-width=40 +//@[unicode] compile-flags: -Zunstable-options=yes --error-format=human-unicode --diagnostic-width=40 //@ normalize-stderr-test: "long-type-\d+" -> "long-type-hash" trait Future { type Error; @@ -15,7 +17,7 @@ impl Future for Option { struct Foo; fn foo() -> Box> { - Box::new( //~ ERROR E0271 + Box::new( //[ascii]~ ERROR E0271 Ok::<_, ()>( Err::<(), _>( Ok::<_, ()>( diff --git a/tests/ui/diagnostic-width/E0271.unicode.stderr b/tests/ui/diagnostic-width/E0271.unicode.stderr new file mode 100644 index 0000000000000..4a96ca36cd78d --- /dev/null +++ b/tests/ui/diagnostic-width/E0271.unicode.stderr @@ -0,0 +1,22 @@ +error[E0271]: type mismatch resolving `>, ...>>, ...>>, ...> as Future>::Error == Foo` + ╭▸ $DIR/E0271.rs:20:5 + │ +LL │ ┏ Box::new( +LL │ ┃ Ok::<_, ()>( +LL │ ┃ Err::<(), _>( +LL │ ┃ Ok::<_, ()>( + ‡ ┃ +LL │ ┃ ) +LL │ ┃ ) + │ ┗━━━━━┛ type mismatch resolving `, ...>>, ...> as Future>::Error == Foo` + ╰╴ +note: expected this to be `Foo` + ╭▸ $DIR/E0271.rs:10:18 + │ +LL │ type Error = E; + │ ━ + ╰ note: required for the cast from `Box>, ()>>, ()>>, ()>>` to `Box<(dyn Future + 'static)>` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/diagnostic-width/flag-human.stderr b/tests/ui/diagnostic-width/flag-human.ascii.stderr similarity index 89% rename from tests/ui/diagnostic-width/flag-human.stderr rename to tests/ui/diagnostic-width/flag-human.ascii.stderr index eaa9684108069..4593304e087d2 100644 --- a/tests/ui/diagnostic-width/flag-human.stderr +++ b/tests/ui/diagnostic-width/flag-human.ascii.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/flag-human.rs:7:17 + --> $DIR/flag-human.rs:9:17 | LL | ..._: () = 42; | -- ^^ expected `()`, found integer diff --git a/tests/ui/diagnostic-width/flag-human.rs b/tests/ui/diagnostic-width/flag-human.rs index a46122ed78350..1af4165914164 100644 --- a/tests/ui/diagnostic-width/flag-human.rs +++ b/tests/ui/diagnostic-width/flag-human.rs @@ -1,9 +1,11 @@ -//@ compile-flags: --diagnostic-width=20 +//@ revisions: ascii unicode +//@[ascii] compile-flags: --diagnostic-width=20 +//@[unicode] compile-flags: -Zunstable-options=yes --error-format=human-unicode --diagnostic-width=20 // This test checks that `-Z output-width` effects the human error output by restricting it to an // arbitrarily low value so that the effect is visible. fn main() { let _: () = 42; - //~^ ERROR mismatched types + //[ascii]~^ ERROR mismatched types } diff --git a/tests/ui/diagnostic-width/flag-human.unicode.stderr b/tests/ui/diagnostic-width/flag-human.unicode.stderr new file mode 100644 index 0000000000000..50176564786b1 --- /dev/null +++ b/tests/ui/diagnostic-width/flag-human.unicode.stderr @@ -0,0 +1,11 @@ +error[E0308]: mismatched types + ╭▸ $DIR/flag-human.rs:9:17 + │ +LL │ …t _: () = 42; + │ ┬─ ━━ expected `()`, found integer + │ │ + ╰╴ expected due to this + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/diagnostic-width/long-E0308.stderr b/tests/ui/diagnostic-width/long-E0308.ascii.stderr similarity index 88% rename from tests/ui/diagnostic-width/long-E0308.stderr rename to tests/ui/diagnostic-width/long-E0308.ascii.stderr index eb37da037e9d7..d45d6bf329bd3 100644 --- a/tests/ui/diagnostic-width/long-E0308.stderr +++ b/tests/ui/diagnostic-width/long-E0308.ascii.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/long-E0308.rs:44:9 + --> $DIR/long-E0308.rs:46:9 | LL | let x: Atype< | _____________- @@ -20,11 +20,11 @@ LL | | )))))))))))))))))))))))))))))); | = note: expected struct `Atype, ...>` found enum `Result, ...>` - = note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308/long-E0308.long-type-hash.txt' + = note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308.ascii/long-E0308.long-type-hash.txt' = note: consider using `--verbose` to print the full type name to the console error[E0308]: mismatched types - --> $DIR/long-E0308.rs:57:26 + --> $DIR/long-E0308.rs:59:26 | LL | ))))))))))))))))) == Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(O... | __________________________^ @@ -36,11 +36,11 @@ LL | | )))))))))))))))))))))))); | = note: expected enum `Option>` found enum `Result, ...>` - = note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308/long-E0308.long-type-hash.txt' + = note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308.ascii/long-E0308.long-type-hash.txt' = note: consider using `--verbose` to print the full type name to the console error[E0308]: mismatched types - --> $DIR/long-E0308.rs:88:9 + --> $DIR/long-E0308.rs:90:9 | LL | let x: Atype< | ____________- @@ -56,11 +56,11 @@ LL | | > = (); | = note: expected struct `Atype, ...>` found unit type `()` - = note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308/long-E0308.long-type-hash.txt' + = note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308.ascii/long-E0308.long-type-hash.txt' = note: consider using `--verbose` to print the full type name to the console error[E0308]: mismatched types - --> $DIR/long-E0308.rs:91:17 + --> $DIR/long-E0308.rs:93:17 | LL | let _: () = Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(O... | ____________--___^ @@ -74,7 +74,7 @@ LL | | )))))))))))))))))))))))); | = note: expected unit type `()` found enum `Result, ...>` - = note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308/long-E0308.long-type-hash.txt' + = note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308.ascii/long-E0308.long-type-hash.txt' = note: consider using `--verbose` to print the full type name to the console error: aborting due to 4 previous errors diff --git a/tests/ui/diagnostic-width/long-E0308.rs b/tests/ui/diagnostic-width/long-E0308.rs index 150164ba21b4d..73f81f5872a64 100644 --- a/tests/ui/diagnostic-width/long-E0308.rs +++ b/tests/ui/diagnostic-width/long-E0308.rs @@ -1,4 +1,6 @@ -//@ compile-flags: --diagnostic-width=60 -Zwrite-long-types-to-disk=yes +//@ revisions: ascii unicode +//@[ascii] compile-flags: --diagnostic-width=60 -Zwrite-long-types-to-disk=yes +//@[unicode] compile-flags: -Zunstable-options=yes --json=diagnostic-unicode --diagnostic-width=60 -Zwrite-long-types-to-disk=yes //@ normalize-stderr-test: "long-type-\d+" -> "long-type-hash" mod a { diff --git a/tests/ui/diagnostic-width/long-E0308.unicode.stderr b/tests/ui/diagnostic-width/long-E0308.unicode.stderr new file mode 100644 index 0000000000000..3e8d881d7a6b1 --- /dev/null +++ b/tests/ui/diagnostic-width/long-E0308.unicode.stderr @@ -0,0 +1,82 @@ +error[E0308]: mismatched types + ╭▸ $DIR/long-E0308.rs:46:9 + │ +LL │ let x: Atype< + │ ┌─────────────┘ +LL │ │ Btype< +LL │ │ Ctype< +LL │ │ Atype< + ‡ │ +LL │ │ i32 +LL │ │ > = Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(O… + │ │┏━━━━━│━━━┛ + │ └┃─────┤ + │ ┃ expected due to this +LL │ ┃ Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(O… +LL │ ┃ Ok("") +LL │ ┃ )))))))))))))))))))))))))))))) +LL │ ┃ )))))))))))))))))))))))))))))); + │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ expected `Atype, ...>`, found `Result, ...>` + │ + ├ note: expected struct `Atype, ...>` + │ found enum `Result, ...>` + ├ note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308.unicode/long-E0308.long-type-hash.txt' + ╰ note: consider using `--verbose` to print the full type name to the console + +error[E0308]: mismatched types + ╭▸ $DIR/long-E0308.rs:59:26 + │ +LL │ ))))))))))))))))) == Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(… + │ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━┛ +LL │ ┃ Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok… +LL │ ┃ Ok(Ok(Ok(Ok(Ok(Ok(Ok(""))))))) +LL │ ┃ )))))))))))))))))))))))))))))) +LL │ ┃ )))))))))))))))))))))))); + │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ expected `Option>`, found `Result, ...>` + │ + ├ note: expected enum `Option>` + │ found enum `Result, ...>` + ├ note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308.unicode/long-E0308.long-type-hash.txt' + ╰ note: consider using `--verbose` to print the full type name to the console + +error[E0308]: mismatched types + ╭▸ $DIR/long-E0308.rs:90:9 + │ +LL │ let x: Atype< + │ ┌────────────┘ +LL │ │ Btype< +LL │ │ Ctype< +LL │ │ Atype< + ‡ │ +LL │ │ i32 +LL │ │ > = (); + │ │ │ ━━ expected `Atype, ...>`, found `()` + │ └─────┤ + │ expected due to this + │ + ├ note: expected struct `Atype, ...>` + │ found unit type `()` + ├ note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308.unicode/long-E0308.long-type-hash.txt' + ╰ note: consider using `--verbose` to print the full type name to the console + +error[E0308]: mismatched types + ╭▸ $DIR/long-E0308.rs:93:17 + │ +LL │ let _: () = Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(… + │ ┏━━━━━━━━━━━━┬─━━━┛ + │ ┃ │ + │ ┃ expected due to this +LL │ ┃ Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok… +LL │ ┃ Ok(Ok(Ok(Ok(Ok(Ok(Ok(""))))))) +LL │ ┃ )))))))))))))))))))))))))))))) +LL │ ┃ )))))))))))))))))))))))); + │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ expected `()`, found `Result, ...>` + │ + ├ note: expected unit type `()` + │ found enum `Result, ...>` + ├ note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308.unicode/long-E0308.long-type-hash.txt' + ╰ note: consider using `--verbose` to print the full type name to the console + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.stderr b/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.ascii.stderr similarity index 97% rename from tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.stderr rename to tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.ascii.stderr index 8f200e15c64d8..4d8afb6f3ad9b 100644 --- a/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.stderr +++ b/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.ascii.stderr @@ -1,5 +1,5 @@ error[E0369]: cannot add `&str` to `&str` - --> $DIR/non-1-width-unicode-multiline-label.rs:5:260 + --> $DIR/non-1-width-unicode-multiline-label.rs:7:260 | LL | ...ཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗ྘ྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྽྾྿࿀࿁࿂࿃࿄࿅࿆࿇...࿋࿌࿍࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun + " really fun!"; | -------------- ^ -------------- &str diff --git a/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.rs b/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.rs index 1989ea8863592..61c4b31e03a62 100644 --- a/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.rs +++ b/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.rs @@ -1,7 +1,9 @@ +//@ revisions: ascii unicode +//@[unicode] compile-flags: -Zunstable-options=yes --error-format=human-unicode // ignore-tidy-linelength fn main() { let unicode_is_fun = "؁‱ஹ௸௵꧄.ဪ꧅⸻𒈙𒐫﷽𒌄𒈟𒍼𒁎𒀱𒌧𒅃 𒈓𒍙𒊎𒄡𒅌𒁏𒀰𒐪𒐩𒈙𒐫𪚥"; let _ = "ༀ༁༂༃༄༅༆༇༈༉༊་༌།༎༏༐༑༒༓༔༕༖༗༘༙༚༛༜༝༞༟༠༡༢༣༤༥༦༧༨༩༪༫༬༭༮༯༰༱༲༳༴༵༶༷༸༹༺༻༼༽༾༿ཀཁགགྷངཅཆཇ཈ཉཊཋཌཌྷཎཏཐདདྷནཔཕབབྷམཙཚཛཛྷཝཞཟའཡརལཤཥསཧཨཀྵཪཫཬ཭཮཯཰ཱཱཱིིུུྲྀཷླྀཹེཻོཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗ྘ྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྽྾྿࿀࿁࿂࿃࿄࿅࿆࿇࿈࿉࿊࿋࿌࿍࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun + " really fun!"; - //~^ ERROR cannot add `&str` to `&str` + //[ascii]~^ ERROR cannot add `&str` to `&str` } diff --git a/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.unicode.stderr b/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.unicode.stderr new file mode 100644 index 0000000000000..ed8ce770bb7ea --- /dev/null +++ b/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.unicode.stderr @@ -0,0 +1,18 @@ +error[E0369]: cannot add `&str` to `&str` + ╭▸ $DIR/non-1-width-unicode-multiline-label.rs:7:260 + │ +LL │ …ཻོཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗ྘ྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྽྾྿࿀࿁࿂࿃࿄࿅࿆࿇࿈࿉…࿋࿌࿍࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun + " really fun!"; + │ ┬───────────── ┯ ────────────── &str + │ │ │ + │ │ `+` cannot be used to concatenate two `&str` strings + │ &str + │ + ╰ note: string concatenation requires an owned `String` on the left +help: create an owned `String` from a string reference + ╭╴ +LL │ let _ = "ༀ༁༂༃༄༅༆༇༈༉༊་༌།༎༏༐༑༒༓༔༕༖༗༘༙༚༛༜༝༞༟༠༡༢༣༤༥༦༧༨༩༪༫༬༭༮༯༰༱༲༳༴༵༶༷༸༹༺༻༼༽༾༿ཀཁགགྷངཅཆཇ཈ཉཊཋཌཌྷཎཏཐདདྷནཔཕབབྷམཙཚཛཛྷཝཞཟའཡརལཤཥསཧཨཀྵཪཫཬ཭཮཯཰ཱཱཱིིུུྲྀཷླྀཹེཻོཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗ྘ྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྽྾྿࿀࿁࿂࿃࿄࿅࿆࿇࿈࿉࿊࿋࿌࿍࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun.to_owned() + " really fun!"; + ╰╴ +++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0369`. diff --git a/tests/ui/diagnostic-width/non-whitespace-trimming-2.stderr b/tests/ui/diagnostic-width/non-whitespace-trimming-2.ascii.stderr similarity index 91% rename from tests/ui/diagnostic-width/non-whitespace-trimming-2.stderr rename to tests/ui/diagnostic-width/non-whitespace-trimming-2.ascii.stderr index a7d5c0bfb9415..70bd149545cfe 100644 --- a/tests/ui/diagnostic-width/non-whitespace-trimming-2.stderr +++ b/tests/ui/diagnostic-width/non-whitespace-trimming-2.ascii.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/non-whitespace-trimming-2.rs:4:311 + --> $DIR/non-whitespace-trimming-2.rs:6:311 | LL | ...13; let _: usize = 14; let _: usize = 15; let _: () = 42; let _: usize = 0; let _: usize = 1; let _: usize = 2; let _: usize = 3; let ... | -- ^^ expected `()`, found integer diff --git a/tests/ui/diagnostic-width/non-whitespace-trimming-2.rs b/tests/ui/diagnostic-width/non-whitespace-trimming-2.rs index abd9e189a7537..283506bd6c90d 100644 --- a/tests/ui/diagnostic-width/non-whitespace-trimming-2.rs +++ b/tests/ui/diagnostic-width/non-whitespace-trimming-2.rs @@ -1,6 +1,8 @@ +//@ revisions: ascii unicode +//@[unicode] compile-flags: -Zunstable-options=yes --error-format=human-unicode // ignore-tidy-linelength fn main() { let _: usize = 0; let _: usize = 1; let _: usize = 2; let _: usize = 3; let _: usize = 4; let _: usize = 5; let _: usize = 6; let _: usize = 7; let _: usize = 8; let _: usize = 9; let _: usize = 10; let _: usize = 11; let _: usize = 12; let _: usize = 13; let _: usize = 14; let _: usize = 15; let _: () = 42; let _: usize = 0; let _: usize = 1; let _: usize = 2; let _: usize = 3; let _: usize = 4; let _: usize = 5; let _: usize = 6; let _: usize = 7; let _: usize = 8; let _: usize = 9; let _: usize = 10; let _: usize = 11; let _: usize = 12; let _: usize = 13; let _: usize = 14; let _: usize = 15; -//~^ ERROR mismatched types +//[ascii]~^ ERROR mismatched types } diff --git a/tests/ui/diagnostic-width/non-whitespace-trimming-2.unicode.stderr b/tests/ui/diagnostic-width/non-whitespace-trimming-2.unicode.stderr new file mode 100644 index 0000000000000..600d196de1673 --- /dev/null +++ b/tests/ui/diagnostic-width/non-whitespace-trimming-2.unicode.stderr @@ -0,0 +1,11 @@ +error[E0308]: mismatched types + ╭▸ $DIR/non-whitespace-trimming-2.rs:6:311 + │ +LL │ …= 13; let _: usize = 14; let _: usize = 15; let _: () = 42; let _: usize = 0; let _: usize = 1; let _: usize = 2; let _: usize = 3; let _:… + │ ┬─ ━━ expected `()`, found integer + │ │ + ╰╴ expected due to this + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/error-emitter/highlighting.svg b/tests/ui/error-emitter/highlighting.svg index be92c00c19bdc..a4019c78f4841 100644 --- a/tests/ui/error-emitter/highlighting.svg +++ b/tests/ui/error-emitter/highlighting.svg @@ -49,7 +49,7 @@ LL | fn query(_: fn(Box<(dyn Any + Send + '_)>) -> Pin<Box<( - | ____^^^^^_- + | ____^^^^^_- LL | | dyn Future<Output = Result<Box<(dyn Any + 'static)>, String>> + Send + 'static diff --git a/tests/ui/error-emitter/highlighting.windows.svg b/tests/ui/error-emitter/highlighting.windows.svg index 152245da9ddc1..c2378113b86f5 100644 --- a/tests/ui/error-emitter/highlighting.windows.svg +++ b/tests/ui/error-emitter/highlighting.windows.svg @@ -50,7 +50,7 @@ LL | fn query(_: fn(Box<(dyn Any + Send + '_)>) -> Pin<Box<( - | ____^^^^^_- + | ____^^^^^_- LL | | dyn Future<Output = Result<Box<(dyn Any + 'static)>, String>> + Send + 'static diff --git a/tests/ui/error-emitter/unicode-output.rs b/tests/ui/error-emitter/unicode-output.rs new file mode 100644 index 0000000000000..ba6db37b66c22 --- /dev/null +++ b/tests/ui/error-emitter/unicode-output.rs @@ -0,0 +1,21 @@ +//@ compile-flags: -Zunstable-options=yes --error-format=human-unicode --color=always +//@ edition:2018 +//@ only-linux + +use core::pin::Pin; +use core::future::Future; +use core::any::Any; + +fn query(_: fn(Box<(dyn Any + Send + '_)>) -> Pin, String>> + Send + 'static +)>>) {} + +fn wrapped_fn<'a>(_: Box<(dyn Any + Send)>) -> Pin, String>> + Send + 'static +)>> { + Box::pin(async { Err("nope".into()) }) +} + +fn main() { + query(wrapped_fn); +} diff --git a/tests/ui/error-emitter/unicode-output.svg b/tests/ui/error-emitter/unicode-output.svg new file mode 100644 index 0000000000000..f98fd8b74032b --- /dev/null +++ b/tests/ui/error-emitter/unicode-output.svg @@ -0,0 +1,72 @@ + + + + + + + error[E0308]: mismatched types + + ╭▸ $DIR/unicode-output.rs:20:11 + + + + LL query(wrapped_fn); + + ┬──── ━━━━━━━━━━ one type is more general than the other + + + + arguments to this function are incorrect + + + + note: expected fn pointer `for<'a> fn(Box<(dyn Any + Send + 'a)>) -> Pin<_>` + + found fn item `fn(Box<(dyn Any + Send + 'static)>) -> Pin<_> {wrapped_fn}` + + note: function defined here + + ╭▸ $DIR/unicode-output.rs:9:4 + + + + LL fn query(_: fn(Box<(dyn Any + Send + '_)>) -> Pin<Box<( + + ┌────━━━━━─┘ + + LL dyn Future<Output = Result<Box<(dyn Any + 'static)>, String>> + Send + 'static + + LL )>>) {} + + ╰╴└───┘ + + + + error: aborting due to 1 previous error + + + + For more information about this error, try `rustc --explain E0308`. + + + + + + diff --git a/tests/ui/parser/bad-char-literals.stderr b/tests/ui/parser/bad-char-literals.stderr index 1fb324a1b7e84..5a81ede0336ff 100644 --- a/tests/ui/parser/bad-char-literals.stderr +++ b/tests/ui/parser/bad-char-literals.stderr @@ -15,7 +15,7 @@ error: character constant must be escaped: `\n` LL | ' | ______^ LL | | '; - | |_ + | |_^ | help: escape the character | From acf6344b42b86bf63c73632620438fc4836b0d8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Sun, 10 Nov 2024 17:51:37 +0100 Subject: [PATCH 2/2] Address review comments --- compiler/rustc_errors/src/emitter.rs | 51 ++++++++++++++-------------- compiler/rustc_session/src/config.rs | 32 ++++++++--------- compiler/rustc_span/src/lib.rs | 4 +++ 3 files changed, 45 insertions(+), 42 deletions(-) diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 120f5ba7d4867..06c961c33042d 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -22,7 +22,7 @@ use rustc_error_messages::{FluentArgs, SpanLabel}; use rustc_lint_defs::pluralize; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::SourceMap; -use rustc_span::{FileLines, FileName, SourceFile, Span, char_width}; +use rustc_span::{FileLines, FileName, SourceFile, Span, char_width, str_width}; use termcolor::{Buffer, BufferWriter, Color, ColorChoice, ColorSpec, StandardStream, WriteColor}; use tracing::{debug, instrument, trace, warn}; @@ -113,8 +113,12 @@ impl Margin { fn was_cut_right(&self, line_len: usize) -> bool { let right = if self.computed_right == self.span_right || self.computed_right == self.label_right { + // FIXME: This comment refers to the only callsite of this method. + // Rephrase it or refactor it, so it can stand on its own. // Account for the "..." padding given above. Otherwise we end up with code lines // that do fit but end in "..." as if they were trimmed. + // FIXME: Don't hard-code this offset. Is this meant to represent + // `2 * str_width(self.margin())`? self.computed_right - 6 } else { self.computed_right @@ -673,6 +677,7 @@ impl HumanEmitter { // Create the source line we will highlight. let left = margin.left(line_len); let right = margin.right(line_len); + // FIXME: The following code looks fishy. See #132860. // On long lines, we strip the source line, accounting for unicode. let mut taken = 0; let code: String = source_string @@ -695,7 +700,7 @@ impl HumanEmitter { buffer.puts(line_offset, code_offset, placeholder, Style::LineNumber); } if margin.was_cut_right(line_len) { - let padding: usize = placeholder.chars().map(|ch| char_width(ch)).sum(); + let padding = str_width(placeholder); // We have stripped some code after the rightmost span end, make it clear we did so. buffer.puts(line_offset, code_offset + taken - padding, placeholder, Style::LineNumber); } @@ -744,6 +749,7 @@ impl HumanEmitter { // Left trim let left = margin.left(source_string.len()); + // FIXME: This looks fishy. See #132860. // Account for unicode characters of width !=0 that were removed. let left = source_string.chars().take(left).map(|ch| char_width(ch)).sum(); @@ -1068,21 +1074,15 @@ impl HumanEmitter { if pos > 1 && (annotation.has_label() || annotation.takes_space()) { for p in line_offset + 1..=line_offset + pos { - if let AnnotationType::MultilineLine(_) = annotation.annotation_type { - buffer.putc( - p, - (code_offset + annotation.start_col.display).saturating_sub(left), - underline.multiline_vertical, - underline.style, - ); - } else { - buffer.putc( - p, - (code_offset + annotation.start_col.display).saturating_sub(left), - underline.vertical_text_line, - underline.style, - ); - } + buffer.putc( + p, + (code_offset + annotation.start_col.display).saturating_sub(left), + match annotation.annotation_type { + AnnotationType::MultilineLine(_) => underline.multiline_vertical, + _ => underline.vertical_text_line, + }, + underline.style, + ); } if let AnnotationType::MultilineStart(_) = annotation.annotation_type { buffer.putc( @@ -2134,7 +2134,7 @@ impl HumanEmitter { } let placeholder = self.margin(); - let padding: usize = placeholder.chars().map(|ch| char_width(ch)).sum(); + let padding = str_width(placeholder); buffer.puts( row_num, max_line_num_len.saturating_sub(padding), @@ -2224,11 +2224,11 @@ impl HumanEmitter { }; // ...or trailing spaces. Account for substitutions containing unicode // characters. - let sub_len: usize = - if is_whitespace_addition { &part.snippet } else { part.snippet.trim() } - .chars() - .map(|ch| char_width(ch)) - .sum(); + let sub_len: usize = str_width(if is_whitespace_addition { + &part.snippet + } else { + part.snippet.trim() + }); let offset: isize = offsets .iter() @@ -2266,8 +2266,7 @@ impl HumanEmitter { } // length of the code after substitution - let full_sub_len = - part.snippet.chars().map(|ch| char_width(ch)).sum::() as isize; + let full_sub_len = str_width(&part.snippet) as isize; // length of the code to be substituted let snippet_len = span_end_pos as isize - span_start_pos as isize; @@ -2282,7 +2281,7 @@ impl HumanEmitter { // if we elided some lines, add an ellipsis if lines.next().is_some() { let placeholder = self.margin(); - let padding: usize = placeholder.chars().map(|ch| char_width(ch)).sum(); + let padding = str_width(placeholder); buffer.puts( row_num, max_line_num_len.saturating_sub(padding), diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 352152a1bd42c..114ee7ac9ded1 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1772,8 +1772,8 @@ pub fn parse_error_format( color, )); early_dcx.early_fatal(format!( - "argument for `--error-format` must be `human`, `json` or \ - `short` (instead was `{arg}`)" + "argument for `--error-format` must be `human`, `human-annotate-rs`, \ + `human-unicode`, `json`, `pretty-json` or `short` (instead was `{arg}`)" )) } } @@ -1826,21 +1826,21 @@ pub fn parse_crate_edition(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches fn check_error_format_stability( early_dcx: &EarlyDiagCtxt, unstable_opts: &UnstableOptions, - error_format: ErrorOutputType, + format: ErrorOutputType, ) { - if !unstable_opts.unstable_options { - if let ErrorOutputType::Json { pretty: true, .. } = error_format { - early_dcx.early_fatal("`--error-format=pretty-json` is unstable"); - } - if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet, _) = - error_format - { - early_dcx.early_fatal("`--error-format=human-annotate-rs` is unstable"); - } - if let ErrorOutputType::HumanReadable(HumanReadableErrorType::Unicode, _) = error_format { - early_dcx.early_fatal("`--error-format=human-unicode` is unstable"); - } - } + if unstable_opts.unstable_options { + return; + } + let format = match format { + ErrorOutputType::Json { pretty: true, .. } => "pretty-json", + ErrorOutputType::HumanReadable(format, _) => match format { + HumanReadableErrorType::AnnotateSnippet => "human-annotate-rs", + HumanReadableErrorType::Unicode => "human-unicode", + _ => return, + }, + _ => return, + }; + early_dcx.early_fatal(format!("`--error-format={format}` is unstable")) } fn parse_output_types( diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 5b1be5bca0593..ef775068515ef 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -2223,6 +2223,10 @@ pub fn char_width(ch: char) -> usize { } } +pub fn str_width(s: &str) -> usize { + s.chars().map(char_width).sum() +} + /// Normalizes the source code and records the normalizations. fn normalize_src(src: &mut String) -> Vec { let mut normalized_pos = vec![];