diff options
| author | Esteban Küber <esteban@kuber.com.ar> | 2024-06-17 15:14:07 +0000 |
|---|---|---|
| committer | León Orell Valerian Liehr <me@fmease.dev> | 2024-11-10 23:57:18 +0100 |
| commit | 1d78004575bea3b958b199d50a8491ae3fd65679 (patch) | |
| tree | 61e6fcb1b058f58c6e8bb1c4b39661deb7d65150 /compiler/rustc_parse/src/parser/tests.rs | |
| parent | f61306d47bc98af8bb9d15f1adf6086785590a8c (diff) | |
| download | rust-1d78004575bea3b958b199d50a8491ae3fd65679.tar.gz rust-1d78004575bea3b958b199d50a8491ae3fd65679.zip | |
Add Unicode block-drawing compiler output support
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 | ^^^^^^^^ ```
Diffstat (limited to 'compiler/rustc_parse/src/parser/tests.rs')
| -rw-r--r-- | compiler/rustc_parse/src/parser/tests.rs | 1231 |
1 files changed, 1204 insertions, 27 deletions
diff --git a/compiler/rustc_parse/src/parser/tests.rs b/compiler/rustc_parse/src/parser/tests.rs index 92684505ab0..decaecd2682 100644 --- a/compiler/rustc_parse/src/parser/tests.rs +++ b/compiler/rustc_parse/src/parser/tests.rs @@ -12,7 +12,7 @@ use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, Toke use rustc_ast::{self as ast, PatKind, visit}; use rustc_ast_pretty::pprust::item_to_string; use rustc_data_structures::sync::Lrc; -use rustc_errors::emitter::HumanEmitter; +use rustc_errors::emitter::{HumanEmitter, OutputTheme}; use rustc_errors::{DiagCtxt, MultiSpan, PResult}; use rustc_session::parse::ParseSess; use rustc_span::source_map::{FilePathMapping, SourceMap}; @@ -36,16 +36,17 @@ fn string_to_parser(psess: &ParseSess, source_str: String) -> Parser<'_> { )) } -fn create_test_handler() -> (DiagCtxt, Lrc<SourceMap>, Arc<Mutex<Vec<u8>>>) { +fn create_test_handler(theme: OutputTheme) -> (DiagCtxt, Lrc<SourceMap>, Arc<Mutex<Vec<u8>>>) { let output = Arc::new(Mutex::new(Vec::new())); let source_map = Lrc::new(SourceMap::new(FilePathMapping::empty())); let fallback_bundle = rustc_errors::fallback_fluent_bundle( vec![crate::DEFAULT_LOCALE_RESOURCE, crate::DEFAULT_LOCALE_RESOURCE], false, ); - let emitter = HumanEmitter::new(Box::new(Shared { data: output.clone() }), fallback_bundle) + let mut emitter = HumanEmitter::new(Box::new(Shared { data: output.clone() }), fallback_bundle) .sm(Some(source_map.clone())) .diagnostic_width(Some(140)); + emitter = emitter.theme(theme); let dcx = DiagCtxt::new(Box::new(emitter)); (dcx, source_map, output) } @@ -69,7 +70,7 @@ fn with_expected_parse_error<T, F>(source_str: &str, expected_output: &str, f: F where F: for<'a> FnOnce(&mut Parser<'a>) -> PResult<'a, T>, { - let (handler, source_map, output) = create_test_handler(); + let (handler, source_map, output) = create_test_handler(OutputTheme::Ascii); let psess = ParseSess::with_dcx(handler, source_map); let mut p = string_to_parser(&psess, source_str.to_string()); let result = f(&mut p); @@ -189,34 +190,55 @@ impl<T: Write> Write for Shared<T> { } #[allow(rustc::untranslatable_diagnostic)] // no translation needed for tests -fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: &str) { +fn test_harness( + file_text: &str, + span_labels: Vec<SpanLabel>, + notes: Vec<(Option<(Position, Position)>, &'static str)>, + expected_output_ascii: &str, + expected_output_unicode: &str, +) { create_default_session_globals_then(|| { - let (dcx, source_map, output) = create_test_handler(); - source_map.new_source_file(Path::new("test.rs").to_owned().into(), file_text.to_owned()); - - let primary_span = make_span(&file_text, &span_labels[0].start, &span_labels[0].end); - let mut msp = MultiSpan::from_span(primary_span); - for span_label in span_labels { - let span = make_span(&file_text, &span_label.start, &span_label.end); - msp.push_span_label(span, span_label.label); - println!("span: {:?} label: {:?}", span, span_label.label); - println!("text: {:?}", source_map.span_to_snippet(span)); - } + for (theme, expected_output) in [ + (OutputTheme::Ascii, expected_output_ascii), + (OutputTheme::Unicode, expected_output_unicode), + ] { + let (dcx, source_map, output) = create_test_handler(theme); + source_map + .new_source_file(Path::new("test.rs").to_owned().into(), file_text.to_owned()); + + let primary_span = make_span(&file_text, &span_labels[0].start, &span_labels[0].end); + let mut msp = MultiSpan::from_span(primary_span); + for span_label in &span_labels { + let span = make_span(&file_text, &span_label.start, &span_label.end); + msp.push_span_label(span, span_label.label); + println!("span: {:?} label: {:?}", span, span_label.label); + println!("text: {:?}", source_map.span_to_snippet(span)); + } - dcx.handle().span_err(msp, "foo"); + let mut err = dcx.handle().struct_span_err(msp, "foo"); + for (position, note) in ¬es { + if let Some((start, end)) = position { + let span = make_span(&file_text, &start, &end); + err.span_note(span, *note); + } else { + err.note(*note); + } + } + err.emit(); - assert!( - expected_output.chars().next() == Some('\n'), - "expected output should begin with newline" - ); - let expected_output = &expected_output[1..]; + assert!( + expected_output.chars().next() == Some('\n'), + "expected output should begin with newline" + ); + let expected_output = &expected_output[1..]; - let bytes = output.lock().unwrap(); - let actual_output = str::from_utf8(&bytes).unwrap(); - println!("expected output:\n------\n{}------", expected_output); - println!("actual output:\n------\n{}------", actual_output); + let bytes = output.lock().unwrap(); + let actual_output = str::from_utf8(&bytes).unwrap(); + println!("expected output:\n------\n{}------", expected_output); + println!("actual output:\n------\n{}------", actual_output); - assert!(expected_output == actual_output) + assert!(expected_output == actual_output) + } }) } @@ -253,6 +275,7 @@ fn foo() { end: Position { string: "}", count: 1 }, label: "test", }], + vec![], r#" error: foo --> test.rs:2:10 @@ -263,6 +286,16 @@ error: foo | |_^ test "#, + r#" +error: foo + ╭▸ test.rs:2:10 + │ +2 │ fn foo() { + │ ┏━━━━━━━━━━┛ +3 │ ┃ } + ╰╴┗━┛ test + +"#, ); } @@ -280,6 +313,7 @@ fn foo() { end: Position { string: "}", count: 1 }, label: "test", }], + vec![], r#" error: foo --> test.rs:2:10 @@ -291,6 +325,17 @@ error: foo | |___^ test "#, + r#" +error: foo + ╭▸ test.rs:2:10 + │ +2 │ fn foo() { + │ ┏━━━━━━━━━━┛ + ‡ ┃ +5 │ ┃ } + ╰╴┗━━━┛ test + +"#, ); } #[test] @@ -315,6 +360,7 @@ fn foo() { label: "`Y` is a good letter too", }, ], + vec![], r#" error: foo --> test.rs:3:3 @@ -329,6 +375,20 @@ error: foo | `X` is a good letter "#, + r#" +error: foo + ╭▸ test.rs:3:3 + │ +3 │ X0 Y0 + │ ┏━━━━┛ │ + │ ┃┌──────┘ +4 │ ┃│ X1 Y1 +5 │ ┃│ X2 Y2 + │ ┃└────╿──┘ `Y` is a good letter too + │ ┗━━━━━┥ + ╰╴ `X` is a good letter + +"#, ); } @@ -353,6 +413,7 @@ fn foo() { label: "`Y` is a good letter too", }, ], + vec![], r#" error: foo --> test.rs:3:3 @@ -366,6 +427,72 @@ error: foo | `Y` is a good letter too "#, + r#" +error: foo + ╭▸ test.rs:3:3 + │ +3 │ X0 Y0 + │ ┏━━━━┛ │ + │ ┃┌──────┘ +4 │ ┃│ Y1 X1 + │ ┗│━━━━│━━┛ `X` is a good letter + │ └────┤ + ╰╴ `Y` is a good letter too + +"#, + ); +} + +#[test] +fn multiline_and_normal_overlap() { + test_harness( + r#" +fn foo() { + X0 Y0 Z0 + X1 Y1 Z1 + X2 Y2 Z2 + X3 Y3 Z3 +} +"#, + vec![ + SpanLabel { + start: Position { string: "Y0", count: 1 }, + end: Position { string: "X2", count: 1 }, + label: "`X` is a good letter", + }, + SpanLabel { + start: Position { string: "X0", count: 1 }, + end: Position { string: "Y0", count: 1 }, + label: "`Y` is a good letter too", + }, + ], + vec![], + r#" +error: foo + --> test.rs:3:6 + | +3 | X0 Y0 Z0 + | ___---^- + | | | + | | `Y` is a good letter too +4 | | X1 Y1 Z1 +5 | | X2 Y2 Z2 + | |____^ `X` is a good letter + +"#, + r#" +error: foo + ╭▸ test.rs:3:6 + │ +3 │ X0 Y0 Z0 + │ ┏━━━┬──┛─ + │ ┃ │ + │ ┃ `Y` is a good letter too +4 │ ┃ X1 Y1 Z1 +5 │ ┃ X2 Y2 Z2 + ╰╴┗━━━━┛ `X` is a good letter + +"#, ); } @@ -392,6 +519,7 @@ fn foo() { label: "`Y` is a good letter too", }, ], + vec![], r#" error: foo --> test.rs:3:6 @@ -406,6 +534,789 @@ error: foo | |____- `Y` is a good letter too "#, + r#" +error: foo + ╭▸ test.rs:3:6 + │ +3 │ X0 Y0 Z0 + │ ┏━━━━━━━┛ +4 │ ┃ X1 Y1 Z1 + │ ┃┌─────────┘ +5 │ ┃│ X2 Y2 Z2 + │ ┗│━━━━┛ `X` is a good letter +6 │ │ X3 Y3 Z3 + ╰╴ └────┘ `Y` is a good letter too + +"#, + ); +} + +#[test] +fn different_note_1() { + test_harness( + r#" +fn foo() { + X0 Y0 Z0 + X1 Y1 Z1 + X2 Y2 Z2 + X3 Y3 Z3 +} +"#, + vec![SpanLabel { + start: Position { string: "Y0", count: 1 }, + end: Position { string: "Z0", count: 1 }, + label: "`X` is a good letter", + }], + vec![(None, "bar")], + r#" +error: foo + --> test.rs:3:6 + | +3 | X0 Y0 Z0 + | ^^^^^ `X` is a good letter + | + = note: bar + +"#, + r#" +error: foo + ╭▸ test.rs:3:6 + │ +3 │ X0 Y0 Z0 + │ ━━━━━ `X` is a good letter + │ + ╰ note: bar + +"#, + ); +} + +#[test] +fn different_note_2() { + test_harness( + r#" +fn foo() { + X0 Y0 Z0 + X1 Y1 Z1 + X2 Y2 Z2 + X3 Y3 Z3 +} +"#, + vec![SpanLabel { + start: Position { string: "Y0", count: 1 }, + end: Position { string: "Z0", count: 1 }, + label: "`X` is a good letter", + }], + vec![(None, "bar"), (None, "qux")], + r#" +error: foo + --> test.rs:3:6 + | +3 | X0 Y0 Z0 + | ^^^^^ `X` is a good letter + | + = note: bar + = note: qux + +"#, + r#" +error: foo + ╭▸ test.rs:3:6 + │ +3 │ X0 Y0 Z0 + │ ━━━━━ `X` is a good letter + │ + ├ note: bar + ╰ note: qux + +"#, + ); +} + +#[test] +fn different_note_3() { + test_harness( + r#" +fn foo() { + X0 Y0 Z0 + X1 Y1 Z1 + X2 Y2 Z2 + X3 Y3 Z3 +} +"#, + vec![SpanLabel { + start: Position { string: "Y0", count: 1 }, + end: Position { string: "Z0", count: 1 }, + label: "`X` is a good letter", + }], + vec![(None, "bar"), (None, "baz"), (None, "qux")], + r#" +error: foo + --> test.rs:3:6 + | +3 | X0 Y0 Z0 + | ^^^^^ `X` is a good letter + | + = note: bar + = note: baz + = note: qux + +"#, + r#" +error: foo + ╭▸ test.rs:3:6 + │ +3 │ X0 Y0 Z0 + │ ━━━━━ `X` is a good letter + │ + ├ note: bar + ├ note: baz + ╰ note: qux + +"#, + ); +} + +#[test] +fn different_note_spanned_1() { + test_harness( + r#" +fn foo() { + X0 Y0 Z0 + X1 Y1 Z1 + X2 Y2 Z2 + X3 Y3 Z3 +} +"#, + vec![SpanLabel { + start: Position { string: "Y0", count: 1 }, + end: Position { string: "Z0", count: 1 }, + label: "`X` is a good letter", + }], + vec![( + Some((Position { string: "X1", count: 1 }, Position { string: "Z1", count: 1 })), + "bar", + )], + r#" +error: foo + --> test.rs:3:6 + | +3 | X0 Y0 Z0 + | ^^^^^ `X` is a good letter + | +note: bar + --> test.rs:4:3 + | +4 | X1 Y1 Z1 + | ^^^^^^^^ + +"#, + r#" +error: foo + ╭▸ test.rs:3:6 + │ +3 │ X0 Y0 Z0 + │ ━━━━━ `X` is a good letter + ╰╴ +note: bar + ╭▸ test.rs:4:3 + │ +4 │ X1 Y1 Z1 + ╰╴ ━━━━━━━━ + +"#, + ); +} + +#[test] +fn different_note_spanned_2() { + test_harness( + r#" +fn foo() { + X0 Y0 Z0 + X1 Y1 Z1 + X2 Y2 Z2 + X3 Y3 Z3 +} +"#, + vec![SpanLabel { + start: Position { string: "Y0", count: 1 }, + end: Position { string: "Z0", count: 1 }, + label: "`X` is a good letter", + }], + vec![ + ( + Some((Position { string: "X1", count: 1 }, Position { string: "Z1", count: 1 })), + "bar", + ), + ( + Some((Position { string: "X2", count: 1 }, Position { string: "Y2", count: 1 })), + "qux", + ), + ], + r#" +error: foo + --> test.rs:3:6 + | +3 | X0 Y0 Z0 + | ^^^^^ `X` is a good letter + | +note: bar + --> test.rs:4:3 + | +4 | X1 Y1 Z1 + | ^^^^^^^^ +note: qux + --> test.rs:5:3 + | +5 | X2 Y2 Z2 + | ^^^^^ + +"#, + r#" +error: foo + ╭▸ test.rs:3:6 + │ +3 │ X0 Y0 Z0 + │ ━━━━━ `X` is a good letter + ╰╴ +note: bar + ╭▸ test.rs:4:3 + │ +4 │ X1 Y1 Z1 + ╰╴ ━━━━━━━━ +note: qux + ╭▸ test.rs:5:3 + │ +5 │ X2 Y2 Z2 + ╰╴ ━━━━━ + +"#, + ); +} + +#[test] +fn different_note_spanned_3() { + test_harness( + r#" +fn foo() { + X0 Y0 Z0 + X1 Y1 Z1 + X2 Y2 Z2 + X3 Y3 Z3 +} +"#, + vec![SpanLabel { + start: Position { string: "Y0", count: 1 }, + end: Position { string: "Z0", count: 1 }, + label: "`X` is a good letter", + }], + vec![ + ( + Some((Position { string: "X1", count: 1 }, Position { string: "Z1", count: 1 })), + "bar", + ), + ( + Some((Position { string: "X1", count: 1 }, Position { string: "Z1", count: 1 })), + "baz", + ), + ( + Some((Position { string: "X1", count: 1 }, Position { string: "Z1", count: 1 })), + "qux", + ), + ], + r#" +error: foo + --> test.rs:3:6 + | +3 | X0 Y0 Z0 + | ^^^^^ `X` is a good letter + | +note: bar + --> test.rs:4:3 + | +4 | X1 Y1 Z1 + | ^^^^^^^^ +note: baz + --> test.rs:4:3 + | +4 | X1 Y1 Z1 + | ^^^^^^^^ +note: qux + --> test.rs:4:3 + | +4 | X1 Y1 Z1 + | ^^^^^^^^ + +"#, + r#" +error: foo + ╭▸ test.rs:3:6 + │ +3 │ X0 Y0 Z0 + │ ━━━━━ `X` is a good letter + ╰╴ +note: bar + ╭▸ test.rs:4:3 + │ +4 │ X1 Y1 Z1 + ╰╴ ━━━━━━━━ +note: baz + ╭▸ test.rs:4:3 + │ +4 │ X1 Y1 Z1 + ╰╴ ━━━━━━━━ +note: qux + ╭▸ test.rs:4:3 + │ +4 │ X1 Y1 Z1 + ╰╴ ━━━━━━━━ + +"#, + ); +} + +#[test] +fn different_note_spanned_4() { + test_harness( + r#" +fn foo() { + X0 Y0 Z0 + X1 Y1 Z1 + X2 Y2 Z2 + X3 Y3 Z3 +} +"#, + vec![SpanLabel { + start: Position { string: "Y0", count: 1 }, + end: Position { string: "Z0", count: 1 }, + label: "`X` is a good letter", + }], + vec![ + ( + Some((Position { string: "X1", count: 1 }, Position { string: "Z1", count: 1 })), + "bar", + ), + (None, "qux"), + ], + r#" +error: foo + --> test.rs:3:6 + | +3 | X0 Y0 Z0 + | ^^^^^ `X` is a good letter + | +note: bar + --> test.rs:4:3 + | +4 | X1 Y1 Z1 + | ^^^^^^^^ + = note: qux + +"#, + r#" +error: foo + ╭▸ test.rs:3:6 + │ +3 │ X0 Y0 Z0 + │ ━━━━━ `X` is a good letter + ╰╴ +note: bar + ╭▸ test.rs:4:3 + │ +4 │ X1 Y1 Z1 + │ ━━━━━━━━ + ╰ note: qux + +"#, + ); +} + +#[test] +fn different_note_spanned_5() { + test_harness( + r#" +fn foo() { + X0 Y0 Z0 + X1 Y1 Z1 + X2 Y2 Z2 + X3 Y3 Z3 +} +"#, + vec![SpanLabel { + start: Position { string: "Y0", count: 1 }, + end: Position { string: "Z0", count: 1 }, + label: "`X` is a good letter", + }], + vec![ + (None, "bar"), + ( + Some((Position { string: "X1", count: 1 }, Position { string: "Z1", count: 1 })), + "qux", + ), + ], + r#" +error: foo + --> test.rs:3:6 + | +3 | X0 Y0 Z0 + | ^^^^^ `X` is a good letter + | + = note: bar +note: qux + --> test.rs:4:3 + | +4 | X1 Y1 Z1 + | ^^^^^^^^ + +"#, + r#" +error: foo + ╭▸ test.rs:3:6 + │ +3 │ X0 Y0 Z0 + │ ━━━━━ `X` is a good letter + │ + ╰ note: bar +note: qux + ╭▸ test.rs:4:3 + │ +4 │ X1 Y1 Z1 + ╰╴ ━━━━━━━━ + +"#, + ); +} + +#[test] +fn different_note_spanned_6() { + test_harness( + r#" +fn foo() { + X0 Y0 Z0 + X1 Y1 Z1 + X2 Y2 Z2 + X3 Y3 Z3 +} +"#, + vec![SpanLabel { + start: Position { string: "Y0", count: 1 }, + end: Position { string: "Z0", count: 1 }, + label: "`X` is a good letter", + }], + vec![ + (None, "bar"), + ( + Some((Position { string: "X1", count: 1 }, Position { string: "Z1", count: 1 })), + "baz", + ), + ( + Some((Position { string: "X1", count: 1 }, Position { string: "Z1", count: 1 })), + "qux", + ), + ], + r#" +error: foo + --> test.rs:3:6 + | +3 | X0 Y0 Z0 + | ^^^^^ `X` is a good letter + | + = note: bar +note: baz + --> test.rs:4:3 + | +4 | X1 Y1 Z1 + | ^^^^^^^^ +note: qux + --> test.rs:4:3 + | +4 | X1 Y1 Z1 + | ^^^^^^^^ + +"#, + r#" +error: foo + ╭▸ test.rs:3:6 + │ +3 │ X0 Y0 Z0 + │ ━━━━━ `X` is a good letter + │ + ╰ note: bar +note: baz + ╭▸ test.rs:4:3 + │ +4 │ X1 Y1 Z1 + ╰╴ ━━━━━━━━ +note: qux + ╭▸ test.rs:4:3 + │ +4 │ X1 Y1 Z1 + ╰╴ ━━━━━━━━ + +"#, + ); +} + +#[test] +fn different_note_spanned_7() { + test_harness( + r#" +fn foo() { + X0 Y0 Z0 + X1 Y1 Z1 + X2 Y2 Z2 + X3 Y3 Z3 +} +"#, + vec![SpanLabel { + start: Position { string: "Y0", count: 1 }, + end: Position { string: "Z0", count: 1 }, + label: "`X` is a good letter", + }], + vec![ + ( + Some((Position { string: "X1", count: 1 }, Position { string: "Z3", count: 1 })), + "bar", + ), + (None, "baz"), + ( + Some((Position { string: "X1", count: 1 }, Position { string: "Z1", count: 1 })), + "qux", + ), + ], + r#" +error: foo + --> test.rs:3:6 + | +3 | X0 Y0 Z0 + | ^^^^^ `X` is a good letter + | +note: bar + --> test.rs:4:3 + | +4 | / X1 Y1 Z1 +5 | | X2 Y2 Z2 +6 | | X3 Y3 Z3 + | |__________^ + = note: baz +note: qux + --> test.rs:4:3 + | +4 | X1 Y1 Z1 + | ^^^^^^^^ + +"#, + r#" +error: foo + ╭▸ test.rs:3:6 + │ +3 │ X0 Y0 Z0 + │ ━━━━━ `X` is a good letter + ╰╴ +note: bar + ╭▸ test.rs:4:3 + │ +4 │ ┏ X1 Y1 Z1 +5 │ ┃ X2 Y2 Z2 +6 │ ┃ X3 Y3 Z3 + │ ┗━━━━━━━━━━┛ + ╰ note: baz +note: qux + ╭▸ test.rs:4:3 + │ +4 │ X1 Y1 Z1 + ╰╴ ━━━━━━━━ + +"#, + ); +} + +#[test] +fn different_note_spanned_8() { + test_harness( + r#" +fn foo() { + X0 Y0 Z0 + X1 Y1 Z1 + X2 Y2 Z2 + X3 Y3 Z3 +} +"#, + vec![SpanLabel { + start: Position { string: "Y0", count: 1 }, + end: Position { string: "Z0", count: 1 }, + label: "`X` is a good letter", + }], + vec![ + ( + Some((Position { string: "X1", count: 1 }, Position { string: "Z1", count: 1 })), + "bar", + ), + ( + Some((Position { string: "X1", count: 1 }, Position { string: "Z1", count: 1 })), + "baz", + ), + (None, "qux"), + ], + r#" +error: foo + --> test.rs:3:6 + | +3 | X0 Y0 Z0 + | ^^^^^ `X` is a good letter + | +note: bar + --> test.rs:4:3 + | +4 | X1 Y1 Z1 + | ^^^^^^^^ +note: baz + --> test.rs:4:3 + | +4 | X1 Y1 Z1 + | ^^^^^^^^ + = note: qux + +"#, + r#" +error: foo + ╭▸ test.rs:3:6 + │ +3 │ X0 Y0 Z0 + │ ━━━━━ `X` is a good letter + ╰╴ +note: bar + ╭▸ test.rs:4:3 + │ +4 │ X1 Y1 Z1 + ╰╴ ━━━━━━━━ +note: baz + ╭▸ test.rs:4:3 + │ +4 │ X1 Y1 Z1 + │ ━━━━━━━━ + ╰ note: qux + +"#, + ); +} + +#[test] +fn different_note_spanned_9() { + test_harness( + r#" +fn foo() { + X0 Y0 Z0 + X1 Y1 Z1 + X2 Y2 Z2 + X3 Y3 Z3 +} +"#, + vec![SpanLabel { + start: Position { string: "Y0", count: 1 }, + end: Position { string: "Z0", count: 1 }, + label: "`X` is a good letter", + }], + vec![ + (None, "bar"), + (None, "baz"), + ( + Some((Position { string: "X1", count: 1 }, Position { string: "Z1", count: 1 })), + "qux", + ), + ], + r#" +error: foo + --> test.rs:3:6 + | +3 | X0 Y0 Z0 + | ^^^^^ `X` is a good letter + | + = note: bar + = note: baz +note: qux + --> test.rs:4:3 + | +4 | X1 Y1 Z1 + | ^^^^^^^^ + +"#, + r#" +error: foo + ╭▸ test.rs:3:6 + │ +3 │ X0 Y0 Z0 + │ ━━━━━ `X` is a good letter + │ + ├ note: bar + ╰ note: baz +note: qux + ╭▸ test.rs:4:3 + │ +4 │ X1 Y1 Z1 + ╰╴ ━━━━━━━━ + +"#, + ); +} + +#[test] +fn different_note_spanned_10() { + test_harness( + r#" +fn foo() { + X0 Y0 Z0 + X1 Y1 Z1 + X2 Y2 Z2 + X3 Y3 Z3 +} +"#, + vec![SpanLabel { + start: Position { string: "Y0", count: 1 }, + end: Position { string: "Z0", count: 1 }, + label: "`X` is a good letter", + }], + vec![ + ( + Some((Position { string: "X1", count: 1 }, Position { string: "Z1", count: 1 })), + "bar", + ), + (None, "baz"), + (None, "qux"), + ], + r#" +error: foo + --> test.rs:3:6 + | +3 | X0 Y0 Z0 + | ^^^^^ `X` is a good letter + | +note: bar + --> test.rs:4:3 + | +4 | X1 Y1 Z1 + | ^^^^^^^^ + = note: baz + = note: qux + +"#, + r#" +error: foo + ╭▸ test.rs:3:6 + │ +3 │ X0 Y0 Z0 + │ ━━━━━ `X` is a good letter + ╰╴ +note: bar + ╭▸ test.rs:4:3 + │ +4 │ X1 Y1 Z1 + │ ━━━━━━━━ + ├ note: baz + ╰ note: qux + +"#, ); } @@ -436,6 +1347,7 @@ fn foo() { label: "`Z` label", }, ], + vec![], r#" error: foo --> test.rs:3:3 @@ -452,6 +1364,22 @@ error: foo | `X` is a good letter "#, + r#" +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 + +"#, ); } @@ -482,6 +1410,7 @@ fn foo() { label: "`Z` label", }, ], + vec![], r#" error: foo --> test.rs:3:3 @@ -496,6 +1425,20 @@ error: foo | `Z` label "#, + r#" +error: foo + ╭▸ test.rs:3:3 + │ +3 │ ┏ X0 Y0 Z0 +4 │ ┃ X1 Y1 Z1 +5 │ ┃ X2 Y2 Z2 + │ ┃ ╿ + │ ┃ │ + │ ┃ `X` is a good letter + │ ┗━━━━`Y` is a good letter too + ╰╴ `Z` label + +"#, ); } @@ -527,6 +1470,7 @@ fn foo() { label: "`Z`", }, ], + vec![], r#" error: foo --> test.rs:3:6 @@ -545,6 +1489,24 @@ error: foo | |_______- `Z` "#, + r#" +error: foo + ╭▸ test.rs:3:6 + │ +3 │ X0 Y0 Z0 + │ ┏━━━━━━━┛ +4 │ ┃ X1 Y1 Z1 + │ ┃┌────╿─┘ + │ ┗│━━━━┥ + │ │ `X` is a good letter +5 │ │ X2 Y2 Z2 + │ └───│──────┘ `Y` is a good letter too + │ ┌───┘ + │ │ +6 │ │ X3 Y3 Z3 + ╰╴ └───────┘ `Z` + +"#, ); } @@ -571,6 +1533,7 @@ fn foo() { label: "`Y` is a good letter too", }, ], + vec![], r#" error: foo --> test.rs:3:3 @@ -584,6 +1547,19 @@ error: foo | |__________- `Y` is a good letter too "#, + r#" +error: foo + ╭▸ test.rs:3:3 + │ +3 │ ┏ X0 Y0 Z0 +4 │ ┃ X1 Y1 Z1 + │ ┗━━━━┛ `X` is a good letter +5 │ X2 Y2 Z2 + │ ┌──────┘ +6 │ │ X3 Y3 Z3 + ╰╴└──────────┘ `Y` is a good letter too + +"#, ); } @@ -610,6 +1586,7 @@ fn foo() { label: "`Y` is a good letter too", }, ], + vec![], r#" error: foo --> test.rs:3:6 @@ -625,6 +1602,21 @@ error: foo | |__________- `Y` is a good letter too "#, + r#" +error: foo + ╭▸ test.rs:3:6 + │ +3 │ X0 Y0 Z0 + │ ┏━━━━━━━┛ +4 │ ┃ X1 Y1 Z1 + │ ┃┌────╿────┘ + │ ┗│━━━━┥ + │ │ `X` is a good letter +5 │ │ X2 Y2 Z2 +6 │ │ X3 Y3 Z3 + ╰╴ └──────────┘ `Y` is a good letter too + +"#, ); } @@ -653,6 +1645,7 @@ fn foo() { label: "", }, ], + vec![], r#" error: foo --> test.rs:3:7 @@ -661,6 +1654,57 @@ error: foo | ----^^^^-^^-- `a` is a good letter "#, + r#" +error: foo + ╭▸ test.rs:3:7 + │ +3 │ a { b { c } d } + ╰╴ ────━━━━─━━── `a` is a good letter + +"#, + ); +} + +#[test] +fn multiline_notes() { + test_harness( + r#" +fn foo() { + a { b { c } d } +} +"#, + vec![SpanLabel { + start: Position { string: "a", count: 1 }, + end: Position { string: "d", count: 1 }, + label: "`a` is a good letter", + }], + vec![(None, "foo\nbar"), (None, "foo\nbar")], + r#" +error: foo + --> test.rs:3:3 + | +3 | a { b { c } d } + | ^^^^^^^^^^^^^ `a` is a good letter + | + = note: foo + bar + = note: foo + bar + +"#, + r#" +error: foo + ╭▸ test.rs:3:3 + │ +3 │ a { b { c } d } + │ ━━━━━━━━━━━━━ `a` is a good letter + │ + ├ note: foo + │ bar + ╰ note: foo + bar + +"#, ); } @@ -684,6 +1728,7 @@ fn foo() { label: "", }, ], + vec![], r#" error: foo --> test.rs:3:3 @@ -692,6 +1737,14 @@ error: foo | ^^^^-------^^ `a` is a good letter "#, + r#" +error: foo + ╭▸ test.rs:3:3 + │ +3 │ a { b { c } d } + ╰╴ ━━━━───────━━ `a` is a good letter + +"#, ); } @@ -720,6 +1773,7 @@ fn foo() { label: "", }, ], + vec![], r#" error: foo --> test.rs:3:7 @@ -730,6 +1784,16 @@ error: foo | `b` is a good letter "#, + r#" +error: foo + ╭▸ test.rs:3:7 + │ +3 │ a { b { c } d } + │ ────┯━━━─━━── + │ │ + ╰╴ `b` is a good letter + +"#, ); } @@ -753,6 +1817,7 @@ fn foo() { label: "`b` is a good letter", }, ], + vec![], r#" error: foo --> test.rs:3:3 @@ -763,6 +1828,16 @@ error: foo | `b` is a good letter "#, + r#" +error: foo + ╭▸ test.rs:3:3 + │ +3 │ a { b { c } d } + │ ━━━━┬──────━━ + │ │ + ╰╴ `b` is a good letter + +"#, ); } @@ -786,6 +1861,7 @@ fn foo() { label: "", }, ], + vec![], r#" error: foo --> test.rs:3:3 @@ -796,6 +1872,16 @@ error: foo | `a` is a good letter "#, + r#" +error: foo + ╭▸ test.rs:3:3 + │ +3 │ a bc d + │ ┯━━━──── + │ │ + ╰╴ `a` is a good letter + +"#, ); } @@ -819,6 +1905,7 @@ fn foo() { label: "", }, ], + vec![], r#" error: foo --> test.rs:3:3 @@ -827,6 +1914,14 @@ error: foo | ^^^^-------^^ "#, + r#" +error: foo + ╭▸ test.rs:3:3 + │ +3 │ a { b { c } d } + ╰╴ ━━━━───────━━ + +"#, ); } @@ -855,6 +1950,7 @@ fn foo() { label: "", }, ], + vec![], r#" error: foo --> test.rs:3:7 @@ -863,6 +1959,14 @@ error: foo | ----^^^^-^^-- "#, + r#" +error: foo + ╭▸ test.rs:3:7 + │ +3 │ a { b { c } d } + ╰╴ ────━━━━─━━── + +"#, ); } @@ -886,6 +1990,7 @@ fn foo() { label: "`b` is a good letter", }, ], + vec![], r#" error: foo --> test.rs:3:3 @@ -897,6 +2002,17 @@ error: foo | `a` is a good letter "#, + r#" +error: foo + ╭▸ test.rs:3:3 + │ +3 │ a { b { c } d } + │ ┯━━━┬──────━━ + │ │ │ + │ │ `b` is a good letter + ╰╴ `a` is a good letter + +"#, ); } @@ -913,6 +2029,7 @@ fn foo() { end: Position { string: "d", count: 1 }, label: "`a` is a good letter", }], + vec![], r#" error: foo --> test.rs:3:3 @@ -921,6 +2038,14 @@ error: foo | ^^^^^^^^^^^^^ `a` is a good letter "#, + r#" +error: foo + ╭▸ test.rs:3:3 + │ +3 │ a { b { c } d } + ╰╴ ━━━━━━━━━━━━━ `a` is a good letter + +"#, ); } @@ -937,6 +2062,7 @@ fn foo() { end: Position { string: "d", count: 1 }, label: "", }], + vec![], r#" error: foo --> test.rs:3:3 @@ -945,6 +2071,14 @@ error: foo | ^^^^^^^^^^^^^ "#, + r#" +error: foo + ╭▸ test.rs:3:3 + │ +3 │ a { b { c } d } + ╰╴ ━━━━━━━━━━━━━ + +"#, ); } @@ -981,6 +2115,7 @@ fn foo() { label: "`Y` is a good letter too", }, ], + vec![], r#" error: foo --> test.rs:3:6 @@ -1000,6 +2135,25 @@ error: foo | |__________- `Y` is a good letter too "#, + r#" +error: foo + ╭▸ test.rs:3:6 + │ +3 │ X0 Y0 Z0 + │ ┏━━━━━━━┛ +4 │ ┃ X1 Y1 Z1 + │ ┃┌────╿────┘ + │ ┗│━━━━┥ + │ │ `X` is a good letter +5 │ │ 1 +6 │ │ 2 +7 │ │ 3 + ‡ │ +15 │ │ X2 Y2 Z2 +16 │ │ X3 Y3 Z3 + ╰╴ └──────────┘ `Y` is a good letter too + +"#, ); } @@ -1036,6 +2190,7 @@ fn foo() { label: "`Z` is a good letter too", }, ], + vec![], r#" error: foo --> test.rs:3:6 @@ -1058,6 +2213,28 @@ error: foo | |________^ `Y` is a good letter "#, + r#" +error: foo + ╭▸ test.rs:3:6 + │ +3 │ X0 Y0 Z0 + │ ┏━━━━━━━┛ +4 │ ┃ 1 +5 │ ┃ 2 +6 │ ┃ 3 +7 │ ┃ X1 Y1 Z1 + │ ┃┌─────────┘ +8 │ ┃│ 4 +9 │ ┃│ 5 +10 │ ┃│ 6 +11 │ ┃│ X2 Y2 Z2 + │ ┃└──────────┘ `Z` is a good letter too + ‡ ┃ +15 │ ┃ 10 +16 │ ┃ X3 Y3 Z3 + ╰╴┗━━━━━━━━┛ `Y` is a good letter + +"#, ); } |
