From 5363f350887b1e5b5dd21a86f88c8af9d7fea6da Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:18:25 +0200 Subject: Merging upstream version 1.67.1+dfsg1. Signed-off-by: Daniel Baumann --- compiler/rustc_errors/src/emitter.rs | 196 ++++++++++++++++++++++++----------- 1 file changed, 135 insertions(+), 61 deletions(-) (limited to 'compiler/rustc_errors/src/emitter.rs') diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index cd6413bc3..4df2198fb 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -16,20 +16,20 @@ use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, Styl use crate::styled_buffer::StyledBuffer; use crate::translation::{to_fluent_args, Translate}; use crate::{ - CodeSuggestion, Diagnostic, DiagnosticId, DiagnosticMessage, FluentBundle, Handler, - LazyFallbackBundle, Level, MultiSpan, SubDiagnostic, SubstitutionHighlight, SuggestionStyle, + diagnostic::DiagnosticLocation, CodeSuggestion, Diagnostic, DiagnosticId, DiagnosticMessage, + FluentBundle, Handler, LazyFallbackBundle, Level, MultiSpan, SubDiagnostic, + SubstitutionHighlight, SuggestionStyle, }; - use rustc_lint_defs::pluralize; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_data_structures::sync::Lrc; -use rustc_error_messages::FluentArgs; +use rustc_error_messages::{FluentArgs, SpanLabel}; use rustc_span::hygiene::{ExpnKind, MacroKind}; use std::borrow::Cow; use std::cmp::{max, min, Reverse}; -use std::io; use std::io::prelude::*; +use std::io::{self, IsTerminal}; use std::iter; use std::path::Path; use termcolor::{Ansi, BufferWriter, ColorChoice, ColorSpec, StandardStream}; @@ -64,6 +64,7 @@ impl HumanReadableErrorType { teach: bool, diagnostic_width: Option, macro_backtrace: bool, + track_diagnostics: bool, ) -> EmitterWriter { let (short, color_config) = self.unzip(); let color = color_config.suggests_using_colors(); @@ -77,6 +78,7 @@ impl HumanReadableErrorType { color, diagnostic_width, macro_backtrace, + track_diagnostics, ) } } @@ -246,7 +248,7 @@ pub trait Emitter: Translate { fluent_args: &FluentArgs<'_>, ) -> (MultiSpan, &'a [CodeSuggestion]) { let mut primary_span = diag.span.clone(); - let suggestions = diag.suggestions.as_ref().map_or(&[][..], |suggestions| &suggestions[..]); + let suggestions = diag.suggestions.as_deref().unwrap_or(&[]); if let Some((sugg, rest)) = suggestions.split_first() { let msg = self.translate_message(&sugg.msg, fluent_args); if rest.is_empty() && @@ -281,7 +283,7 @@ pub trait Emitter: Translate { if self .source_map() .map(|sm| is_case_difference( - &**sm, + sm, substitution, sugg.substitutions[0].parts[0].span, )) @@ -312,7 +314,6 @@ pub trait Emitter: Translate { fn fix_multispans_in_extern_macros_and_render_macro_backtrace( &self, - source_map: &Option>, span: &mut MultiSpan, children: &mut Vec, level: &Level, @@ -338,7 +339,7 @@ pub trait Emitter: Translate { .collect(); if !backtrace { - self.fix_multispans_in_extern_macros(source_map, span, children); + self.fix_multispans_in_extern_macros(span, children); } self.render_multispans_macro_backtrace(span, children, backtrace); @@ -478,15 +479,13 @@ pub trait Emitter: Translate { // this will change the span to point at the use site. fn fix_multispans_in_extern_macros( &self, - source_map: &Option>, span: &mut MultiSpan, children: &mut Vec, ) { - let Some(source_map) = source_map else { return }; debug!("fix_multispans_in_extern_macros: before: span={:?} children={:?}", span, children); - self.fix_multispan_in_extern_macros(source_map, span); + self.fix_multispan_in_extern_macros(span); for child in children.iter_mut() { - self.fix_multispan_in_extern_macros(source_map, &mut child.span); + self.fix_multispan_in_extern_macros(&mut child.span); } debug!("fix_multispans_in_extern_macros: after: span={:?} children={:?}", span, children); } @@ -494,7 +493,8 @@ pub trait Emitter: Translate { // This "fixes" MultiSpans that contain `Span`s pointing to locations inside of external macros. // Since these locations are often difficult to read, // we move these spans from the external macros to their corresponding use site. - fn fix_multispan_in_extern_macros(&self, source_map: &Lrc, span: &mut MultiSpan) { + fn fix_multispan_in_extern_macros(&self, span: &mut MultiSpan) { + let Some(source_map) = self.source_map() else { return }; // First, find all the spans in external macros and point instead at their use site. let replacements: Vec<(Span, Span)> = span .primary_spans() @@ -525,7 +525,7 @@ impl Translate for EmitterWriter { } fn fallback_fluent_bundle(&self) -> &FluentBundle { - &**self.fallback_bundle + &self.fallback_bundle } } @@ -538,11 +538,10 @@ impl Emitter for EmitterWriter { let fluent_args = to_fluent_args(diag.args()); let mut children = diag.children.clone(); - let (mut primary_span, suggestions) = self.primary_span_formatted(&diag, &fluent_args); + let (mut primary_span, suggestions) = self.primary_span_formatted(diag, &fluent_args); debug!("emit_diagnostic: suggestions={:?}", suggestions); self.fix_multispans_in_extern_macros_and_render_macro_backtrace( - &self.sm, &mut primary_span, &mut children, &diag.level, @@ -556,7 +555,8 @@ impl Emitter for EmitterWriter { &diag.code, &primary_span, &children, - &suggestions, + suggestions, + self.track_diagnostics.then_some(&diag.emitted_at), ); } @@ -619,14 +619,14 @@ impl ColorConfig { fn to_color_choice(self) -> ColorChoice { match self { ColorConfig::Always => { - if atty::is(atty::Stream::Stderr) { + if io::stderr().is_terminal() { ColorChoice::Always } else { ColorChoice::AlwaysAnsi } } ColorConfig::Never => ColorChoice::Never, - ColorConfig::Auto if atty::is(atty::Stream::Stderr) => ColorChoice::Auto, + ColorConfig::Auto if io::stderr().is_terminal() => ColorChoice::Auto, ColorConfig::Auto => ColorChoice::Never, } } @@ -650,6 +650,7 @@ pub struct EmitterWriter { diagnostic_width: Option, macro_backtrace: bool, + track_diagnostics: bool, } #[derive(Debug)] @@ -669,6 +670,7 @@ impl EmitterWriter { teach: bool, diagnostic_width: Option, macro_backtrace: bool, + track_diagnostics: bool, ) -> EmitterWriter { let dst = Destination::from_stderr(color_config); EmitterWriter { @@ -681,6 +683,7 @@ impl EmitterWriter { ui_testing: false, diagnostic_width, macro_backtrace, + track_diagnostics, } } @@ -694,6 +697,7 @@ impl EmitterWriter { colored: bool, diagnostic_width: Option, macro_backtrace: bool, + track_diagnostics: bool, ) -> EmitterWriter { EmitterWriter { dst: Raw(dst, colored), @@ -705,6 +709,7 @@ impl EmitterWriter { ui_testing: false, diagnostic_width, macro_backtrace, + track_diagnostics, } } @@ -768,6 +773,7 @@ impl EmitterWriter { draw_col_separator_no_space(buffer, line_offset, width_offset - 2); } + #[instrument(level = "trace", skip(self), ret)] fn render_source_line( &self, buffer: &mut StyledBuffer, @@ -796,9 +802,10 @@ impl EmitterWriter { } let source_string = match file.get_line(line.line_index - 1) { - Some(s) => normalize_whitespace(&*s), + Some(s) => normalize_whitespace(&s), None => return Vec::new(), }; + trace!(?source_string); let line_offset = buffer.num_lines(); @@ -1143,7 +1150,7 @@ impl EmitterWriter { (pos + 2, annotation.start_col.saturating_sub(left)) }; 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); } } @@ -1318,6 +1325,7 @@ impl EmitterWriter { } } + #[instrument(level = "trace", skip(self, args), ret)] fn emit_message_default( &mut self, msp: &MultiSpan, @@ -1327,6 +1335,7 @@ impl EmitterWriter { level: &Level, max_line_num_len: usize, is_secondary: bool, + emitted_at: Option<&DiagnosticLocation>, ) -> io::Result<()> { let mut buffer = StyledBuffer::new(); @@ -1352,7 +1361,7 @@ impl EmitterWriter { // only render error codes, not lint codes if let Some(DiagnosticId::Error(ref code)) = *code { buffer.append(0, "[", Style::Level(*level)); - buffer.append(0, &code, Style::Level(*level)); + buffer.append(0, code, Style::Level(*level)); buffer.append(0, "]", Style::Level(*level)); label_width += 2 + code.len(); } @@ -1377,24 +1386,16 @@ impl EmitterWriter { } } } - let mut annotated_files = FileWithAnnotatedLines::collect_annotations(self, args, msp); + trace!("{annotated_files:#?}"); // Make sure our primary file comes first - let (primary_lo, sm) = if let (Some(sm), Some(ref primary_span)) = - (self.sm.as_ref(), msp.primary_span().as_ref()) - { - if !primary_span.is_dummy() { - (sm.lookup_char_pos(primary_span.lo()), sm) - } else { - emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message)?; - return Ok(()); - } - } else { + let primary_span = msp.primary_span().unwrap_or_default(); + let (Some(sm), false) = (self.sm.as_ref(), primary_span.is_dummy()) else { // If we don't have span information, emit and exit - emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message)?; - return Ok(()); + return emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message); }; + let primary_lo = sm.lookup_char_pos(primary_span.lo()); if let Ok(pos) = annotated_files.binary_search_by(|x| x.file.name.cmp(&primary_lo.file.name)) { @@ -1405,6 +1406,54 @@ impl EmitterWriter { for annotated_file in annotated_files { // we can't annotate anything if the source is unavailable. if !sm.ensure_source_file_source_present(annotated_file.file.clone()) { + if !self.short_message { + // We'll just print an unannotated message. + for (annotation_id, line) in annotated_file.lines.into_iter().enumerate() { + let mut annotations = line.annotations.clone(); + annotations.sort_by_key(|a| Reverse(a.start_col)); + let mut line_idx = buffer.num_lines(); + buffer.append( + line_idx, + &format!( + "{}:{}:{}", + sm.filename_for_diagnostics(&annotated_file.file.name), + sm.doctest_offset_line(&annotated_file.file.name, line.line_index), + annotations[0].start_col + 1, + ), + Style::LineAndColumn, + ); + if annotation_id == 0 { + buffer.prepend(line_idx, "--> ", Style::LineNumber); + for _ in 0..max_line_num_len { + buffer.prepend(line_idx, " ", Style::NoStyle); + } + line_idx += 1; + }; + for (i, annotation) in annotations.into_iter().enumerate() { + if let Some(label) = &annotation.label { + let style = if annotation.is_primary { + Style::LabelPrimary + } else { + Style::LabelSecondary + }; + if annotation_id == 0 { + buffer.prepend(line_idx, " |", Style::LineNumber); + for _ in 0..max_line_num_len { + buffer.prepend(line_idx, " ", Style::NoStyle); + } + line_idx += 1; + buffer.append(line_idx + i, " = note: ", style); + for _ in 0..max_line_num_len { + buffer.prepend(line_idx, " ", Style::NoStyle); + } + } else { + buffer.append(line_idx + i, ": ", style); + } + buffer.append(line_idx + i, label, style); + } + } + } + } continue; } @@ -1651,6 +1700,13 @@ impl EmitterWriter { multilines.extend(&to_add); } } + trace!("buffer: {:#?}", buffer.render()); + } + + if let Some(tracked) = emitted_at { + let track = format!("-Ztrack-diagnostics: created at {tracked}"); + let len = buffer.num_lines(); + buffer.append(len, &track, Style::NoStyle); } // final step: take our styled buffer, render it, then output it @@ -1672,7 +1728,7 @@ impl EmitterWriter { }; // Render the replacements for each suggestion - let suggestions = suggestion.splice_lines(&**sm); + let suggestions = suggestion.splice_lines(sm); debug!("emit_suggestion_default: suggestions={:?}", suggestions); if suggestions.is_empty() { @@ -1773,7 +1829,7 @@ impl EmitterWriter { buffer.puts( row_num - 1 + line - line_start, max_line_num_len + 3, - &normalize_whitespace(&*file_lines.file.get_line(line - 1).unwrap()), + &normalize_whitespace(&file_lines.file.get_line(line - 1).unwrap()), Style::Removal, ); } @@ -1915,7 +1971,7 @@ impl EmitterWriter { buffer.putc( row_num, (padding as isize + p) as usize, - if part.is_addition(&sm) { '+' } else { '~' }, + if part.is_addition(sm) { '+' } else { '~' }, Style::Addition, ); } @@ -1962,12 +2018,13 @@ impl EmitterWriter { buffer.puts(row_num, max_line_num_len + 3, &msg, Style::NoStyle); } else if notice_capitalization { let msg = "notice the capitalization difference"; - buffer.puts(row_num, max_line_num_len + 3, &msg, Style::NoStyle); + buffer.puts(row_num, max_line_num_len + 3, msg, Style::NoStyle); } emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message)?; Ok(()) } + #[instrument(level = "trace", skip(self, args, code, children, suggestions))] fn emit_messages_default( &mut self, level: &Level, @@ -1977,6 +2034,7 @@ impl EmitterWriter { span: &MultiSpan, children: &[SubDiagnostic], suggestions: &[CodeSuggestion], + emitted_at: Option<&DiagnosticLocation>, ) { let max_line_num_len = if self.ui_testing { ANONYMIZED_LINE_NUM.len() @@ -1985,7 +2043,16 @@ impl EmitterWriter { num_decimal_digits(n) }; - match self.emit_message_default(span, message, args, code, level, max_line_num_len, false) { + match self.emit_message_default( + span, + message, + args, + code, + level, + max_line_num_len, + false, + emitted_at, + ) { Ok(()) => { if !children.is_empty() || suggestions.iter().any(|s| s.style != SuggestionStyle::CompletelyHidden) @@ -2007,13 +2074,14 @@ impl EmitterWriter { for child in children { let span = child.render_span.as_ref().unwrap_or(&child.span); if let Err(err) = self.emit_message_default( - &span, + span, &child.message, args, &None, &child.level, max_line_num_len, true, + None, ) { panic!("failed to emit error: {}", err); } @@ -2030,6 +2098,7 @@ impl EmitterWriter { &Level::Help, max_line_num_len, true, + None, ) { panic!("failed to emit error: {}", e); } @@ -2090,7 +2159,7 @@ impl EmitterWriter { *row_num - 1, max_line_num_len + 3, &normalize_whitespace( - &*file_lines.file.get_line(file_lines.lines[line_pos].line_index).unwrap(), + &file_lines.file.get_line(file_lines.lines[line_pos].line_index).unwrap(), ), Style::NoStyle, ); @@ -2186,13 +2255,16 @@ impl FileWithAnnotatedLines { let mut multiline_annotations = vec![]; if let Some(ref sm) = emitter.source_map() { - for span_label in msp.span_labels() { - if span_label.span.is_dummy() { - continue; - } + for SpanLabel { span, is_primary, label } in msp.span_labels() { + // If we don't have a useful span, pick the primary span if that exists. + // Worst case we'll just print an error at the top of the main file. + let span = match (span.is_dummy(), msp.primary_span()) { + (_, None) | (false, _) => span, + (true, Some(span)) => span, + }; - let lo = sm.lookup_char_pos(span_label.span.lo()); - let mut hi = sm.lookup_char_pos(span_label.span.hi()); + let lo = sm.lookup_char_pos(span.lo()); + let mut hi = sm.lookup_char_pos(span.hi()); // Watch out for "empty spans". If we get a span like 6..6, we // want to just display a `^` at 6, so convert that to @@ -2204,6 +2276,8 @@ impl FileWithAnnotatedLines { hi.col_display += 1; } + let label = label.as_ref().map(|m| emitter.translate_message(m, args).to_string()); + if lo.line != hi.line { let ml = MultilineAnnotation { depth: 1, @@ -2211,11 +2285,8 @@ impl FileWithAnnotatedLines { line_end: hi.line, start_col: lo.col_display, end_col: hi.col_display, - is_primary: span_label.is_primary, - label: span_label - .label - .as_ref() - .map(|m| emitter.translate_message(m, args).to_string()), + is_primary, + label, overlaps_exactly: false, }; multiline_annotations.push((lo.file, ml)); @@ -2223,11 +2294,8 @@ impl FileWithAnnotatedLines { let ann = Annotation { start_col: lo.col_display, end_col: hi.col_display, - is_primary: span_label.is_primary, - label: span_label - .label - .as_ref() - .map(|m| emitter.translate_message(m, args).to_string()), + is_primary, + label, annotation_type: AnnotationType::Singleline, }; add_annotation_to_file(&mut output, lo.file, lo.line, ann); @@ -2236,7 +2304,7 @@ impl FileWithAnnotatedLines { } // Find overlapping multiline annotations, put them at different depths - multiline_annotations.sort_by_key(|&(_, ref ml)| (ml.line_start, ml.line_end)); + multiline_annotations.sort_by_key(|&(_, ref ml)| (ml.line_start, usize::MAX - ml.line_end)); for (_, ann) in multiline_annotations.clone() { for (_, a) in multiline_annotations.iter_mut() { // Move all other multiline annotations overlapping with this one @@ -2254,8 +2322,14 @@ impl FileWithAnnotatedLines { } let mut max_depth = 0; // max overlapping multiline spans - for (file, ann) in multiline_annotations { + for (_, ann) in &multiline_annotations { max_depth = max(max_depth, ann.depth); + } + // Change order of multispan depth to minimize the number of overlaps in the ASCII art. + for (_, a) in multiline_annotations.iter_mut() { + a.depth = max_depth - a.depth + 1; + } + for (file, ann) in multiline_annotations { let mut end_ann = ann.as_end(); if !ann.overlaps_exactly { // avoid output like -- cgit v1.2.3