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