1use std::borrow::Cow;
11use std::io::prelude::*;
12use std::io::{self, IsTerminal};
13use std::iter;
14use std::path::Path;
15
16use anstream::{AutoStream, ColorChoice};
17use anstyle::{AnsiColor, Effects};
18use rustc_data_structures::fx::FxIndexSet;
19use rustc_data_structures::sync::DynSend;
20use rustc_error_messages::DiagArgMap;
21use rustc_span::hygiene::{ExpnKind, MacroKind};
22use rustc_span::source_map::SourceMap;
23use rustc_span::{FileName, SourceFile, Span};
24use tracing::{debug, warn};
25
26use crate::formatting::format_diag_message;
27use crate::timings::TimingRecord;
28use crate::{
29 CodeSuggestion, DiagInner, DiagMessage, Level, MultiSpan, Style, Subdiag, Sublevel,
30 SuggestionStyle,
31};
32
33#[derive(#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for HumanReadableErrorType { }
#[automatically_derived]
impl ::core::clone::Clone for HumanReadableErrorType {
#[inline]
fn clone(&self) -> Self {
let _: ::core::clone::AssertParamIsClone<bool>;
*self
}
}Clone, #[automatically_derived]
impl ::core::marker::Copy for HumanReadableErrorType { }Copy, #[automatically_derived]
impl ::core::fmt::Debug for HumanReadableErrorType {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f,
"HumanReadableErrorType", "short", &self.short, "unicode",
&&self.unicode)
}
}Debug, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for HumanReadableErrorType { }
#[automatically_derived]
impl ::core::cmp::PartialEq for HumanReadableErrorType {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.short == other.short && self.unicode == other.unicode
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for HumanReadableErrorType {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<bool>;
}
}Eq)]
35pub struct HumanReadableErrorType {
36 pub short: bool,
37 pub unicode: bool,
38}
39
40impl HumanReadableErrorType {
41 pub fn short(&self) -> bool {
42 self.short
43 }
44}
45
46pub enum TimingEvent {
47 Start,
48 End,
49}
50
51pub type DynEmitter = dyn Emitter + DynSend;
52
53pub trait Emitter {
55 fn emit_diagnostic(&mut self, diag: DiagInner);
57
58 fn emit_artifact_notification(&mut self, _path: &Path, _artifact_type: &str) {}
61
62 fn emit_timing_section(&mut self, _record: TimingRecord, _event: TimingEvent) {}
65
66 fn emit_future_breakage_report(&mut self, _diags: Vec<DiagInner>) {}
69
70 fn emit_unused_externs(
73 &mut self,
74 _lint_level: rustc_lint_defs::Level,
75 _unused_externs: &[&str],
76 ) {
77 }
78
79 fn should_show_explain(&self) -> bool {
81 true
82 }
83
84 fn supports_color(&self) -> bool {
86 false
87 }
88
89 fn source_map(&self) -> Option<&SourceMap>;
90
91 fn primary_span_formatted(
103 &self,
104 primary_span: &mut MultiSpan,
105 suggestions: &mut Vec<CodeSuggestion>,
106 fluent_args: &DiagArgMap,
107 ) {
108 if let Some((sugg, rest)) = suggestions.split_first() {
109 let msg = format_diag_message(&sugg.msg, fluent_args);
110 if rest.is_empty()
111 && let [substitution] = sugg.substitutions.as_slice()
114 && let [part] = substitution.parts.as_slice()
116 && msg.split_whitespace().count() < 10
118 && !part.snippet.contains('\n')
120 && ![
121 SuggestionStyle::HideCodeAlways,
123 SuggestionStyle::CompletelyHidden,
125 SuggestionStyle::ShowAlways,
127 ].contains(&sugg.style)
128 {
129 let snippet = part.snippet.trim();
130 let msg = if snippet.is_empty() || sugg.style.hide_inline() {
131 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("help: {0}", msg))
})format!("help: {msg}")
134 } else {
135 let confusion_type = self
137 .source_map()
138 .map(|sm| detect_confusion_type(sm, snippet, part.span))
139 .unwrap_or(ConfusionType::None);
140 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("help: {0}{1}: `{2}`", msg,
confusion_type.label_text(), snippet))
})format!("help: {}{}: `{}`", msg, confusion_type.label_text(), snippet,)
141 };
142 primary_span.push_span_label(part.span, msg);
143
144 suggestions.clear();
146 } else {
147 }
152 } else {
153 }
155 }
156
157 fn fix_multispans_in_extern_macros_and_render_macro_backtrace(
158 &self,
159 span: &mut MultiSpan,
160 children: &mut Vec<Subdiag>,
161 level: &Level,
162 backtrace: bool,
163 ) {
164 let has_macro_spans: Vec<_> = iter::once(&*span)
167 .chain(children.iter().map(|child| &child.span))
168 .flat_map(|span| span.primary_spans())
169 .flat_map(|sp| sp.macro_backtrace().map(move |expn_data| (sp, expn_data)))
170 .filter_map(|(sp, expn_data)| {
171 match expn_data.kind {
172 ExpnKind::Root => None,
173
174 ExpnKind::Desugaring(..) | ExpnKind::AstPass(..) => None,
177
178 ExpnKind::Macro(macro_kind, name) => {
179 let same_line = sp
180 .overlaps(expn_data.def_site)
181 .then(|| expn_data.def_site.with_hi(sp.lo()));
182 Some((
183 macro_kind,
184 name,
185 expn_data.diagnostic_opaque,
186 expn_data.def_site,
187 same_line,
188 ))
189 }
190 }
191 })
192 .collect();
193
194 if !backtrace {
195 self.fix_multispans_in_extern_macros(span, children);
196 }
197
198 self.render_multispans_macro_backtrace(span, children, backtrace);
199
200 if !backtrace
201 && let Some((macro_kind, name, _, sp, same_line_span)) = has_macro_spans.first()
203 && let Some((_, _, false, _, _)) = has_macro_spans.last()
204 {
205 let and_then = if let Some((macro_kind, last_name, _, _, _)) = has_macro_spans.last()
207 && last_name != name
208 {
209 let descr = macro_kind.descr();
210 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!(" which comes from the expansion of the {0} `{1}`",
descr, last_name))
})format!(" which comes from the expansion of the {descr} `{last_name}`")
211 } else {
212 "".to_string()
213 };
214
215 let descr = macro_kind.descr();
216 let msg = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("this {0} originates in the {1} `{2}`{3}",
level, descr, name, and_then))
})format!("this {level} originates in the {descr} `{name}`{and_then}");
217
218 if let Some(source_map) = self.source_map() {
219 if source_map.is_imported(*sp) || same_line_span.is_none() {
220 let msg = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0} (in Nightly builds, run with -Z macro-backtrace for more info)",
msg))
})format!(
221 "{msg} (in Nightly builds, run with -Z macro-backtrace for more info)"
222 );
223 children.push(Subdiag {
224 level: Sublevel::Note,
225 messages: ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[(DiagMessage::from(msg), Style::NoStyle)]))vec![(DiagMessage::from(msg), Style::NoStyle)],
226 span: MultiSpan::new(),
227 });
228 } else if let Some(def) = same_line_span
229 && source_map.is_multiline(*def)
230 && !and_then.is_empty()
231 {
232 span.push_span_label(*sp, msg);
235 } else {
236 span.push_span_context(sp.shrink_to_lo());
239 }
240 } else {
241 children.push(Subdiag {
242 level: Sublevel::Note,
243 messages: ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[(DiagMessage::from(msg), Style::NoStyle)]))vec![(DiagMessage::from(msg), Style::NoStyle)],
244 span: MultiSpan::new(),
245 });
246 }
247 }
248 }
249
250 fn render_multispans_macro_backtrace(
251 &self,
252 span: &mut MultiSpan,
253 children: &mut Vec<Subdiag>,
254 backtrace: bool,
255 ) {
256 for span in iter::once(span).chain(children.iter_mut().map(|child| &mut child.span)) {
257 self.render_multispan_macro_backtrace(span, backtrace);
258 }
259 }
260
261 fn render_multispan_macro_backtrace(&self, span: &mut MultiSpan, always_backtrace: bool) {
262 let mut new_labels = FxIndexSet::default();
263
264 for &sp in span.primary_spans() {
265 if sp.is_dummy() {
266 continue;
267 }
268
269 let macro_backtrace: Vec<_> = sp.macro_backtrace().collect();
273 for (i, trace) in macro_backtrace.iter().rev().enumerate() {
274 if trace.def_site.is_dummy() {
275 continue;
276 }
277
278 if always_backtrace {
279 new_labels.insert((
280 trace.def_site,
281 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("in this expansion of `{0}`{1}",
trace.kind.descr(),
if macro_backtrace.len() > 1 {
::alloc::__export::must_use({
::alloc::fmt::format(format_args!(" (#{0})", i + 1))
})
} else { String::new() }))
})format!(
282 "in this expansion of `{}`{}",
283 trace.kind.descr(),
284 if macro_backtrace.len() > 1 {
285 format!(" (#{})", i + 1)
288 } else {
289 String::new()
290 },
291 ),
292 ));
293 }
294
295 let redundant_span = trace.call_site.contains(sp);
307
308 if !redundant_span || always_backtrace {
309 let msg: Cow<'static, _> = match trace.kind {
310 ExpnKind::Macro(MacroKind::Attr, _) => {
311 "this attribute macro expansion".into()
312 }
313 ExpnKind::Macro(MacroKind::Derive, _) => {
314 "this derive macro expansion".into()
315 }
316 ExpnKind::Macro(MacroKind::Bang, _) => "this macro invocation".into(),
317 ExpnKind::Root => "the crate root".into(),
318 ExpnKind::AstPass(kind) => kind.descr().into(),
319 ExpnKind::Desugaring(kind) => {
320 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("this {0} desugaring",
kind.descr()))
})format!("this {} desugaring", kind.descr()).into()
321 }
322 };
323 new_labels.insert((
324 trace.call_site,
325 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("in {0}{1}", msg,
if macro_backtrace.len() > 1 && always_backtrace {
::alloc::__export::must_use({
::alloc::fmt::format(format_args!(" (#{0})", i + 1))
})
} else { String::new() }))
})format!(
326 "in {}{}",
327 msg,
328 if macro_backtrace.len() > 1 && always_backtrace {
329 format!(" (#{})", i + 1)
332 } else {
333 String::new()
334 },
335 ),
336 ));
337 }
338 if !always_backtrace {
339 break;
340 }
341 }
342 }
343
344 for (label_span, label_text) in new_labels {
345 span.push_span_label(label_span, label_text);
346 }
347 }
348
349 fn fix_multispans_in_extern_macros(&self, span: &mut MultiSpan, children: &mut Vec<Subdiag>) {
353 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/6bb1652a020e80cef79332741d89e996d71933c9/compiler/rustc_errors/src/emitter.rs:353",
"rustc_errors::emitter", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/6bb1652a020e80cef79332741d89e996d71933c9/compiler/rustc_errors/src/emitter.rs"),
::tracing_core::__macro_support::Option::Some(353u32),
::tracing_core::__macro_support::Option::Some("rustc_errors::emitter"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("fix_multispans_in_extern_macros: before: span={0:?} children={1:?}",
span, children) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("fix_multispans_in_extern_macros: before: span={:?} children={:?}", span, children);
354 self.fix_multispan_in_extern_macros(span);
355 for child in children.iter_mut() {
356 self.fix_multispan_in_extern_macros(&mut child.span);
357 }
358 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/6bb1652a020e80cef79332741d89e996d71933c9/compiler/rustc_errors/src/emitter.rs:358",
"rustc_errors::emitter", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/6bb1652a020e80cef79332741d89e996d71933c9/compiler/rustc_errors/src/emitter.rs"),
::tracing_core::__macro_support::Option::Some(358u32),
::tracing_core::__macro_support::Option::Some("rustc_errors::emitter"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("fix_multispans_in_extern_macros: after: span={0:?} children={1:?}",
span, children) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("fix_multispans_in_extern_macros: after: span={:?} children={:?}", span, children);
359 }
360
361 fn fix_multispan_in_extern_macros(&self, span: &mut MultiSpan) {
365 let Some(source_map) = self.source_map() else { return };
366 let should_hide = |span| {
367 source_map.is_imported(span) || {
368 let expn = span.data().ctxt.outer_expn_data();
369 expn.diagnostic_opaque && #[allow(non_exhaustive_omitted_patterns)] match expn.kind {
ExpnKind::Macro(MacroKind::Bang, _) => true,
_ => false,
}matches!(expn.kind, ExpnKind::Macro(MacroKind::Bang, _))
370 }
371 };
372
373 let replacements: Vec<(Span, Span)> = span
375 .primary_spans()
376 .iter()
377 .copied()
378 .chain(span.span_labels().iter().map(|sp_label| sp_label.span))
379 .filter_map(|sp| {
380 if !sp.is_dummy() && should_hide(sp) {
381 let mut span = sp;
382 while let Some(callsite) = span.parent_callsite() {
383 span = callsite;
384 if !should_hide(span) {
385 return Some((sp, span));
386 }
387 }
388 }
389 None
390 })
391 .collect();
392
393 for (from, to) in replacements {
395 span.replace(from, to);
396 }
397 }
398}
399
400pub struct EmitterWithNote {
402 pub emitter: Box<dyn Emitter + DynSend>,
403 pub note: String,
404}
405
406impl Emitter for EmitterWithNote {
407 fn source_map(&self) -> Option<&SourceMap> {
408 None
409 }
410
411 fn emit_diagnostic(&mut self, mut diag: DiagInner) {
412 diag.sub(Sublevel::Note, self.note.clone(), MultiSpan::new());
413 self.emitter.emit_diagnostic(diag);
414 }
415}
416
417pub struct SilentEmitter;
418
419impl Emitter for SilentEmitter {
420 fn source_map(&self) -> Option<&SourceMap> {
421 None
422 }
423
424 fn emit_diagnostic(&mut self, _diag: DiagInner) {}
425}
426
427pub const MAX_SUGGESTIONS: usize = 4;
431
432#[derive(#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for ColorConfig { }
#[automatically_derived]
impl ::core::clone::Clone for ColorConfig {
#[inline]
fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for ColorConfig { }Copy, #[automatically_derived]
impl ::core::fmt::Debug for ColorConfig {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self {
ColorConfig::Auto => "Auto",
ColorConfig::Always => "Always",
ColorConfig::Never => "Never",
})
}
}Debug, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for ColorConfig { }
#[automatically_derived]
impl ::core::cmp::PartialEq for ColorConfig {
#[inline]
fn eq(&self, other: &Self) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for ColorConfig { }Eq)]
433pub enum ColorConfig {
434 Auto,
435 Always,
436 Never,
437}
438
439impl ColorConfig {
440 pub fn to_color_choice(self) -> ColorChoice {
441 match self {
442 ColorConfig::Always => {
443 if io::stderr().is_terminal() {
444 ColorChoice::Always
445 } else {
446 ColorChoice::AlwaysAnsi
447 }
448 }
449 ColorConfig::Never => ColorChoice::Never,
450 ColorConfig::Auto if io::stderr().is_terminal() => ColorChoice::Auto,
451 ColorConfig::Auto => ColorChoice::Never,
452 }
453 }
454}
455
456#[derive(#[automatically_derived]
impl ::core::fmt::Debug for OutputTheme {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self {
OutputTheme::Ascii => "Ascii",
OutputTheme::Unicode => "Unicode",
})
}
}Debug, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for OutputTheme { }
#[automatically_derived]
impl ::core::clone::Clone for OutputTheme {
#[inline]
fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for OutputTheme { }Copy, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for OutputTheme { }
#[automatically_derived]
impl ::core::cmp::PartialEq for OutputTheme {
#[inline]
fn eq(&self, other: &Self) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for OutputTheme { }Eq)]
457pub enum OutputTheme {
458 Ascii,
459 Unicode,
460}
461
462const OUTPUT_REPLACEMENTS: &[(char, &str)] = &[
465 ('\0', "␀"),
469 ('\u{0001}', "␁"),
470 ('\u{0002}', "␂"),
471 ('\u{0003}', "␃"),
472 ('\u{0004}', "␄"),
473 ('\u{0005}', "␅"),
474 ('\u{0006}', "␆"),
475 ('\u{0007}', "␇"),
476 ('\u{0008}', "␈"),
477 ('\t', " "), ('\u{000b}', "␋"),
479 ('\u{000c}', "␌"),
480 ('\u{000d}', "␍"),
481 ('\u{000e}', "␎"),
482 ('\u{000f}', "␏"),
483 ('\u{0010}', "␐"),
484 ('\u{0011}', "␑"),
485 ('\u{0012}', "␒"),
486 ('\u{0013}', "␓"),
487 ('\u{0014}', "␔"),
488 ('\u{0015}', "␕"),
489 ('\u{0016}', "␖"),
490 ('\u{0017}', "␗"),
491 ('\u{0018}', "␘"),
492 ('\u{0019}', "␙"),
493 ('\u{001a}', "␚"),
494 ('\u{001b}', "␛"),
495 ('\u{001c}', "␜"),
496 ('\u{001d}', "␝"),
497 ('\u{001e}', "␞"),
498 ('\u{001f}', "␟"),
499 ('\u{007f}', "␡"),
500 ('\u{200d}', ""), ('\u{202a}', "�"), ('\u{202b}', "�"), ('\u{202c}', "�"), ('\u{202d}', "�"),
505 ('\u{202e}', "�"),
506 ('\u{2066}', "�"),
507 ('\u{2067}', "�"),
508 ('\u{2068}', "�"),
509 ('\u{2069}', "�"),
510];
511
512pub(crate) fn normalize_whitespace(s: &str) -> String {
513 const {
514 let mut i = 1;
515 while i < OUTPUT_REPLACEMENTS.len() {
516 if !(OUTPUT_REPLACEMENTS[i - 1].0 < OUTPUT_REPLACEMENTS[i].0) {
{
::core::panicking::panic_fmt(format_args!("The OUTPUT_REPLACEMENTS array must be sorted (for binary search to work) and must contain no duplicate entries"));
}
};assert!(
517 OUTPUT_REPLACEMENTS[i - 1].0 < OUTPUT_REPLACEMENTS[i].0,
518 "The OUTPUT_REPLACEMENTS array must be sorted (for binary search to work) \
519 and must contain no duplicate entries"
520 );
521 i += 1;
522 }
523 }
524 s.chars().fold(String::with_capacity(s.len()), |mut s, c| {
528 match OUTPUT_REPLACEMENTS.binary_search_by_key(&c, |(k, _)| *k) {
529 Ok(i) => s.push_str(OUTPUT_REPLACEMENTS[i].1),
530 _ => s.push(c),
531 }
532 s
533 })
534}
535
536pub type Destination = AutoStream<Box<dyn Write + Send>>;
537
538struct Buffy {
539 buffer_writer: std::io::Stderr,
540 buffer: Vec<u8>,
541}
542
543impl Write for Buffy {
544 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
545 self.buffer.write(buf)
546 }
547
548 fn flush(&mut self) -> io::Result<()> {
549 self.buffer_writer.write_all(&self.buffer)?;
550 self.buffer.clear();
551 Ok(())
552 }
553}
554
555impl Drop for Buffy {
556 fn drop(&mut self) {
557 if !self.buffer.is_empty() {
558 self.flush().unwrap();
559 {
::core::panicking::panic_fmt(format_args!("buffers need to be flushed in order to print their contents"));
};panic!("buffers need to be flushed in order to print their contents");
560 }
561 }
562}
563
564pub fn stderr_destination(color: ColorConfig) -> Destination {
565 let buffer_writer = std::io::stderr();
566 let choice = get_stderr_color_choice(color, &buffer_writer);
569 if falsecfg!(windows) {
576 AutoStream::new(Box::new(buffer_writer), choice)
577 } else {
578 let buffer = Vec::new();
579 AutoStream::new(Box::new(Buffy { buffer_writer, buffer }), choice)
580 }
581}
582
583pub fn get_stderr_color_choice(color: ColorConfig, stderr: &std::io::Stderr) -> ColorChoice {
584 let choice = color.to_color_choice();
585 if #[allow(non_exhaustive_omitted_patterns)] match choice {
ColorChoice::Auto => true,
_ => false,
}matches!(choice, ColorChoice::Auto) { AutoStream::choice(stderr) } else { choice }
586}
587
588impl Style {
589 pub(crate) fn anstyle(&self) -> anstyle::Style {
590 match self {
591 Style::NoStyle => anstyle::Style::new(),
592 Style::Highlight => AnsiColor::Magenta.on_default().effects(Effects::BOLD),
593 }
594 }
595}
596
597pub fn is_different(sm: &SourceMap, suggested: &str, sp: Span) -> bool {
599 let found = match sm.span_to_snippet(sp) {
600 Ok(snippet) => snippet,
601 Err(e) => {
602 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/6bb1652a020e80cef79332741d89e996d71933c9/compiler/rustc_errors/src/emitter.rs:602",
"rustc_errors::emitter", ::tracing::Level::WARN,
::tracing_core::__macro_support::Option::Some("/rustc-dev/6bb1652a020e80cef79332741d89e996d71933c9/compiler/rustc_errors/src/emitter.rs"),
::tracing_core::__macro_support::Option::Some(602u32),
::tracing_core::__macro_support::Option::Some("rustc_errors::emitter"),
::tracing_core::field::FieldSet::new(&["message",
{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("error")
}> =
::tracing::__macro_support::FieldName::new("error");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::WARN <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::WARN <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("Invalid span {0:?}",
sp) as &dyn ::tracing::field::Value)),
(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&e)
as &dyn ::tracing::field::Value))])
});
} else { ; }
};warn!(error = ?e, "Invalid span {:?}", sp);
603 return true;
604 }
605 };
606 found != suggested
607}
608
609pub fn detect_confusion_type(sm: &SourceMap, suggested: &str, sp: Span) -> ConfusionType {
611 let found = match sm.span_to_snippet(sp) {
612 Ok(snippet) => snippet,
613 Err(e) => {
614 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/6bb1652a020e80cef79332741d89e996d71933c9/compiler/rustc_errors/src/emitter.rs:614",
"rustc_errors::emitter", ::tracing::Level::WARN,
::tracing_core::__macro_support::Option::Some("/rustc-dev/6bb1652a020e80cef79332741d89e996d71933c9/compiler/rustc_errors/src/emitter.rs"),
::tracing_core::__macro_support::Option::Some(614u32),
::tracing_core::__macro_support::Option::Some("rustc_errors::emitter"),
::tracing_core::field::FieldSet::new(&["message",
{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("error")
}> =
::tracing::__macro_support::FieldName::new("error");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::WARN <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::WARN <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("Invalid span {0:?}",
sp) as &dyn ::tracing::field::Value)),
(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&e)
as &dyn ::tracing::field::Value))])
});
} else { ; }
};warn!(error = ?e, "Invalid span {:?}", sp);
615 return ConfusionType::None;
616 }
617 };
618
619 let mut has_case_confusion = false;
620 let mut has_digit_letter_confusion = false;
621
622 if found.len() == suggested.len() {
623 let mut has_case_diff = false;
624 let mut has_digit_letter_confusable = false;
625 let mut has_other_diff = false;
626
627 let ascii_confusables = &['c', 'f', 'i', 'k', 'o', 's', 'u', 'v', 'w', 'x', 'y', 'z'];
630
631 let digit_letter_confusables = [('0', 'O'), ('1', 'l'), ('5', 'S'), ('8', 'B'), ('9', 'g')];
632
633 for (f, s) in iter::zip(found.chars(), suggested.chars()) {
634 if f != s {
635 if f.eq_ignore_ascii_case(&s) {
636 if ascii_confusables.contains(&f) || ascii_confusables.contains(&s) {
638 has_case_diff = true;
639 } else {
640 has_other_diff = true;
641 }
642 } else if digit_letter_confusables.contains(&(f, s))
643 || digit_letter_confusables.contains(&(s, f))
644 {
645 has_digit_letter_confusable = true;
647 } else {
648 has_other_diff = true;
649 }
650 }
651 }
652
653 if has_case_diff && !has_other_diff && found != suggested {
655 has_case_confusion = true;
656 }
657 if has_digit_letter_confusable && !has_other_diff && found != suggested {
658 has_digit_letter_confusion = true;
659 }
660 }
661
662 match (has_case_confusion, has_digit_letter_confusion) {
663 (true, true) => ConfusionType::Both,
664 (true, false) => ConfusionType::Case,
665 (false, true) => ConfusionType::DigitLetter,
666 (false, false) => ConfusionType::None,
667 }
668}
669
670#[derive(#[automatically_derived]
impl ::core::fmt::Debug for ConfusionType {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self {
ConfusionType::None => "None",
ConfusionType::Case => "Case",
ConfusionType::DigitLetter => "DigitLetter",
ConfusionType::Both => "Both",
})
}
}Debug, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for ConfusionType { }
#[automatically_derived]
impl ::core::clone::Clone for ConfusionType {
#[inline]
fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for ConfusionType { }Copy, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for ConfusionType { }
#[automatically_derived]
impl ::core::cmp::PartialEq for ConfusionType {
#[inline]
fn eq(&self, other: &Self) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for ConfusionType { }Eq)]
672pub enum ConfusionType {
673 None,
675 Case,
677 DigitLetter,
679 Both,
681}
682
683impl ConfusionType {
684 pub fn label_text(&self) -> &'static str {
686 match self {
687 ConfusionType::None => "",
688 ConfusionType::Case => " (notice the capitalization)",
689 ConfusionType::DigitLetter => " (notice the digit/letter confusion)",
690 ConfusionType::Both => " (notice the capitalization and digit/letter confusion)",
691 }
692 }
693
694 pub fn combine(self, other: ConfusionType) -> ConfusionType {
698 match (self, other) {
699 (ConfusionType::None, other) => other,
700 (this, ConfusionType::None) => this,
701 (ConfusionType::Both, _) | (_, ConfusionType::Both) => ConfusionType::Both,
702 (ConfusionType::Case, ConfusionType::DigitLetter)
703 | (ConfusionType::DigitLetter, ConfusionType::Case) => ConfusionType::Both,
704 (ConfusionType::Case, ConfusionType::Case) => ConfusionType::Case,
705 (ConfusionType::DigitLetter, ConfusionType::DigitLetter) => ConfusionType::DigitLetter,
706 }
707 }
708
709 pub fn has_confusion(&self) -> bool {
711 *self != ConfusionType::None
712 }
713}
714
715pub(crate) fn should_show_source_code(
716 ignored_directories: &[String],
717 sm: &SourceMap,
718 file: &SourceFile,
719) -> bool {
720 if !sm.ensure_source_file_source_present(file) {
721 return false;
722 }
723
724 let FileName::Real(name) = &file.name else { return true };
725 name.local_path()
726 .map(|path| ignored_directories.iter().all(|dir| !path.starts_with(dir)))
727 .unwrap_or(true)
728}