Remove old error emitter

This completes the transition to annotate-snippets
This commit is contained in:
bjorn3 2026-01-09 15:27:49 +00:00
parent 838db25382
commit 3ccabc6a8d
13 changed files with 53 additions and 3606 deletions

View file

@ -3865,7 +3865,6 @@ dependencies = [
"rustc_fluent_macro",
"rustc_hashes",
"rustc_index",
"rustc_lexer",
"rustc_lint_defs",
"rustc_macros",
"rustc_serialize",

View file

@ -1534,10 +1534,11 @@ fn report_ice(
using_internal_features: &AtomicBool,
) {
let translator = default_translator();
let emitter = Box::new(rustc_errors::emitter::HumanEmitter::new(
stderr_destination(rustc_errors::ColorConfig::Auto),
translator,
));
let emitter =
Box::new(rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitter::new(
stderr_destination(rustc_errors::ColorConfig::Auto),
translator,
));
let dcx = rustc_errors::DiagCtxt::new(emitter);
let dcx = dcx.handle();

View file

@ -17,7 +17,6 @@ rustc_error_messages = { path = "../rustc_error_messages" }
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_hashes = { path = "../rustc_hashes" }
rustc_index = { path = "../rustc_index" }
rustc_lexer = { path = "../rustc_lexer" }
rustc_lint_defs = { path = "../rustc_lint_defs" }
rustc_macros = { path = "../rustc_macros" }
rustc_serialize = { path = "../rustc_serialize" }

View file

@ -15,10 +15,9 @@ use rustc_span::source_map::Spanned;
use rustc_span::{DUMMY_SP, Span, Symbol};
use tracing::debug;
use crate::snippet::Style;
use crate::{
CodeSuggestion, DiagCtxtHandle, DiagMessage, ErrCode, ErrorGuaranteed, ExplicitBug, Level,
MultiSpan, StashKey, SubdiagMessage, Substitution, SubstitutionPart, SuggestionStyle,
MultiSpan, StashKey, Style, SubdiagMessage, Substitution, SubstitutionPart, SuggestionStyle,
Suggestions,
};

File diff suppressed because it is too large Load diff

View file

@ -51,7 +51,7 @@ pub use diagnostic_impls::{
IndicateAnonymousLifetime, SingleLabelManySpans,
};
pub use emitter::ColorConfig;
use emitter::{ConfusionType, DynEmitter, Emitter, detect_confusion_type, is_different};
use emitter::{DynEmitter, Emitter};
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_data_structures::stable_hasher::StableHasher;
use rustc_data_structures::sync::{DynSend, Lock};
@ -68,8 +68,7 @@ use rustc_macros::{Decodable, Encodable};
pub use rustc_span::ErrorGuaranteed;
pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker, catch_fatal_errors};
use rustc_span::source_map::SourceMap;
use rustc_span::{BytePos, DUMMY_SP, Loc, Span};
pub use snippet::Style;
use rustc_span::{DUMMY_SP, Span};
use tracing::debug;
use crate::emitter::TimingEvent;
@ -87,8 +86,6 @@ pub mod json;
mod lock;
pub mod markdown;
pub mod registry;
mod snippet;
mod styled_buffer;
#[cfg(test)]
mod tests;
pub mod timings;
@ -215,43 +212,6 @@ pub struct TrimmedSubstitutionPart {
pub snippet: String,
}
/// Used to translate between `Span`s and byte positions within a single output line in highlighted
/// code of structured suggestions.
#[derive(Debug, Clone, Copy)]
pub(crate) struct SubstitutionHighlight {
start: usize,
end: usize,
}
impl SubstitutionPart {
/// Try to turn a replacement into an addition when the span that is being
/// overwritten matches either the prefix or suffix of the replacement.
fn trim_trivial_replacements(self, sm: &SourceMap) -> TrimmedSubstitutionPart {
let mut trimmed_part = TrimmedSubstitutionPart {
original_span: self.span,
span: self.span,
snippet: self.snippet,
};
if trimmed_part.snippet.is_empty() {
return trimmed_part;
}
let Ok(snippet) = sm.span_to_snippet(trimmed_part.span) else {
return trimmed_part;
};
if let Some((prefix, substr, suffix)) = as_substr(&snippet, &trimmed_part.snippet) {
trimmed_part.span = Span::new(
trimmed_part.span.lo() + BytePos(prefix as u32),
trimmed_part.span.hi() - BytePos(suffix as u32),
trimmed_part.span.ctxt(),
trimmed_part.span.parent(),
);
trimmed_part.snippet = substr.to_string();
}
trimmed_part
}
}
impl TrimmedSubstitutionPart {
pub fn is_addition(&self, sm: &SourceMap) -> bool {
!self.snippet.is_empty() && !self.replaces_meaningful_content(sm)
@ -303,229 +263,6 @@ fn as_substr<'a>(original: &'a str, suggestion: &'a str) -> Option<(usize, &'a s
}
}
impl CodeSuggestion {
/// Returns the assembled code suggestions, whether they should be shown with an underline
/// and whether the substitution only differs in capitalization.
pub(crate) fn splice_lines(
&self,
sm: &SourceMap,
) -> Vec<(String, Vec<TrimmedSubstitutionPart>, Vec<Vec<SubstitutionHighlight>>, ConfusionType)>
{
// For the `Vec<Vec<SubstitutionHighlight>>` value, the first level of the vector
// corresponds to the output snippet's lines, while the second level corresponds to the
// substrings within that line that should be highlighted.
use rustc_span::{CharPos, Pos};
/// Extracts a substring from the provided `line_opt` based on the specified low and high
/// indices, appends it to the given buffer `buf`, and returns the count of newline
/// characters in the substring for accurate highlighting. If `line_opt` is `None`, a
/// newline character is appended to the buffer, and 0 is returned.
///
/// ## Returns
///
/// The count of newline characters in the extracted substring.
fn push_trailing(
buf: &mut String,
line_opt: Option<&Cow<'_, str>>,
lo: &Loc,
hi_opt: Option<&Loc>,
) -> usize {
let mut line_count = 0;
// Convert `CharPos` to `usize`, as `CharPos` is character offset
// Extract low index and high index
let (lo, hi_opt) = (lo.col.to_usize(), hi_opt.map(|hi| hi.col.to_usize()));
if let Some(line) = line_opt {
if let Some(lo) = line.char_indices().map(|(i, _)| i).nth(lo) {
// Get high index while account for rare unicode and emoji with char_indices
let hi_opt = hi_opt.and_then(|hi| line.char_indices().map(|(i, _)| i).nth(hi));
match hi_opt {
// If high index exist, take string from low to high index
Some(hi) if hi > lo => {
// count how many '\n' exist
line_count = line[lo..hi].matches('\n').count();
buf.push_str(&line[lo..hi])
}
Some(_) => (),
// If high index absence, take string from low index till end string.len
None => {
// count how many '\n' exist
line_count = line[lo..].matches('\n').count();
buf.push_str(&line[lo..])
}
}
}
// If high index is None
if hi_opt.is_none() {
buf.push('\n');
}
}
line_count
}
assert!(!self.substitutions.is_empty());
self.substitutions
.iter()
.filter(|subst| {
// Suggestions coming from macros can have malformed spans. This is a heavy
// handed approach to avoid ICEs by ignoring the suggestion outright.
let invalid = subst.parts.iter().any(|item| sm.is_valid_span(item.span).is_err());
if invalid {
debug!("splice_lines: suggestion contains an invalid span: {:?}", subst);
}
!invalid
})
.cloned()
.filter_map(|mut substitution| {
// Assumption: all spans are in the same file, and all spans
// are disjoint. Sort in ascending order.
substitution.parts.sort_by_key(|part| part.span.lo());
// Find the bounding span.
let lo = substitution.parts.iter().map(|part| part.span.lo()).min()?;
let hi = substitution.parts.iter().map(|part| part.span.hi()).max()?;
let bounding_span = Span::with_root_ctxt(lo, hi);
// The different spans might belong to different contexts, if so ignore suggestion.
let lines = sm.span_to_lines(bounding_span).ok()?;
assert!(!lines.lines.is_empty() || bounding_span.is_dummy());
// We can't splice anything if the source is unavailable.
if !sm.ensure_source_file_source_present(&lines.file) {
return None;
}
let mut highlights = vec![];
// To build up the result, we do this for each span:
// - push the line segment trailing the previous span
// (at the beginning a "phantom" span pointing at the start of the line)
// - push lines between the previous and current span (if any)
// - if the previous and current span are not on the same line
// push the line segment leading up to the current span
// - splice in the span substitution
//
// Finally push the trailing line segment of the last span
let sf = &lines.file;
let mut prev_hi = sm.lookup_char_pos(bounding_span.lo());
prev_hi.col = CharPos::from_usize(0);
let mut prev_line =
lines.lines.get(0).and_then(|line0| sf.get_line(line0.line_index));
let mut buf = String::new();
let mut line_highlight = vec![];
// We need to keep track of the difference between the existing code and the added
// or deleted code in order to point at the correct column *after* substitution.
let mut acc = 0;
let mut confusion_type = ConfusionType::None;
let trimmed_parts = substitution
.parts
.into_iter()
// If this is a replacement of, e.g. `"a"` into `"ab"`, adjust the
// suggestion and snippet to look as if we just suggested to add
// `"b"`, which is typically much easier for the user to understand.
.map(|part| part.trim_trivial_replacements(sm))
.collect::<Vec<_>>();
for part in &trimmed_parts {
let part_confusion = detect_confusion_type(sm, &part.snippet, part.span);
confusion_type = confusion_type.combine(part_confusion);
let cur_lo = sm.lookup_char_pos(part.span.lo());
if prev_hi.line == cur_lo.line {
let mut count =
push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, Some(&cur_lo));
while count > 0 {
highlights.push(std::mem::take(&mut line_highlight));
acc = 0;
count -= 1;
}
} else {
acc = 0;
highlights.push(std::mem::take(&mut line_highlight));
let mut count = push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
while count > 0 {
highlights.push(std::mem::take(&mut line_highlight));
count -= 1;
}
// push lines between the previous and current span (if any)
for idx in prev_hi.line..(cur_lo.line - 1) {
if let Some(line) = sf.get_line(idx) {
buf.push_str(line.as_ref());
buf.push('\n');
highlights.push(std::mem::take(&mut line_highlight));
}
}
if let Some(cur_line) = sf.get_line(cur_lo.line - 1) {
let end = match cur_line.char_indices().nth(cur_lo.col.to_usize()) {
Some((i, _)) => i,
None => cur_line.len(),
};
buf.push_str(&cur_line[..end]);
}
}
// Add a whole line highlight per line in the snippet.
let len: isize = part
.snippet
.split('\n')
.next()
.unwrap_or(&part.snippet)
.chars()
.map(|c| match c {
'\t' => 4,
_ => 1,
})
.sum();
if !is_different(sm, &part.snippet, part.span) {
// Account for cases where we are suggesting the same code that's already
// there. This shouldn't happen often, but in some cases for multipart
// suggestions it's much easier to handle it here than in the origin.
} else {
line_highlight.push(SubstitutionHighlight {
start: (cur_lo.col.0 as isize + acc) as usize,
end: (cur_lo.col.0 as isize + acc + len) as usize,
});
}
buf.push_str(&part.snippet);
let cur_hi = sm.lookup_char_pos(part.span.hi());
// Account for the difference between the width of the current code and the
// snippet being suggested, so that the *later* suggestions are correctly
// aligned on the screen. Note that cur_hi and cur_lo can be on different
// lines, so cur_hi.col can be smaller than cur_lo.col
acc += len - (cur_hi.col.0 as isize - cur_lo.col.0 as isize);
prev_hi = cur_hi;
prev_line = sf.get_line(prev_hi.line - 1);
for line in part.snippet.split('\n').skip(1) {
acc = 0;
highlights.push(std::mem::take(&mut line_highlight));
let end: usize = line
.chars()
.map(|c| match c {
'\t' => 4,
_ => 1,
})
.sum();
line_highlight.push(SubstitutionHighlight { start: 0, end });
}
}
highlights.push(std::mem::take(&mut line_highlight));
// if the replacement already ends with a newline, don't print the next line
if !buf.ends_with('\n') {
push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
}
// remove trailing newlines
while buf.ends_with('\n') {
buf.pop();
}
if highlights.iter().all(|parts| parts.is_empty()) {
None
} else {
Some((buf, trimmed_parts, highlights, confusion_type))
}
})
.collect()
}
}
/// Signifies that the compiler died with an explicit call to `.bug`
/// or `.span_bug` rather than a failed assertion, etc.
pub struct ExplicitBug;
@ -1961,15 +1698,6 @@ impl Level {
pub fn is_failure_note(&self) -> bool {
matches!(*self, FailureNote)
}
// Can this level be used in a subdiagnostic message?
fn can_be_subdiag(&self) -> bool {
match self {
Bug | DelayedBug | Fatal | Error | ForceWarning | FailureNote | Allow | Expect => false,
Warning | Note | Help | OnceNote | OnceHelp => true,
}
}
}
impl IntoDiagArg for Level {
@ -1978,6 +1706,24 @@ impl IntoDiagArg for Level {
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
pub enum Style {
MainHeaderMsg,
HeaderMsg,
LineAndColumn,
LineNumber,
Quotation,
UnderlinePrimary,
UnderlineSecondary,
LabelPrimary,
LabelSecondary,
NoStyle,
Level(Level),
Highlight,
Addition,
Removal,
}
// FIXME(eddyb) this doesn't belong here AFAICT, should be moved to callsite.
pub fn elided_lifetime_in_path_suggestion(
source_map: &SourceMap,

View file

@ -1,214 +0,0 @@
// Code for annotating snippets.
use rustc_macros::{Decodable, Encodable};
use crate::{Level, Loc};
#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub(crate) struct Line {
pub line_index: usize,
pub annotations: Vec<Annotation>,
}
#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Default)]
pub(crate) struct AnnotationColumn {
/// the (0-indexed) column for *display* purposes, counted in characters, not utf-8 bytes
pub display: usize,
/// the (0-indexed) column in the file, counted in characters, not utf-8 bytes.
///
/// this may be different from `self.display`,
/// e.g. if the file contains hard tabs, because we convert tabs to spaces for error messages.
///
/// for example:
/// ```text
/// (hard tab)hello
/// ^ this is display column 4, but file column 1
/// ```
///
/// we want to keep around the correct file offset so that column numbers in error messages
/// are correct. (motivated by <https://github.com/rust-lang/rust/issues/109537>)
pub file: usize,
}
impl AnnotationColumn {
pub(crate) fn from_loc(loc: &Loc) -> AnnotationColumn {
AnnotationColumn { display: loc.col_display, file: loc.col.0 }
}
}
#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub(crate) struct MultilineAnnotation {
pub depth: usize,
pub line_start: usize,
pub line_end: usize,
pub start_col: AnnotationColumn,
pub end_col: AnnotationColumn,
pub is_primary: bool,
pub label: Option<String>,
pub overlaps_exactly: bool,
}
impl MultilineAnnotation {
pub(crate) fn increase_depth(&mut self) {
self.depth += 1;
}
/// Compare two `MultilineAnnotation`s considering only the `Span` they cover.
pub(crate) fn same_span(&self, other: &MultilineAnnotation) -> bool {
self.line_start == other.line_start
&& self.line_end == other.line_end
&& self.start_col == other.start_col
&& self.end_col == other.end_col
}
pub(crate) fn as_start(&self) -> Annotation {
Annotation {
start_col: self.start_col,
end_col: AnnotationColumn {
// these might not correspond to the same place anymore,
// but that's okay for our purposes
display: self.start_col.display + 1,
file: self.start_col.file + 1,
},
is_primary: self.is_primary,
label: None,
annotation_type: AnnotationType::MultilineStart(self.depth),
}
}
pub(crate) fn as_end(&self) -> Annotation {
Annotation {
start_col: AnnotationColumn {
// these might not correspond to the same place anymore,
// but that's okay for our purposes
display: self.end_col.display.saturating_sub(1),
file: self.end_col.file.saturating_sub(1),
},
end_col: self.end_col,
is_primary: self.is_primary,
label: self.label.clone(),
annotation_type: AnnotationType::MultilineEnd(self.depth),
}
}
pub(crate) fn as_line(&self) -> Annotation {
Annotation {
start_col: Default::default(),
end_col: Default::default(),
is_primary: self.is_primary,
label: None,
annotation_type: AnnotationType::MultilineLine(self.depth),
}
}
}
#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub(crate) enum AnnotationType {
/// Annotation under a single line of code
Singleline,
// The Multiline type above is replaced with the following three in order
// to reuse the current label drawing code.
//
// Each of these corresponds to one part of the following diagram:
//
// x | foo(1 + bar(x,
// | _________^ < MultilineStart
// x | | y), < MultilineLine
// | |______________^ label < MultilineEnd
// x | z);
/// Annotation marking the first character of a fully shown multiline span
MultilineStart(usize),
/// Annotation marking the last character of a fully shown multiline span
MultilineEnd(usize),
/// Line at the left enclosing the lines of a fully shown multiline span
// Just a placeholder for the drawing algorithm, to know that it shouldn't skip the first 4
// and last 2 lines of code. The actual line is drawn in `emit_message_default` and not in
// `draw_multiline_line`.
MultilineLine(usize),
}
#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub(crate) struct Annotation {
/// Start column.
/// Note that it is important that this field goes
/// first, so that when we sort, we sort orderings by start
/// column.
pub start_col: AnnotationColumn,
/// End column within the line (exclusive)
pub end_col: AnnotationColumn,
/// Is this annotation derived from primary span
pub is_primary: bool,
/// Optional label to display adjacent to the annotation.
pub label: Option<String>,
/// Is this a single line, multiline or multiline span minimized down to a
/// smaller span.
pub annotation_type: AnnotationType,
}
impl Annotation {
/// Whether this annotation is a vertical line placeholder.
pub(crate) fn is_line(&self) -> bool {
matches!(self.annotation_type, AnnotationType::MultilineLine(_))
}
/// Length of this annotation as displayed in the stderr output
pub(crate) fn len(&self) -> usize {
// Account for usize underflows
self.end_col.display.abs_diff(self.start_col.display)
}
pub(crate) fn has_label(&self) -> bool {
if let Some(ref label) = self.label {
// Consider labels with no text as effectively not being there
// to avoid weird output with unnecessary vertical lines, like:
//
// X | fn foo(x: u32) {
// | -------^------
// | | |
// | |
// |
//
// Note that this would be the complete output users would see.
!label.is_empty()
} else {
false
}
}
pub(crate) fn takes_space(&self) -> bool {
// Multiline annotations always have to keep vertical space.
matches!(
self.annotation_type,
AnnotationType::MultilineStart(_) | AnnotationType::MultilineEnd(_)
)
}
}
#[derive(Debug)]
pub(crate) struct StyledString {
pub text: String,
pub style: Style,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
pub enum Style {
MainHeaderMsg,
HeaderMsg,
LineAndColumn,
LineNumber,
Quotation,
UnderlinePrimary,
UnderlineSecondary,
LabelPrimary,
LabelSecondary,
NoStyle,
Level(Level),
Highlight,
Addition,
Removal,
}

View file

@ -1,163 +0,0 @@
// Code for creating styled buffers
use crate::snippet::{Style, StyledString};
#[derive(Debug)]
pub(crate) struct StyledBuffer {
lines: Vec<Vec<StyledChar>>,
}
#[derive(Debug, Clone)]
struct StyledChar {
chr: char,
style: Style,
}
impl StyledChar {
const SPACE: Self = StyledChar::new(' ', Style::NoStyle);
const fn new(chr: char, style: Style) -> Self {
StyledChar { chr, style }
}
}
impl StyledBuffer {
pub(crate) fn new() -> StyledBuffer {
StyledBuffer { lines: vec![] }
}
/// Returns content of `StyledBuffer` split by lines and line styles
pub(crate) fn render(&self) -> Vec<Vec<StyledString>> {
// Tabs are assumed to have been replaced by spaces in calling code.
debug_assert!(self.lines.iter().all(|r| !r.iter().any(|sc| sc.chr == '\t')));
let mut output: Vec<Vec<StyledString>> = vec![];
let mut styled_vec: Vec<StyledString> = vec![];
for styled_line in &self.lines {
let mut current_style = Style::NoStyle;
let mut current_text = String::new();
for sc in styled_line {
if sc.style != current_style {
if !current_text.is_empty() {
styled_vec.push(StyledString { text: current_text, style: current_style });
}
current_style = sc.style;
current_text = String::new();
}
current_text.push(sc.chr);
}
if !current_text.is_empty() {
styled_vec.push(StyledString { text: current_text, style: current_style });
}
// We're done with the row, push and keep going
output.push(styled_vec);
styled_vec = vec![];
}
output
}
fn ensure_lines(&mut self, line: usize) {
if line >= self.lines.len() {
self.lines.resize(line + 1, Vec::new());
}
}
/// Sets `chr` with `style` for given `line`, `col`.
/// If `line` does not exist in our buffer, adds empty lines up to the given
/// and fills the last line with unstyled whitespace.
pub(crate) fn putc(&mut self, line: usize, col: usize, chr: char, style: Style) {
self.ensure_lines(line);
if col >= self.lines[line].len() {
self.lines[line].resize(col + 1, StyledChar::SPACE);
}
self.lines[line][col] = StyledChar::new(chr, style);
}
/// Sets `string` with `style` for given `line`, starting from `col`.
/// If `line` does not exist in our buffer, adds empty lines up to the given
/// and fills the last line with unstyled whitespace.
pub(crate) fn puts(&mut self, line: usize, col: usize, string: &str, style: Style) {
let mut n = col;
for c in string.chars() {
self.putc(line, n, c, style);
n += 1;
}
}
pub(crate) fn replace(&mut self, line: usize, start: usize, end: usize, string: &str) {
if start == end {
return;
}
if start > self.lines[line].len() || end > self.lines[line].len() {
return;
}
let _ = self.lines[line].drain(start..(end - string.chars().count()));
for (i, c) in string.chars().enumerate() {
self.lines[line][start + i] = StyledChar::new(c, Style::LineNumber);
}
}
/// For given `line` inserts `string` with `style` before old content of that line,
/// adding lines if needed
pub(crate) fn prepend(&mut self, line: usize, string: &str, style: Style) {
self.ensure_lines(line);
let string_len = string.chars().count();
if !self.lines[line].is_empty() {
// Push the old content over to make room for new content
for _ in 0..string_len {
self.lines[line].insert(0, StyledChar::SPACE);
}
}
self.puts(line, 0, string, style);
}
/// For given `line` inserts `string` with `style` after old content of that line,
/// adding lines if needed
pub(crate) fn append(&mut self, line: usize, string: &str, style: Style) {
if line >= self.lines.len() {
self.puts(line, 0, string, style);
} else {
let col = self.lines[line].len();
self.puts(line, col, string, style);
}
}
pub(crate) fn num_lines(&self) -> usize {
self.lines.len()
}
/// Set `style` for `line`, `col_start..col_end` range if:
/// 1. That line and column range exist in `StyledBuffer`
/// 2. `overwrite` is `true` or existing style is `Style::NoStyle` or `Style::Quotation`
pub(crate) fn set_style_range(
&mut self,
line: usize,
col_start: usize,
col_end: usize,
style: Style,
overwrite: bool,
) {
for col in col_start..col_end {
self.set_style(line, col, style, overwrite);
}
}
/// Set `style` for `line`, `col` if:
/// 1. That line and column exist in `StyledBuffer`
/// 2. `overwrite` is `true` or existing style is `Style::NoStyle` or `Style::Quotation`
fn set_style(&mut self, line: usize, col: usize, style: Style, overwrite: bool) {
if let Some(ref mut line) = self.lines.get_mut(line)
&& let Some(StyledChar { style: s, .. }) = line.get_mut(col)
&& (overwrite || matches!(s, Style::NoStyle | Style::Quotation))
{
*s = style;
}
}
}

View file

@ -7,8 +7,7 @@ pub use rustc_error_messages::{FluentArgs, LazyFallbackBundle};
use tracing::{debug, trace};
use crate::error::{TranslateError, TranslateErrorKind};
use crate::snippet::Style;
use crate::{DiagArg, DiagMessage, FluentBundle};
use crate::{DiagArg, DiagMessage, FluentBundle, Style};
/// Convert diagnostic arguments (a rustc internal type that exists to implement
/// `Encodable`/`Decodable`) into `FluentArgs` which is necessary to perform translation.

View file

@ -12,7 +12,7 @@ use rustc_ast::{self as ast, PatKind, visit};
use rustc_ast_pretty::pprust::item_to_string;
use rustc_data_structures::assert_matches;
use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitter;
use rustc_errors::emitter::{HumanEmitter, OutputTheme};
use rustc_errors::emitter::OutputTheme;
use rustc_errors::translation::Translator;
use rustc_errors::{AutoStream, DiagCtxt, MultiSpan, PResult};
use rustc_session::parse::ParseSess;
@ -49,20 +49,12 @@ fn create_test_handler(theme: OutputTheme) -> (DiagCtxt, Arc<SourceMap>, Arc<Mut
let translator = Translator::with_fallback_bundle(vec![crate::DEFAULT_LOCALE_RESOURCE], false);
let shared: Box<dyn Write + Send> = Box::new(Shared { data: output.clone() });
let auto_stream = AutoStream::never(shared);
let dcx = DiagCtxt::new(match theme {
OutputTheme::Ascii => Box::new(
HumanEmitter::new(auto_stream, translator)
.sm(Some(source_map.clone()))
.diagnostic_width(Some(140))
.theme(theme),
),
OutputTheme::Unicode => Box::new(
AnnotateSnippetEmitter::new(auto_stream, translator)
.sm(Some(source_map.clone()))
.diagnostic_width(Some(140))
.theme(theme),
),
});
let dcx = DiagCtxt::new(Box::new(
AnnotateSnippetEmitter::new(auto_stream, translator)
.sm(Some(source_map.clone()))
.diagnostic_width(Some(140))
.theme(theme),
));
(dcx, source_map, output)
}

View file

@ -8,7 +8,8 @@ use rustc_ast::attr::AttrIdGenerator;
use rustc_ast::node_id::NodeId;
use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
use rustc_data_structures::sync::{AppendOnlyVec, Lock};
use rustc_errors::emitter::{EmitterWithNote, HumanEmitter, stderr_destination};
use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitter;
use rustc_errors::emitter::{EmitterWithNote, stderr_destination};
use rustc_errors::translation::Translator;
use rustc_errors::{
BufferedEarlyLint, ColorConfig, DecorateDiagCompat, Diag, DiagCtxt, DiagCtxtHandle,
@ -283,7 +284,7 @@ impl ParseSess {
let translator = Translator::with_fallback_bundle(locale_resources, false);
let sm = Arc::new(SourceMap::new(FilePathMapping::empty()));
let emitter = Box::new(
HumanEmitter::new(stderr_destination(ColorConfig::Auto), translator)
AnnotateSnippetEmitter::new(stderr_destination(ColorConfig::Auto), translator)
.sm(Some(Arc::clone(&sm))),
);
let dcx = DiagCtxt::new(emitter);
@ -315,8 +316,10 @@ impl ParseSess {
pub fn emitter_with_note(locale_resources: Vec<&'static str>, note: String) -> Self {
let translator = Translator::with_fallback_bundle(locale_resources, false);
let sm = Arc::new(SourceMap::new(FilePathMapping::empty()));
let emitter =
Box::new(HumanEmitter::new(stderr_destination(ColorConfig::Auto), translator));
let emitter = Box::new(AnnotateSnippetEmitter::new(
stderr_destination(ColorConfig::Auto),
translator,
));
let dcx = DiagCtxt::new(Box::new(EmitterWithNote { emitter, note }));
ParseSess::with_dcx(dcx, sm)
}

View file

@ -456,7 +456,7 @@ fn parse_source(
span: Span,
) -> Result<ParseSourceInfo, ()> {
use rustc_errors::DiagCtxt;
use rustc_errors::emitter::HumanEmitter;
use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitter;
use rustc_span::source_map::FilePathMapping;
let mut info =
@ -476,7 +476,7 @@ fn parse_source(
info.supports_color = supports_color;
// Any errors in parsing should also appear when the doctest is compiled for real, so just
// send all the errors that the parser emits directly into a `Sink` instead of stderr.
let emitter = HumanEmitter::new(AutoStream::never(Box::new(io::sink())), translator);
let emitter = AnnotateSnippetEmitter::new(AutoStream::never(Box::new(io::sink())), translator);
// FIXME(misdreavus): pass `-Z treat-err-as-bug` to the doctest parser
let dcx = DiagCtxt::new(Box::new(emitter)).disable_warnings();

View file

@ -3,7 +3,8 @@ use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use rustc_data_structures::sync::IntoDynSyncSend;
use rustc_errors::emitter::{DynEmitter, Emitter, HumanEmitter, SilentEmitter, stderr_destination};
use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitter;
use rustc_errors::emitter::{DynEmitter, Emitter, SilentEmitter, stderr_destination};
use rustc_errors::registry::Registry;
use rustc_errors::translation::Translator;
use rustc_errors::{ColorConfig, Diag, DiagCtxt, DiagInner, Level as DiagnosticLevel};
@ -108,7 +109,7 @@ fn default_dcx(
let emitter: Box<DynEmitter> = if show_parse_errors {
Box::new(
HumanEmitter::new(stderr_destination(emit_color), translator)
AnnotateSnippetEmitter::new(stderr_destination(emit_color), translator)
.sm(Some(source_map.clone())),
)
} else {