diff --git a/Cargo.lock b/Cargo.lock index 06c455b3c910d..16baa7436cb81 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3219,6 +3219,7 @@ dependencies = [ "rustc_data_structures", "serialize", "syntax_pos", + "term_size", "termcolor", "unicode-width", ] @@ -4090,6 +4091,17 @@ dependencies = [ "winapi 0.3.6", ] +[[package]] +name = "term_size" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5b9a66db815dcfd2da92db471106457082577c3c278d4138ab3e3b4e189327" +dependencies = [ + "kernel32-sys", + "libc", + "winapi 0.2.8", +] + [[package]] name = "termcolor" version = "1.0.4" diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 8e3b910e0da3a..89481e9eafde5 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1292,6 +1292,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "show macro backtraces even for non-local macros"), teach: bool = (false, parse_bool, [TRACKED], "show extended diagnostic help"), + terminal_width: Option = (None, parse_opt_uint, [UNTRACKED], + "set the current terminal width"), continue_parse_after_error: bool = (false, parse_bool, [TRACKED], "attempt to recover from parse errors (experimental)"), dep_tasks: bool = (false, parse_bool, [UNTRACKED], diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 61dac678912df..f01883d9634cd 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -1055,6 +1055,7 @@ fn default_emitter( Some(source_map.clone()), short, sopts.debugging_opts.teach, + sopts.debugging_opts.terminal_width, ), Some(dst) => EmitterWriter::new( dst, @@ -1062,6 +1063,7 @@ fn default_emitter( short, false, // no teach messages when writing to a buffer false, // no colors when writing to a buffer + None, // no terminal width ), }; Box::new(emitter.ui_testing(sopts.debugging_opts.ui_testing)) @@ -1375,7 +1377,7 @@ pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! { let emitter: Box = match output { config::ErrorOutputType::HumanReadable(kind) => { let (short, color_config) = kind.unzip(); - Box::new(EmitterWriter::stderr(color_config, None, short, false)) + Box::new(EmitterWriter::stderr(color_config, None, short, false, None)) } config::ErrorOutputType::Json { pretty, json_rendered } => Box::new(JsonEmitter::basic(pretty, json_rendered)), @@ -1389,7 +1391,7 @@ pub fn early_warn(output: config::ErrorOutputType, msg: &str) { let emitter: Box = match output { config::ErrorOutputType::HumanReadable(kind) => { let (short, color_config) = kind.unzip(); - Box::new(EmitterWriter::stderr(color_config, None, short, false)) + Box::new(EmitterWriter::stderr(color_config, None, short, false, None)) } config::ErrorOutputType::Json { pretty, json_rendered } => Box::new(JsonEmitter::basic(pretty, json_rendered)), diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index b19ea513b7575..3d94d51f17ec0 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -1135,11 +1135,13 @@ pub fn report_ices_to_stderr_if_any R, R>(f: F) -> Result, source_map: Option>, teach: bool, + terminal_width: Option, ) -> EmitterWriter { let (short, color_config) = self.unzip(); - EmitterWriter::new(dst, source_map, short, teach, color_config.suggests_using_colors()) + let color = color_config.suggests_using_colors(); + EmitterWriter::new(dst, source_map, short, teach, color, terminal_width) + } +} + +#[derive(Clone, Copy, Debug)] +struct Margin { + /// The available whitespace in the left that can be consumed when centering. + pub whitespace_left: usize, + /// The column of the beginning of left-most span. + pub span_left: usize, + /// The column of the end of right-most span. + pub span_right: usize, + /// The beginning of the line to be displayed. + pub computed_left: usize, + /// The end of the line to be displayed. + pub computed_right: usize, + /// The current width of the terminal. 140 by default and in tests. + pub column_width: usize, + /// The end column of a span label, including the span. Doesn't account for labels not in the + /// same line as the span. + pub label_right: usize, +} + +impl Margin { + fn new( + whitespace_left: usize, + span_left: usize, + span_right: usize, + label_right: usize, + column_width: usize, + max_line_len: usize, + ) -> Self { + // The 6 is padding to give a bit of room for `...` when displaying: + // ``` + // error: message + // --> file.rs:16:58 + // | + // 16 | ... fn foo(self) -> Self::Bar { + // | ^^^^^^^^^ + // ``` + + let mut m = Margin { + whitespace_left: if whitespace_left >= 6 { whitespace_left - 6 } else { 0 }, + span_left: if span_left >= 6 { span_left - 6 } else { 0 }, + span_right: span_right + 6, + computed_left: 0, + computed_right: 0, + column_width, + label_right: label_right + 6, + }; + m.compute(max_line_len); + m + } + + fn was_cut_left(&self) -> bool { + self.computed_left > 0 + } + + fn was_cut_right(&self, line_len: usize) -> bool { + let right = if self.computed_right == self.span_right || + self.computed_right == self.label_right + { + // Account for the "..." padding given above. Otherwise we end up with code lines that + // do fit but end in "..." as if they were trimmed. + self.computed_right - 6 + } else { + self.computed_right + }; + right < line_len && line_len > self.computed_left + self.column_width + } + + fn compute(&mut self, max_line_len: usize) { + // When there's a lot of whitespace (>20), we want to trim it as it is useless. + self.computed_left = if self.whitespace_left > 20 { + self.whitespace_left - 16 // We want some padding. + } else { + 0 + }; + // We want to show as much as possible, max_line_len is the right-most boundary for the + // relevant code. + self.computed_right = max(max_line_len, self.computed_left); + + if self.computed_right - self.computed_left > self.column_width { + // Trimming only whitespace isn't enough, let's get craftier. + if self.label_right - self.whitespace_left <= self.column_width { + // Attempt to fit the code window only trimming whitespace. + self.computed_left = self.whitespace_left; + self.computed_right = self.computed_left + self.column_width; + } else if self.label_right - self.span_left <= self.column_width { + // Attempt to fit the code window considering only the spans and labels. + let padding_left = (self.column_width - (self.label_right - self.span_left)) / 2; + self.computed_left = self.span_left - padding_left; + self.computed_right = self.computed_left + self.column_width; + } else if self.span_right - self.span_left <= self.column_width { + // Attempt to fit the code window considering the spans and labels plus padding. + let padding_left = (self.column_width - (self.span_right - self.span_left)) / 5 * 2; + self.computed_left = self.span_left - padding_left; + self.computed_right = self.computed_left + self.column_width; + } else { // Mostly give up but still don't show the full line. + self.computed_left = self.span_left; + self.computed_right = self.span_right; + } + } + } + + fn left(&self, line_len: usize) -> usize { + min(self.computed_left, line_len) + } + + fn right(&self, line_len: usize) -> usize { + if max(line_len, self.computed_left) - self.computed_left <= self.column_width { + line_len + } else if self.computed_right > line_len { + line_len + } else { + self.computed_right + } } } @@ -180,6 +298,7 @@ pub struct EmitterWriter { short_message: bool, teach: bool, ui_testing: bool, + terminal_width: Option, } #[derive(Debug)] @@ -190,11 +309,13 @@ pub struct FileWithAnnotatedLines { } impl EmitterWriter { - pub fn stderr(color_config: ColorConfig, - source_map: Option>, - short_message: bool, - teach: bool) - -> EmitterWriter { + pub fn stderr( + color_config: ColorConfig, + source_map: Option>, + short_message: bool, + teach: bool, + terminal_width: Option, + ) -> EmitterWriter { let dst = Destination::from_stderr(color_config); EmitterWriter { dst, @@ -202,6 +323,7 @@ impl EmitterWriter { short_message, teach, ui_testing: false, + terminal_width, } } @@ -211,6 +333,7 @@ impl EmitterWriter { short_message: bool, teach: bool, colored: bool, + terminal_width: Option, ) -> EmitterWriter { EmitterWriter { dst: Raw(dst, colored), @@ -218,6 +341,7 @@ impl EmitterWriter { short_message, teach, ui_testing: false, + terminal_width, } } @@ -234,12 +358,70 @@ impl EmitterWriter { } } - fn render_source_line(&self, - buffer: &mut StyledBuffer, - file: Lrc, - line: &Line, - width_offset: usize, - code_offset: usize) -> Vec<(usize, Style)> { + fn draw_line( + &self, + buffer: &mut StyledBuffer, + source_string: &str, + line_index: usize, + line_offset: usize, + width_offset: usize, + code_offset: usize, + margin: Margin, + ) { + let line_len = source_string.len(); + // Create the source line we will highlight. + let left = margin.left(line_len); + let right = margin.right(line_len); + // On long lines, we strip the source line, accounting for unicode. + let mut taken = 0; + let code: String = source_string.chars().skip(left).take_while(|ch| { + // Make sure that the trimming on the right will fall within the terminal width. + // FIXME: `unicode_width` sometimes disagrees with terminals on how wide a `char` is. + // For now, just accept that sometimes the code line will be longer than desired. + let next = unicode_width::UnicodeWidthChar::width(*ch).unwrap_or(1); + if taken + next > right - left { + return false; + } + taken += next; + true + }).collect(); + buffer.puts(line_offset, code_offset, &code, Style::Quotation); + 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); + } + if margin.was_cut_right(line_len) { + // We have stripped some code after the right-most span end, make it clear we did so. + buffer.puts(line_offset, code_offset + taken - 3, "...", Style::LineNumber); + } + buffer.puts(line_offset, 0, &self.maybe_anonymized(line_index), Style::LineNumber); + + draw_col_separator(buffer, line_offset, width_offset - 2); + } + + fn render_source_line( + &self, + buffer: &mut StyledBuffer, + file: Lrc, + line: &Line, + width_offset: usize, + code_offset: usize, + margin: Margin, + ) -> Vec<(usize, Style)> { + // Draw: + // + // LL | ... code ... + // | ^^-^ span label + // | | + // | secondary span label + // + // ^^ ^ ^^^ ^^^^ ^^^ we don't care about code too far to the right of a span, we trim it + // | | | | + // | | | actual code found in your source code and the spans we use to mark it + // | | when there's too much wasted space to the left, trim it + // | vertical divider between the column number and the code + // column number + if line.line_index == 0 { return Vec::new(); } @@ -251,14 +433,21 @@ impl EmitterWriter { let line_offset = buffer.num_lines(); - // First create the source line we will highlight. - buffer.puts(line_offset, code_offset, &source_string, Style::Quotation); - buffer.puts(line_offset, - 0, - &self.maybe_anonymized(line.line_index), - Style::LineNumber); + let left = margin.left(source_string.len()); // Left trim + // Account for unicode characters of width !=0 that were removed. + let left = source_string.chars().take(left).fold(0, |acc, ch| { + acc + unicode_width::UnicodeWidthChar::width(ch).unwrap_or(1) + }); - draw_col_separator(buffer, line_offset, width_offset - 2); + self.draw_line( + buffer, + &source_string, + line.line_index, + line_offset, + width_offset, + code_offset, + margin, + ); // Special case when there's only one annotation involved, it is the start of a multiline // span and there's no text at the beginning of the code line. Instead of doing the whole @@ -279,18 +468,13 @@ impl EmitterWriter { if line.annotations.len() == 1 { if let Some(ref ann) = line.annotations.get(0) { if let AnnotationType::MultilineStart(depth) = ann.annotation_type { - if source_string.chars() - .take(ann.start_col) - .all(|c| c.is_whitespace()) { + if source_string.chars().take(ann.start_col).all(|c| c.is_whitespace()) { let style = if ann.is_primary { Style::UnderlinePrimary } else { Style::UnderlineSecondary }; - buffer.putc(line_offset, - width_offset + depth - 1, - '/', - style); + buffer.putc(line_offset, width_offset + depth - 1, '/', style); return vec![(depth, style)]; } } @@ -511,19 +695,23 @@ impl EmitterWriter { match annotation.annotation_type { AnnotationType::MultilineStart(depth) | AnnotationType::MultilineEnd(depth) => { - draw_range(buffer, - '_', - line_offset + pos, - width_offset + depth, - code_offset + annotation.start_col, - style); + draw_range( + buffer, + '_', + line_offset + pos, + width_offset + depth, + code_offset + annotation.start_col - left, + style, + ); } _ if self.teach => { - buffer.set_style_range(line_offset, - code_offset + annotation.start_col, - code_offset + annotation.end_col, - style, - annotation.is_primary); + buffer.set_style_range( + line_offset, + code_offset + annotation.start_col - left, + code_offset + annotation.end_col - left, + style, + annotation.is_primary, + ); } _ => {} } @@ -551,7 +739,7 @@ impl EmitterWriter { if pos > 1 && (annotation.has_label() || annotation.takes_space()) { for p in line_offset + 1..=line_offset + pos { buffer.putc(p, - code_offset + annotation.start_col, + code_offset + annotation.start_col - margin.computed_left, '|', style); } @@ -595,15 +783,20 @@ impl EmitterWriter { Style::LabelSecondary }; let (pos, col) = if pos == 0 { - (pos + 1, annotation.end_col + 1) + (pos + 1, if annotation.end_col + 1 > left { + annotation.end_col + 1 - left + } else { + 0 + }) } else { - (pos + 2, annotation.start_col) + (pos + 2, if annotation.start_col > left { + annotation.start_col - left + } else { + 0 + }) }; if let Some(ref label) = annotation.label { - buffer.puts(line_offset + pos, - code_offset + col, - &label, - style); + buffer.puts(line_offset + pos, code_offset + col, &label, style); } } @@ -638,10 +831,16 @@ impl EmitterWriter { ('-', Style::UnderlineSecondary) }; for p in annotation.start_col..annotation.end_col { - buffer.putc(line_offset + 1, - code_offset + p, - underline, - style); + buffer.putc( + line_offset + 1, + if code_offset + p > left { + code_offset + p - left + } else { + 0 + }, + underline, + style, + ); } } annotations_position.iter().filter_map(|&(_, annotation)| { @@ -979,22 +1178,30 @@ impl EmitterWriter { let buffer_msg_line_offset = buffer.num_lines(); buffer.prepend(buffer_msg_line_offset, "--> ", Style::LineNumber); - buffer.append(buffer_msg_line_offset, - &format!("{}:{}:{}", - loc.file.name, - sm.doctest_offset_line(&loc.file.name, loc.line), - loc.col.0 + 1), - Style::LineAndColumn); + buffer.append( + buffer_msg_line_offset, + &format!( + "{}:{}:{}", + loc.file.name, + sm.doctest_offset_line(&loc.file.name, loc.line), + loc.col.0 + 1, + ), + Style::LineAndColumn, + ); for _ in 0..max_line_num_len { buffer.prepend(buffer_msg_line_offset, " ", Style::NoStyle); } } else { - buffer.prepend(0, - &format!("{}:{}:{}: ", - loc.file.name, - sm.doctest_offset_line(&loc.file.name, loc.line), - loc.col.0 + 1), - Style::LineAndColumn); + buffer.prepend( + 0, + &format!( + "{}:{}:{}: ", + loc.file.name, + sm.doctest_offset_line(&loc.file.name, loc.line), + loc.col.0 + 1, + ), + Style::LineAndColumn, + ); } } else if !self.short_message { // remember where we are in the output buffer for easy reference @@ -1037,22 +1244,94 @@ impl EmitterWriter { // Contains the vertical lines' positions for active multiline annotations let mut multilines = FxHashMap::default(); + // Get the left-side margin to remove it + let mut whitespace_margin = std::usize::MAX; + for line_idx in 0..annotated_file.lines.len() { + let file = annotated_file.file.clone(); + let line = &annotated_file.lines[line_idx]; + if let Some(source_string) = file.get_line(line.line_index - 1) { + let leading_whitespace = source_string + .chars() + .take_while(|c| c.is_whitespace()) + .count(); + if source_string.chars().any(|c| !c.is_whitespace()) { + whitespace_margin = min( + whitespace_margin, + leading_whitespace, + ); + } + } + } + if whitespace_margin == std::usize::MAX { + whitespace_margin = 0; + } + + // Left-most column any visible span points at. + let mut span_left_margin = std::usize::MAX; + for line in &annotated_file.lines { + for ann in &line.annotations { + span_left_margin = min(span_left_margin, ann.start_col); + span_left_margin = min(span_left_margin, ann.end_col); + } + } + if span_left_margin == std::usize::MAX { + span_left_margin = 0; + } + + // Right-most column any visible span points at. + let mut span_right_margin = 0; + let mut label_right_margin = 0; + let mut max_line_len = 0; + for line in &annotated_file.lines { + max_line_len = max(max_line_len, annotated_file.file + .get_line(line.line_index - 1) + .map(|s| s.len()) + .unwrap_or(0)); + for ann in &line.annotations { + span_right_margin = max(span_right_margin, ann.start_col); + span_right_margin = max(span_right_margin, ann.end_col); + // FIXME: account for labels not in the same line + let label_right = ann.label.as_ref().map(|l| l.len() + 1).unwrap_or(0); + label_right_margin = max(label_right_margin, ann.end_col + label_right); + } + } + + let width_offset = 3 + max_line_num_len; + let code_offset = if annotated_file.multiline_depth == 0 { + width_offset + } else { + width_offset + annotated_file.multiline_depth + 1 + }; + + let column_width = if let Some(width) = self.terminal_width { + width + } else if self.ui_testing { + 140 + } else { + term_size::dimensions().map(|(w, _)| w - code_offset).unwrap_or(140) + }; + + let margin = Margin::new( + whitespace_margin, + span_left_margin, + span_right_margin, + label_right_margin, + column_width, + max_line_len, + ); + // Next, output the annotate source for this file for line_idx in 0..annotated_file.lines.len() { let previous_buffer_line = buffer.num_lines(); - let width_offset = 3 + max_line_num_len; - let code_offset = if annotated_file.multiline_depth == 0 { - width_offset - } else { - width_offset + annotated_file.multiline_depth + 1 - }; - - let depths = self.render_source_line(&mut buffer, - annotated_file.file.clone(), - &annotated_file.lines[line_idx], - width_offset, - code_offset); + let depths = self.render_source_line( + &mut buffer, + annotated_file.file.clone(), + &annotated_file.lines[line_idx], + width_offset, + code_offset, + margin, + ); let mut to_add = FxHashMap::default(); @@ -1099,25 +1378,24 @@ impl EmitterWriter { let last_buffer_line_num = buffer.num_lines(); - buffer.puts(last_buffer_line_num, - 0, - &self.maybe_anonymized(annotated_file.lines[line_idx + 1] - .line_index - 1), - Style::LineNumber); - draw_col_separator(&mut buffer, - last_buffer_line_num, - 1 + max_line_num_len); - buffer.puts(last_buffer_line_num, - code_offset, - &unannotated_line, - Style::Quotation); + self.draw_line( + &mut buffer, + &unannotated_line, + annotated_file.lines[line_idx + 1].line_index - 1, + last_buffer_line_num, + width_offset, + code_offset, + margin, + ); for (depth, style) in &multilines { - draw_multiline_line(&mut buffer, - last_buffer_line_num, - width_offset, - *depth, - *style); + draw_multiline_line( + &mut buffer, + last_buffer_line_num, + width_offset, + *depth, + *style, + ); } } } @@ -1207,7 +1485,7 @@ impl EmitterWriter { // ...or trailing spaces. Account for substitutions containing unicode // characters. let sub_len = part.snippet.trim().chars().fold(0, |acc, ch| { - acc + unicode_width::UnicodeWidthChar::width(ch).unwrap_or(0) + acc + unicode_width::UnicodeWidthChar::width(ch).unwrap_or(1) }); let underline_start = (span_start_pos + start) as isize + offset; @@ -1230,7 +1508,7 @@ impl EmitterWriter { // length of the code after substitution let full_sub_len = part.snippet.chars().fold(0, |acc, ch| { - acc + unicode_width::UnicodeWidthChar::width(ch).unwrap_or(0) as isize + acc + unicode_width::UnicodeWidthChar::width(ch).unwrap_or(1) as isize }); // length of the code to be substituted diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 4018a667bf264..6585633e00af8 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -383,7 +383,7 @@ impl Handler { cm: Option>, flags: HandlerFlags) -> Handler { - let emitter = Box::new(EmitterWriter::stderr(color_config, cm, false, false)); + let emitter = Box::new(EmitterWriter::stderr(color_config, cm, false, false, None)); Handler::with_emitter_and_flags(emitter, flags) } diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 87381f224d0bb..98362464771e0 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -193,6 +193,7 @@ pub fn new_handler(error_format: ErrorOutputType, source_map.map(|cm| cm as _), short, sessopts.debugging_opts.teach, + sessopts.debugging_opts.terminal_width, ).ui_testing(ui_testing) ) }, diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 83a8d3fc10999..8db0eb15929dc 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -427,7 +427,7 @@ pub fn make_test(s: &str, // Any errors in parsing should also appear when the doctest is compiled for real, so just // send all the errors that libsyntax emits directly into a `Sink` instead of stderr. let cm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let emitter = EmitterWriter::new(box io::sink(), None, false, false, false); + let emitter = EmitterWriter::new(box io::sink(), None, false, false, false, None); // FIXME(misdreavus): pass `-Z treat-err-as-bug` to the doctest parser let handler = Handler::with_emitter(false, None, box emitter); let sess = ParseSess::with_span_handler(handler, cm); diff --git a/src/libsyntax/json.rs b/src/libsyntax/json.rs index 83c9c692bd30c..ada46f7bc5a74 100644 --- a/src/libsyntax/json.rs +++ b/src/libsyntax/json.rs @@ -219,7 +219,7 @@ impl Diagnostic { } let buf = BufWriter::default(); let output = buf.clone(); - je.json_rendered.new_emitter(Box::new(buf), Some(je.sm.clone()), false) + je.json_rendered.new_emitter(Box::new(buf), Some(je.sm.clone()), false, None) .ui_testing(je.ui_testing).emit_diagnostic(db); let output = Arc::try_unwrap(output.0).unwrap().into_inner().unwrap(); let output = String::from_utf8(output).unwrap(); diff --git a/src/libsyntax/parse/lexer/tests.rs b/src/libsyntax/parse/lexer/tests.rs index a915aa42fd15a..652ae95c85349 100644 --- a/src/libsyntax/parse/lexer/tests.rs +++ b/src/libsyntax/parse/lexer/tests.rs @@ -10,7 +10,14 @@ use errors::{Handler, emitter::EmitterWriter}; use syntax_pos::{BytePos, Span}; fn mk_sess(sm: Lrc) -> ParseSess { - let emitter = EmitterWriter::new(Box::new(io::sink()), Some(sm.clone()), false, false, false); + let emitter = EmitterWriter::new( + Box::new(io::sink()), + Some(sm.clone()), + false, + false, + false, + None, + ); ParseSess::with_span_handler(Handler::with_emitter(true, None, Box::new(emitter)), sm) } @@ -28,10 +35,11 @@ fn t1() { with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); - let mut string_reader = setup(&sm, - &sh, - "/* my source file */ fn main() { println!(\"zebra\"); }\n" - .to_string()); + let mut string_reader = setup( + &sm, + &sh, + "/* my source file */ fn main() { println!(\"zebra\"); }\n".to_string(), + ); assert_eq!(string_reader.next_token(), token::Comment); assert_eq!(string_reader.next_token(), token::Whitespace); let tok1 = string_reader.next_token(); @@ -127,8 +135,10 @@ fn character_a() { with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); - assert_eq!(setup(&sm, &sh, "'a'".to_string()).next_token(), - mk_lit(token::Char, "a", None)); + assert_eq!( + setup(&sm, &sh, "'a'".to_string()).next_token(), + mk_lit(token::Char, "a", None), + ); }) } @@ -137,8 +147,10 @@ fn character_space() { with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); - assert_eq!(setup(&sm, &sh, "' '".to_string()).next_token(), - mk_lit(token::Char, " ", None)); + assert_eq!( + setup(&sm, &sh, "' '".to_string()).next_token(), + mk_lit(token::Char, " ", None), + ); }) } @@ -147,8 +159,10 @@ fn character_escaped() { with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); - assert_eq!(setup(&sm, &sh, "'\\n'".to_string()).next_token(), - mk_lit(token::Char, "\\n", None)); + assert_eq!( + setup(&sm, &sh, "'\\n'".to_string()).next_token(), + mk_lit(token::Char, "\\n", None), + ); }) } @@ -157,8 +171,10 @@ fn lifetime_name() { with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); - assert_eq!(setup(&sm, &sh, "'abc".to_string()).next_token(), - token::Lifetime(Symbol::intern("'abc"))); + assert_eq!( + setup(&sm, &sh, "'abc".to_string()).next_token(), + token::Lifetime(Symbol::intern("'abc")), + ); }) } @@ -167,8 +183,10 @@ fn raw_string() { with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); - assert_eq!(setup(&sm, &sh, "r###\"\"#a\\b\x00c\"\"###".to_string()).next_token(), - mk_lit(token::StrRaw(3), "\"#a\\b\x00c\"", None)); + assert_eq!( + setup(&sm, &sh, "r###\"\"#a\\b\x00c\"\"###".to_string()).next_token(), + mk_lit(token::StrRaw(3), "\"#a\\b\x00c\"", None), + ); }) } @@ -179,11 +197,15 @@ fn literal_suffixes() { let sh = mk_sess(sm.clone()); macro_rules! test { ($input: expr, $tok_type: ident, $tok_contents: expr) => {{ - assert_eq!(setup(&sm, &sh, format!("{}suffix", $input)).next_token(), - mk_lit(token::$tok_type, $tok_contents, Some("suffix"))); + assert_eq!( + setup(&sm, &sh, format!("{}suffix", $input)).next_token(), + mk_lit(token::$tok_type, $tok_contents, Some("suffix")), + ); // with a whitespace separator: - assert_eq!(setup(&sm, &sh, format!("{} suffix", $input)).next_token(), - mk_lit(token::$tok_type, $tok_contents, None)); + assert_eq!( + setup(&sm, &sh, format!("{} suffix", $input)).next_token(), + mk_lit(token::$tok_type, $tok_contents, None), + ); }} } @@ -197,12 +219,18 @@ fn literal_suffixes() { test!("1.0", Float, "1.0"); test!("1.0e10", Float, "1.0e10"); - assert_eq!(setup(&sm, &sh, "2us".to_string()).next_token(), - mk_lit(token::Integer, "2", Some("us"))); - assert_eq!(setup(&sm, &sh, "r###\"raw\"###suffix".to_string()).next_token(), - mk_lit(token::StrRaw(3), "raw", Some("suffix"))); - assert_eq!(setup(&sm, &sh, "br###\"raw\"###suffix".to_string()).next_token(), - mk_lit(token::ByteStrRaw(3), "raw", Some("suffix"))); + assert_eq!( + setup(&sm, &sh, "2us".to_string()).next_token(), + mk_lit(token::Integer, "2", Some("us")), + ); + assert_eq!( + setup(&sm, &sh, "r###\"raw\"###suffix".to_string()).next_token(), + mk_lit(token::StrRaw(3), "raw", Some("suffix")), + ); + assert_eq!( + setup(&sm, &sh, "br###\"raw\"###suffix".to_string()).next_token(), + mk_lit(token::ByteStrRaw(3), "raw", Some("suffix")), + ); }) } diff --git a/src/libsyntax/tests.rs b/src/libsyntax/tests.rs index 4c0e1e3704dff..c472212bc2096 100644 --- a/src/libsyntax/tests.rs +++ b/src/libsyntax/tests.rs @@ -144,11 +144,14 @@ fn test_harness(file_text: &str, span_labels: Vec, expected_output: & println!("text: {:?}", source_map.span_to_snippet(span)); } - let emitter = EmitterWriter::new(Box::new(Shared { data: output.clone() }), - Some(source_map.clone()), - false, - false, - false); + let emitter = EmitterWriter::new( + Box::new(Shared { data: output.clone() }), + Some(source_map.clone()), + false, + false, + false, + None, + ); let handler = Handler::with_emitter(true, None, Box::new(emitter)); handler.span_err(msp, "foo"); diff --git a/src/test/ui/inline-asm-bad-operand.stderr b/src/test/ui/inline-asm-bad-operand.stderr index 4554da7b798ea..55523bad6c507 100644 --- a/src/test/ui/inline-asm-bad-operand.stderr +++ b/src/test/ui/inline-asm-bad-operand.stderr @@ -37,8 +37,8 @@ LL | asm!("mov sp, $0"::"r"(addr), error[E0669]: invalid value for constraint in inline assembly --> $DIR/inline-asm-bad-operand.rs:56:32 | -LL | "r"("hello e0669")); - | ^^^^^^^^^^^^^ +LL | ... "r"("hello e0669")); + | ^^^^^^^^^^^^^ error: aborting due to 7 previous errors diff --git a/src/test/ui/lint/lint-stability-deprecated.stderr b/src/test/ui/lint/lint-stability-deprecated.stderr index 8132a66df8a0f..62380135b333b 100644 --- a/src/test/ui/lint/lint-stability-deprecated.stderr +++ b/src/test/ui/lint/lint-stability-deprecated.stderr @@ -67,14 +67,14 @@ LL | deprecated_unstable_text(); warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text --> $DIR/lint-stability-deprecated.rs:57:9 | -LL | Trait::trait_deprecated_unstable_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | ... Trait::trait_deprecated_unstable_text(&foo); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text --> $DIR/lint-stability-deprecated.rs:59:9 | -LL | ::trait_deprecated_unstable_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | ... ::trait_deprecated_unstable_text(&foo); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::DeprecatedStruct': text --> $DIR/lint-stability-deprecated.rs:106:17 @@ -181,14 +181,14 @@ LL | ::trait_deprecated_unstable(&foo); warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text --> $DIR/lint-stability-deprecated.rs:155:9 | -LL | Trait::trait_deprecated_unstable_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | ... Trait::trait_deprecated_unstable_text(&foo); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text --> $DIR/lint-stability-deprecated.rs:157:9 | -LL | ::trait_deprecated_unstable_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | ... ::trait_deprecated_unstable_text(&foo); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::DeprecatedTrait': text --> $DIR/lint-stability-deprecated.rs:185:10 @@ -421,20 +421,20 @@ LL | ::trait_deprecated_unstable(&foo); warning: use of deprecated item 'lint_stability::MethodTester::method_deprecated_unstable_text': text --> $DIR/lint-stability-deprecated.rs:53:13 | -LL | foo.method_deprecated_unstable_text(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | ... foo.method_deprecated_unstable_text(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::MethodTester::method_deprecated_unstable_text': text --> $DIR/lint-stability-deprecated.rs:54:9 | -LL | Foo::method_deprecated_unstable_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | ... Foo::method_deprecated_unstable_text(&foo); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::MethodTester::method_deprecated_unstable_text': text --> $DIR/lint-stability-deprecated.rs:55:9 | -LL | ::method_deprecated_unstable_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | ... ::method_deprecated_unstable_text(&foo); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text --> $DIR/lint-stability-deprecated.rs:56:13 @@ -445,8 +445,8 @@ LL | foo.trait_deprecated_unstable_text(); warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text --> $DIR/lint-stability-deprecated.rs:58:9 | -LL | ::trait_deprecated_unstable_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | ... ::trait_deprecated_unstable_text(&foo); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::DeprecatedStruct::i': text --> $DIR/lint-stability-deprecated.rs:107:13 @@ -505,8 +505,8 @@ LL | foo.trait_deprecated_unstable_text(); warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text --> $DIR/lint-stability-deprecated.rs:156:9 | -LL | ::trait_deprecated_unstable_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | ... ::trait_deprecated_unstable_text(&foo); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated': text --> $DIR/lint-stability-deprecated.rs:173:13 diff --git a/src/test/ui/regions/regions-name-undeclared.stderr b/src/test/ui/regions/regions-name-undeclared.stderr index 4840d751f7f57..5f6a48a35f368 100644 --- a/src/test/ui/regions/regions-name-undeclared.stderr +++ b/src/test/ui/regions/regions-name-undeclared.stderr @@ -49,14 +49,14 @@ LL | fn fn_types(a: &'a isize, error[E0261]: use of undeclared lifetime name `'b` --> $DIR/regions-name-undeclared.rs:42:36 | -LL | &'b isize, - | ^^ undeclared lifetime +LL | ... &'b isize, + | ^^ undeclared lifetime error[E0261]: use of undeclared lifetime name `'b` --> $DIR/regions-name-undeclared.rs:45:36 | -LL | &'b isize)>, - | ^^ undeclared lifetime +LL | ... &'b isize)>, + | ^^ undeclared lifetime error[E0261]: use of undeclared lifetime name `'a` --> $DIR/regions-name-undeclared.rs:46:17 diff --git a/src/test/ui/terminal-width/non-whitespace-trimming-2.rs b/src/test/ui/terminal-width/non-whitespace-trimming-2.rs new file mode 100644 index 0000000000000..abd9e189a7537 --- /dev/null +++ b/src/test/ui/terminal-width/non-whitespace-trimming-2.rs @@ -0,0 +1,6 @@ +// 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 +} diff --git a/src/test/ui/terminal-width/non-whitespace-trimming-2.stderr b/src/test/ui/terminal-width/non-whitespace-trimming-2.stderr new file mode 100644 index 0000000000000..bf1699f5cabbb --- /dev/null +++ b/src/test/ui/terminal-width/non-whitespace-trimming-2.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/non-whitespace-trimming-2.rs:4:311 + | +LL | ...; let _: usize = 14; let _: usize = 15; let _: () = 42; let _: usize = 0; let _: usize = 1; let _: usize = 2; let _: usize = 3; let _:... + | ^^ expected (), found integer + | + = note: expected type `()` + found type `{integer}` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/terminal-width/non-whitespace-trimming-unicode.rs b/src/test/ui/terminal-width/non-whitespace-trimming-unicode.rs new file mode 100644 index 0000000000000..8d4d1b1627940 --- /dev/null +++ b/src/test/ui/terminal-width/non-whitespace-trimming-unicode.rs @@ -0,0 +1,6 @@ +// ignore-tidy-linelength + +fn main() { + let _: &str = "🦀☀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓ ☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼☽☾☿♀♁♂♃♄♅♆♇♏♔♕♖♗♘♙♚♛♜♝♞♟♠♡♢♣♤♥♦♧♨♩♪♫♬♭♮♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚈⚉4🦀☀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼☽☾☿♀♁♂♃♄♅♆♇♏♔♕♖♗♘♙♚♛♜♝♞♟♠♡♢♣♤♥♦♧♨♩♪♫♬♭♮♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚈⚉4🦀🦀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼☽☾☿♀♁♂♃♄♅♆♇♏♔♕♖♗♘♙♚♛♜♝♞♟♠♡♢♣♤♥♦♧♨♩♪♫♬♭♮♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚈⚉4"; let _: () = 42; let _: &str = "🦀☀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓ ☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼☽☾☿♀♁♂♃♄♅♆♇♏♔♕♖♗♘♙♚♛♜♝♞♟♠♡♢♣♤♥♦♧♨♩♪♫♬♭♮♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚈⚉4🦀☀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼☽☾☿♀♁♂♃♄♅♆♇♏♔♕♖♗♘♙♚♛♜♝♞♟♠♡♢♣♤♥♦♧♨♩♪♫♬♭♮♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚈⚉4🦀🦀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼☽☾☿♀♁♂♃♄♅♆♇♏♔♕♖♗♘♙♚♛♜♝♞♟♠♡♢♣♤♥♦♧♨♩♪♫♬♭♮♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚈⚉4"; +//~^ ERROR mismatched types +} diff --git a/src/test/ui/terminal-width/non-whitespace-trimming-unicode.stderr b/src/test/ui/terminal-width/non-whitespace-trimming-unicode.stderr new file mode 100644 index 0000000000000..b56b1948d9e07 --- /dev/null +++ b/src/test/ui/terminal-width/non-whitespace-trimming-unicode.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/non-whitespace-trimming-unicode.rs:4:415 + | +LL | ...♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚈⚉4"; let _: () = 42; let _: &str = "🦀☀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓ ☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼☽☾☿♀♁♂♃♄♅♆... + | ^^ expected (), found integer + | + = note: expected type `()` + found type `{integer}` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/terminal-width/non-whitespace-trimming.rs b/src/test/ui/terminal-width/non-whitespace-trimming.rs new file mode 100644 index 0000000000000..f6c8d345c652e --- /dev/null +++ b/src/test/ui/terminal-width/non-whitespace-trimming.rs @@ -0,0 +1,6 @@ +// ignore-tidy-linelength + +fn main() { + let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = 42; let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); +//~^ ERROR mismatched types +} diff --git a/src/test/ui/terminal-width/non-whitespace-trimming.stderr b/src/test/ui/terminal-width/non-whitespace-trimming.stderr new file mode 100644 index 0000000000000..622713eb5f6fc --- /dev/null +++ b/src/test/ui/terminal-width/non-whitespace-trimming.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/non-whitespace-trimming.rs:4:241 + | +LL | ...) = (); let _: () = (); let _: () = (); let _: () = 42; let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = ()... + | ^^ expected (), found integer + | + = note: expected type `()` + found type `{integer}` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/terminal-width/whitespace-trimming-2.rs b/src/test/ui/terminal-width/whitespace-trimming-2.rs new file mode 100644 index 0000000000000..c68f678aab349 --- /dev/null +++ b/src/test/ui/terminal-width/whitespace-trimming-2.rs @@ -0,0 +1,8 @@ +// ignore-tidy-linelength + +fn foo() -> usize { + () +//~^ ERROR mismatched types +} + +fn main() {} diff --git a/src/test/ui/terminal-width/whitespace-trimming-2.stderr b/src/test/ui/terminal-width/whitespace-trimming-2.stderr new file mode 100644 index 0000000000000..38df5a9e9a01f --- /dev/null +++ b/src/test/ui/terminal-width/whitespace-trimming-2.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/whitespace-trimming-2.rs:4:187 + | +LL | ...-> usize { + | ----- expected `usize` because of return type +LL | ... () + | ^^ expected usize, found () + | + = note: expected type `usize` + found type `()` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/terminal-width/whitespace-trimming.rs b/src/test/ui/terminal-width/whitespace-trimming.rs new file mode 100644 index 0000000000000..f747bcf17e0b4 --- /dev/null +++ b/src/test/ui/terminal-width/whitespace-trimming.rs @@ -0,0 +1,6 @@ +// ignore-tidy-linelength + +fn main() { + let _: () = 42; +//~^ ERROR mismatched types +} diff --git a/src/test/ui/terminal-width/whitespace-trimming.stderr b/src/test/ui/terminal-width/whitespace-trimming.stderr new file mode 100644 index 0000000000000..45a804b9f6a46 --- /dev/null +++ b/src/test/ui/terminal-width/whitespace-trimming.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/whitespace-trimming.rs:4:193 + | +LL | ... let _: () = 42; + | ^^ expected (), found integer + | + = note: expected type `()` + found type `{integer}` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index de54eb8f57312..92f60b2ddab73 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -159,6 +159,7 @@ const WHITELIST: &[Crate<'_>] = &[ Crate("termcolor"), Crate("terminon"), Crate("termion"), + Crate("term_size"), Crate("thread_local"), Crate("ucd-util"), Crate("unicode-width"),