1use std::{
12 borrow::Cow,
13 cell::RefCell,
14 error, fmt,
15 io::Write,
16 panic,
17 sync::atomic::{AtomicUsize, Ordering::SeqCst},
18};
19
20use rustc_hash::FxHashSet;
21#[cfg(feature = "tty-emitter")]
22use termcolor::{Color, ColorSpec};
23
24use self::Level::*;
25pub use self::{
26 diagnostic::{Diagnostic, DiagnosticId, DiagnosticStyledString, Message, SubDiagnostic},
27 diagnostic_builder::DiagnosticBuilder,
28 emitter::{ColorConfig, Emitter, EmitterWriter},
29 snippet::Style,
30};
31use crate::{
32 rustc_data_structures::stable_hasher::StableHasher,
33 sync::{Lock, LockCell, Lrc},
34 syntax_pos::{BytePos, FileLinesResult, FileName, Loc, MultiSpan, Span},
35 SpanSnippetError,
36};
37
38mod diagnostic;
39mod diagnostic_builder;
40
41pub mod emitter;
42mod lock;
43mod snippet;
44mod styled_buffer;
45
46#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
47#[cfg_attr(
48 feature = "diagnostic-serde",
49 derive(serde::Serialize, serde::Deserialize)
50)]
51#[cfg_attr(
52 any(feature = "rkyv-impl"),
53 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
54)]
55#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
56#[cfg_attr(feature = "rkyv-impl", repr(u32))]
57pub enum Applicability {
58 MachineApplicable,
59 HasPlaceholders,
60 MaybeIncorrect,
61 Unspecified,
62}
63
64#[derive(Clone, Debug, PartialEq, Eq, Hash)]
65#[cfg_attr(
66 feature = "diagnostic-serde",
67 derive(serde::Serialize, serde::Deserialize)
68)]
69#[cfg_attr(
70 any(feature = "rkyv-impl"),
71 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
72)]
73#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
74#[cfg_attr(feature = "rkyv-impl", repr(C))]
75pub struct CodeSuggestion {
76 pub substitutions: Vec<Substitution>,
106 pub msg: String,
107 pub show_code_when_inline: bool,
108 pub applicability: Applicability,
114}
115
116#[derive(Clone, Debug, PartialEq, Eq, Hash)]
117#[cfg_attr(
119 feature = "diagnostic-serde",
120 derive(serde::Serialize, serde::Deserialize)
121)]
122#[cfg_attr(
123 any(feature = "rkyv-impl"),
124 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
125)]
126#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
127#[cfg_attr(feature = "rkyv-impl", repr(C))]
128pub struct Substitution {
129 pub parts: Vec<SubstitutionPart>,
130}
131
132#[derive(Clone, Debug, PartialEq, Eq, Hash)]
133#[cfg_attr(
134 feature = "diagnostic-serde",
135 derive(serde::Serialize, serde::Deserialize)
136)]
137#[cfg_attr(
138 any(feature = "rkyv-impl"),
139 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
140)]
141#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
142#[cfg_attr(feature = "rkyv-impl", repr(C))]
143pub struct SubstitutionPart {
144 pub span: Span,
145 pub snippet: String,
146}
147
148pub type SourceMapperDyn = dyn SourceMapper;
149
150pub trait SourceMapper: crate::sync::Send + crate::sync::Sync {
151 fn lookup_char_pos(&self, pos: BytePos) -> Loc;
152 fn span_to_lines(&self, sp: Span) -> FileLinesResult;
153 fn span_to_string(&self, sp: Span) -> String;
154 fn span_to_filename(&self, sp: Span) -> Lrc<FileName>;
155 fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option<Span>;
156 fn call_span_if_macro(&self, sp: Span) -> Span;
157 fn doctest_offset_line(&self, line: usize) -> usize;
158 fn span_to_snippet(&self, sp: Span) -> Result<String, Box<SpanSnippetError>>;
159}
160
161impl CodeSuggestion {
162 pub fn splice_lines(&self, cm: &SourceMapperDyn) -> Vec<(String, Vec<SubstitutionPart>)> {
165 use crate::syntax_pos::{CharPos, SmallPos};
166
167 fn push_trailing(
168 buf: &mut String,
169 line_opt: Option<&Cow<'_, str>>,
170 lo: &Loc,
171 hi_opt: Option<&Loc>,
172 ) {
173 let (lo, hi_opt) = (lo.col.to_usize(), hi_opt.map(|hi| hi.col.to_usize()));
174 if let Some(line) = line_opt {
175 if let Some(lo) = line.char_indices().map(|(i, _)| i).nth(lo) {
176 let hi_opt = hi_opt.and_then(|hi| line.char_indices().map(|(i, _)| i).nth(hi));
177 buf.push_str(match hi_opt {
178 Some(hi) => &line[lo..hi],
179 None => &line[lo..],
180 });
181 }
182 if hi_opt.is_none() {
183 buf.push('\n');
184 }
185 }
186 }
187
188 assert!(!self.substitutions.is_empty());
189
190 self.substitutions
191 .iter()
192 .cloned()
193 .map(|mut substitution| {
194 substitution.parts.sort_by_key(|part| part.span.lo());
197
198 let lo = substitution
200 .parts
201 .iter()
202 .map(|part| part.span.lo())
203 .min()
204 .unwrap();
205 let hi = substitution
206 .parts
207 .iter()
208 .map(|part| part.span.hi())
209 .min()
210 .unwrap();
211 let bounding_span = Span::new(lo, hi);
212 let lines = cm.span_to_lines(bounding_span).unwrap();
213 assert!(!lines.lines.is_empty());
214
215 let fm = &lines.file;
225 let mut prev_hi = cm.lookup_char_pos(bounding_span.lo());
226 prev_hi.col = CharPos::from_usize(0);
227
228 let mut prev_line = fm.get_line(lines.lines[0].line_index);
229 let mut buf = String::new();
230
231 for part in &substitution.parts {
232 let cur_lo = cm.lookup_char_pos(part.span.lo());
233 if prev_hi.line == cur_lo.line {
234 push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, Some(&cur_lo));
235 } else {
236 push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
237 for idx in prev_hi.line..(cur_lo.line - 1) {
239 if let Some(line) = fm.get_line(idx) {
240 buf.push_str(line.as_ref());
241 buf.push('\n');
242 }
243 }
244 if let Some(cur_line) = fm.get_line(cur_lo.line - 1) {
245 buf.push_str(&cur_line[..cur_lo.col.to_usize()]);
246 }
247 }
248 buf.push_str(&part.snippet);
249 prev_hi = cm.lookup_char_pos(part.span.hi());
250 prev_line = fm.get_line(prev_hi.line - 1);
251 }
252 if !buf.ends_with('\n') {
254 push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
255 }
256 while buf.ends_with('\n') {
258 buf.pop();
259 }
260 (buf, substitution.parts)
261 })
262 .collect()
263 }
264}
265
266#[derive(Copy, Clone, Debug)]
270#[must_use]
271pub struct FatalError;
272
273pub struct FatalErrorMarker;
274
275impl FatalError {
281 pub fn raise(self) -> ! {
282 panic::resume_unwind(Box::new(FatalErrorMarker))
283 }
284}
285
286impl fmt::Display for FatalError {
287 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
288 write!(f, "parser fatal error")
289 }
290}
291
292impl error::Error for FatalError {
293 fn description(&self) -> &str {
294 "The parser has encountered a fatal error"
295 }
296}
297
298#[derive(Copy, Clone, Debug)]
301pub struct ExplicitBug;
302
303impl fmt::Display for ExplicitBug {
304 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
305 write!(f, "parser internal bug")
306 }
307}
308
309impl error::Error for ExplicitBug {
310 fn description(&self) -> &str {
311 "The parser has encountered an internal bug"
312 }
313}
314
315pub struct Handler {
356 pub flags: HandlerFlags,
357
358 err_count: AtomicUsize,
359 emitter: Lock<Box<dyn Emitter>>,
360 continue_after_error: LockCell<bool>,
361 delayed_span_bugs: Lock<Vec<Diagnostic>>,
362
363 taught_diagnostics: Lock<FxHashSet<DiagnosticId>>,
367
368 emitted_diagnostic_codes: Lock<FxHashSet<DiagnosticId>>,
370
371 emitted_diagnostics: Lock<FxHashSet<u128>>,
375}
376
377fn default_track_diagnostic(_: &Diagnostic) {}
378
379thread_local!(pub static TRACK_DIAGNOSTICS: RefCell<Box<dyn Fn(&Diagnostic)>> =
380 RefCell::new(Box::new(default_track_diagnostic)));
381
382#[derive(Default)]
383pub struct HandlerFlags {
384 pub can_emit_warnings: bool,
387 pub treat_err_as_bug: bool,
390 pub dont_buffer_diagnostics: bool,
393 pub report_delayed_bugs: bool,
396 pub external_macro_backtrace: bool,
399}
400
401impl Drop for Handler {
402 fn drop(&mut self) {
403 if self.err_count() == 0 {
404 let mut bugs = self.delayed_span_bugs.borrow_mut();
405 let has_bugs = !bugs.is_empty();
406 for bug in bugs.drain(..) {
407 DiagnosticBuilder::new_diagnostic(self, bug).emit();
408 }
409 if has_bugs {
410 panic!("no errors encountered even though `delay_span_bug` issued");
411 }
412 }
413 }
414}
415
416impl Handler {
417 #[cfg(feature = "tty-emitter")]
418 #[cfg_attr(docsrs, doc(cfg(feature = "tty-emitter")))]
419 pub fn with_tty_emitter(
420 color_config: ColorConfig,
421 can_emit_warnings: bool,
422 treat_err_as_bug: bool,
423 cm: Option<Lrc<SourceMapperDyn>>,
424 ) -> Handler {
425 Handler::with_tty_emitter_and_flags(
426 color_config,
427 cm,
428 HandlerFlags {
429 can_emit_warnings,
430 treat_err_as_bug,
431 ..Default::default()
432 },
433 )
434 }
435
436 #[cfg(feature = "tty-emitter")]
437 #[cfg_attr(docsrs, doc(cfg(feature = "tty-emitter")))]
438 pub fn with_tty_emitter_and_flags(
439 color_config: ColorConfig,
440 cm: Option<Lrc<SourceMapperDyn>>,
441 flags: HandlerFlags,
442 ) -> Handler {
443 let emitter = Box::new(EmitterWriter::stderr(color_config, cm, false, false));
444 Handler::with_emitter_and_flags(emitter, flags)
445 }
446
447 pub fn with_emitter(
449 can_emit_warnings: bool,
450 treat_err_as_bug: bool,
451 emitter: Box<dyn Emitter>,
452 ) -> Handler {
453 Handler::with_emitter_and_flags(
454 emitter,
455 HandlerFlags {
456 can_emit_warnings,
457 treat_err_as_bug,
458 ..Default::default()
459 },
460 )
461 }
462
463 pub fn with_emitter_writer(
465 dst: Box<dyn Write + Send>,
466 cm: Option<Lrc<SourceMapperDyn>>,
467 ) -> Handler {
468 Handler::with_emitter(
469 true,
470 false,
471 Box::new(EmitterWriter::new(dst, cm, false, true)),
472 )
473 }
474
475 pub fn with_emitter_and_flags(e: Box<dyn Emitter>, flags: HandlerFlags) -> Handler {
476 Handler {
477 flags,
478 err_count: AtomicUsize::new(0),
479 emitter: Lock::new(e),
480 continue_after_error: LockCell::new(true),
481 delayed_span_bugs: Lock::new(Vec::new()),
482 taught_diagnostics: Default::default(),
483 emitted_diagnostic_codes: Default::default(),
484 emitted_diagnostics: Default::default(),
485 }
486 }
487
488 pub fn set_continue_after_error(&self, continue_after_error: bool) {
489 self.continue_after_error.set(continue_after_error);
490 }
491
492 pub fn reset_err_count(&self) {
500 *self.emitted_diagnostics.borrow_mut() = Default::default();
502 self.err_count.store(0, SeqCst);
503 }
504
505 pub fn struct_dummy(&self) -> DiagnosticBuilder<'_> {
506 DiagnosticBuilder::new(self, Level::Cancelled, "")
507 }
508
509 pub fn struct_span_warn<'a, S: Into<MultiSpan>>(
510 &'a self,
511 sp: S,
512 msg: &str,
513 ) -> DiagnosticBuilder<'a> {
514 let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
515 result.set_span(sp);
516 if !self.flags.can_emit_warnings {
517 result.cancel();
518 }
519 result
520 }
521
522 pub fn struct_span_warn_with_code<'a, S: Into<MultiSpan>>(
523 &'a self,
524 sp: S,
525 msg: &str,
526 code: DiagnosticId,
527 ) -> DiagnosticBuilder<'a> {
528 let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
529 result.set_span(sp);
530 result.code(code);
531 if !self.flags.can_emit_warnings {
532 result.cancel();
533 }
534 result
535 }
536
537 pub fn struct_warn<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
538 let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
539 if !self.flags.can_emit_warnings {
540 result.cancel();
541 }
542 result
543 }
544
545 pub fn struct_span_err<'a, S: Into<MultiSpan>>(
546 &'a self,
547 sp: S,
548 msg: &str,
549 ) -> DiagnosticBuilder<'a> {
550 let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
551 result.set_span(sp);
552 result
553 }
554
555 pub fn struct_span_err_with_code<'a, S: Into<MultiSpan>>(
556 &'a self,
557 sp: S,
558 msg: &str,
559 code: DiagnosticId,
560 ) -> DiagnosticBuilder<'a> {
561 let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
562 result.set_span(sp);
563 result.code(code);
564 result
565 }
566
567 pub fn struct_err<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
570 DiagnosticBuilder::new(self, Level::Error, msg)
571 }
572
573 pub fn struct_err_with_code<'a>(
574 &'a self,
575 msg: &str,
576 code: DiagnosticId,
577 ) -> DiagnosticBuilder<'a> {
578 let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
579 result.code(code);
580 result
581 }
582
583 pub fn struct_span_fatal<'a, S: Into<MultiSpan>>(
584 &'a self,
585 sp: S,
586 msg: &str,
587 ) -> DiagnosticBuilder<'a> {
588 let mut result = DiagnosticBuilder::new(self, Level::Fatal, msg);
589 result.set_span(sp);
590 result
591 }
592
593 pub fn struct_span_fatal_with_code<'a, S: Into<MultiSpan>>(
594 &'a self,
595 sp: S,
596 msg: &str,
597 code: DiagnosticId,
598 ) -> DiagnosticBuilder<'a> {
599 let mut result = DiagnosticBuilder::new(self, Level::Fatal, msg);
600 result.set_span(sp);
601 result.code(code);
602 result
603 }
604
605 pub fn struct_fatal<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
606 DiagnosticBuilder::new(self, Level::Fatal, msg)
607 }
608
609 pub fn cancel(&self, err: &mut DiagnosticBuilder<'_>) {
610 err.cancel();
611 }
612
613 fn panic_if_treat_err_as_bug(&self) {
614 if self.flags.treat_err_as_bug {
615 panic!("encountered error with `-Z treat_err_as_bug");
616 }
617 }
618
619 pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> FatalError {
620 self.emit(&sp.into(), msg, Fatal);
621 FatalError
622 }
623
624 pub fn span_fatal_with_code<S: Into<MultiSpan>>(
625 &self,
626 sp: S,
627 msg: &str,
628 code: DiagnosticId,
629 ) -> FatalError {
630 self.emit_with_code(&sp.into(), msg, code, Fatal);
631 FatalError
632 }
633
634 pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
635 self.emit(&sp.into(), msg, Error);
636 }
637
638 pub fn mut_span_err<'a, S: Into<MultiSpan>>(
639 &'a self,
640 sp: S,
641 msg: &str,
642 ) -> DiagnosticBuilder<'a> {
643 let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
644 result.set_span(sp);
645 result
646 }
647
648 pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: DiagnosticId) {
649 self.emit_with_code(&sp.into(), msg, code, Error);
650 }
651
652 pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
653 self.emit(&sp.into(), msg, Warning);
654 }
655
656 pub fn span_warn_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: DiagnosticId) {
657 self.emit_with_code(&sp.into(), msg, code, Warning);
658 }
659
660 pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
661 self.emit(&sp.into(), msg, Bug);
662 panic!("{}", ExplicitBug);
663 }
664
665 pub fn delay_span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
666 if self.flags.treat_err_as_bug {
667 self.span_bug(sp, msg);
669 }
670 let mut diagnostic = Diagnostic::new(Level::Bug, msg);
671 diagnostic.set_span(sp.into());
672 self.delay_as_bug(diagnostic);
673 }
674
675 fn delay_as_bug(&self, diagnostic: Diagnostic) {
676 if self.flags.report_delayed_bugs {
677 DiagnosticBuilder::new_diagnostic(self, diagnostic.clone()).emit();
678 }
679 self.delayed_span_bugs.borrow_mut().push(diagnostic);
680 }
681
682 pub fn span_bug_no_panic<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
683 self.emit(&sp.into(), msg, Bug);
684 }
685
686 pub fn span_note_without_error<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
687 self.emit(&sp.into(), msg, Note);
688 }
689
690 pub fn span_note_diag<'a>(&'a self, sp: Span, msg: &str) -> DiagnosticBuilder<'a> {
691 let mut db = DiagnosticBuilder::new(self, Note, msg);
692 db.set_span(sp);
693 db
694 }
695
696 pub fn span_unimpl<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
697 self.span_bug(sp, &format!("unimplemented {msg}"));
698 }
699
700 pub fn failure(&self, msg: &str) {
701 DiagnosticBuilder::new(self, FailureNote, msg).emit()
702 }
703
704 pub fn fatal(&self, msg: &str) -> FatalError {
705 if self.flags.treat_err_as_bug {
706 self.bug(msg);
707 }
708 DiagnosticBuilder::new(self, Fatal, msg).emit();
709 FatalError
710 }
711
712 pub fn err(&self, msg: &str) {
713 if self.flags.treat_err_as_bug {
714 self.bug(msg);
715 }
716 let mut db = DiagnosticBuilder::new(self, Error, msg);
717 db.emit();
718 }
719
720 pub fn err_with_code(&self, msg: &str, code: DiagnosticId) {
721 if self.flags.treat_err_as_bug {
722 self.bug(msg);
723 }
724 let mut db = DiagnosticBuilder::new_with_code(self, Error, Some(code), msg);
725 db.emit();
726 }
727
728 pub fn warn(&self, msg: &str) {
729 let mut db = DiagnosticBuilder::new(self, Warning, msg);
730 db.emit();
731 }
732
733 pub fn note_without_error(&self, msg: &str) {
734 let mut db = DiagnosticBuilder::new(self, Note, msg);
735 db.emit();
736 }
737
738 pub fn bug(&self, msg: &str) -> ! {
739 let mut db = DiagnosticBuilder::new(self, Bug, msg);
740 db.emit();
741 panic!("{}", ExplicitBug);
742 }
743
744 pub fn unimpl(&self, msg: &str) -> ! {
745 self.bug(&format!("unimplemented {msg}"));
746 }
747
748 fn bump_err_count(&self) {
749 self.panic_if_treat_err_as_bug();
750 self.err_count.fetch_add(1, SeqCst);
751 }
752
753 pub fn err_count(&self) -> usize {
754 self.err_count.load(SeqCst)
755 }
756
757 pub fn has_errors(&self) -> bool {
758 self.err_count() > 0
759 }
760
761 pub fn print_error_count(&self) {
762 let s = match self.err_count() {
763 0 => return,
764 1 => "aborting due to previous error".to_string(),
765 _ => format!("aborting due to {} previous errors", self.err_count()),
766 };
767
768 let _ = self.fatal(&s);
769
770 let can_show_explain = self.emitter.borrow().should_show_explain();
771 let are_there_diagnostics = !self.emitted_diagnostic_codes.borrow().is_empty();
772 if can_show_explain && are_there_diagnostics {
773 let mut error_codes = self
774 .emitted_diagnostic_codes
775 .borrow()
776 .iter()
777 .filter_map(|x| match *x {
778 DiagnosticId::Error(ref s) => Some(s.clone()),
779 _ => None,
780 })
781 .collect::<Vec<_>>();
782 if !error_codes.is_empty() {
783 error_codes.sort();
784 if error_codes.len() > 1 {
785 let limit = if error_codes.len() > 9 {
786 9
787 } else {
788 error_codes.len()
789 };
790 self.failure(&format!(
791 "Some errors occurred: {}{}",
792 error_codes[..limit].join(", "),
793 if error_codes.len() > 9 { "..." } else { "." }
794 ));
795 self.failure(&format!(
796 "For more information about an error, try `rustc --explain {}`.",
797 &error_codes[0]
798 ));
799 } else {
800 self.failure(&format!(
801 "For more information about this error, try `rustc --explain {}`.",
802 &error_codes[0]
803 ));
804 }
805 }
806 }
807 }
808
809 pub fn abort_if_errors(&self) {
810 if self.err_count() == 0 {
811 return;
812 }
813 FatalError.raise();
814 }
815
816 pub fn emit(&self, msp: &MultiSpan, msg: &str, lvl: Level) {
817 if lvl == Warning && !self.flags.can_emit_warnings {
818 return;
819 }
820 let mut db = DiagnosticBuilder::new(self, lvl, msg);
821 db.set_span(msp.clone());
822 db.emit();
823 if !self.continue_after_error.get() {
824 self.abort_if_errors();
825 }
826 }
827
828 pub fn emit_with_code(&self, msp: &MultiSpan, msg: &str, code: DiagnosticId, lvl: Level) {
829 if lvl == Warning && !self.flags.can_emit_warnings {
830 return;
831 }
832 let mut db = DiagnosticBuilder::new_with_code(self, lvl, Some(code), msg);
833 db.set_span(msp.clone());
834 db.emit();
835 if !self.continue_after_error.get() {
836 self.abort_if_errors();
837 }
838 }
839
840 pub fn must_teach(&self, code: &DiagnosticId) -> bool {
846 self.taught_diagnostics.borrow_mut().insert(code.clone())
847 }
848
849 pub fn force_print_db(&self, mut db: DiagnosticBuilder<'_>) {
850 self.emitter.borrow_mut().emit(&mut db);
851 db.cancel();
852 }
853
854 fn emit_db(&self, db: &mut DiagnosticBuilder<'_>) {
855 let diagnostic = &**db;
856
857 TRACK_DIAGNOSTICS.with(|track_diagnostics| {
858 track_diagnostics.borrow()(diagnostic);
859 });
860
861 if let Some(ref code) = diagnostic.code {
862 self.emitted_diagnostic_codes
863 .borrow_mut()
864 .insert(code.clone());
865 }
866
867 let diagnostic_hash = {
868 use std::hash::Hash;
869 let mut hasher = StableHasher::new();
870 diagnostic.hash(&mut hasher);
871 hasher.finish()
872 };
873
874 if self
877 .emitted_diagnostics
878 .borrow_mut()
879 .insert(diagnostic_hash)
880 {
881 self.emitter.borrow_mut().emit(db);
882 if db.is_error() {
883 self.bump_err_count();
884 }
885 }
886 }
887
888 pub fn take_diagnostics(&self) -> Vec<String> {
889 self.emitter.borrow_mut().take_diagnostics()
890 }
891}
892
893#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug, Default)]
894#[cfg_attr(
895 feature = "diagnostic-serde",
896 derive(serde::Serialize, serde::Deserialize)
897)]
898#[cfg_attr(
899 any(feature = "rkyv-impl"),
900 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
901)]
902#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
903#[cfg_attr(feature = "rkyv-impl", repr(u32))]
904pub enum Level {
905 Bug,
906 Fatal,
907 PhaseFatal,
910 Error,
911 Warning,
912 Note,
913 Help,
914 #[default]
915 Cancelled,
916 FailureNote,
917}
918
919impl fmt::Display for Level {
920 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
921 self.to_str().fmt(f)
922 }
923}
924
925impl Level {
926 #[cfg(feature = "tty-emitter")]
927 fn color(self) -> ColorSpec {
928 let mut spec = ColorSpec::new();
929 match self {
930 Bug | Fatal | PhaseFatal | Error => {
931 spec.set_fg(Some(Color::Red)).set_intense(true);
932 }
933 Warning => {
934 spec.set_fg(Some(Color::Yellow)).set_intense(cfg!(windows));
935 }
936 Note => {
937 spec.set_fg(Some(Color::Green)).set_intense(true);
938 }
939 Help => {
940 spec.set_fg(Some(Color::Cyan)).set_intense(true);
941 }
942 FailureNote => {}
943 Cancelled => unreachable!(),
944 }
945 spec
946 }
947
948 pub fn to_str(self) -> &'static str {
949 match self {
950 Bug => "error: internal compiler error",
951 Fatal | PhaseFatal | Error => "error",
952 Warning => "warning",
953 Note => "note",
954 Help => "help",
955 FailureNote => "",
956 Cancelled => panic!("Shouldn't call on cancelled error"),
957 }
958 }
959
960 pub fn is_failure_note(self) -> bool {
961 matches!(self, FailureNote)
962 }
963}
964
965better_scoped_tls::scoped_tls!(
966 pub static HANDLER: Handler
976);