1 //! This implementation uses [`proc_macro::Diagnostic`], nightly only.
2
3 use std::cell::Cell;
4
5 use proc_macro::{Diagnostic as PDiag, Level as PLevel};
6
7 use crate::{
8 abort_now, check_correctness,
9 diagnostic::{Diagnostic, Level, SuggestionKind},
10 };
11
abort_if_dirty()12 pub fn abort_if_dirty() {
13 check_correctness();
14 if IS_DIRTY.with(|c| c.get()) {
15 abort_now()
16 }
17 }
18
cleanup() -> Vec<Diagnostic>19 pub(crate) fn cleanup() -> Vec<Diagnostic> {
20 IS_DIRTY.with(|c| c.set(false));
21 vec![]
22 }
23
emit_diagnostic(diag: Diagnostic)24 pub(crate) fn emit_diagnostic(diag: Diagnostic) {
25 let Diagnostic {
26 level,
27 span_range,
28 msg,
29 suggestions,
30 children,
31 } = diag;
32
33 let span = span_range.collapse().unwrap();
34
35 let level = match level {
36 Level::Warning => PLevel::Warning,
37 Level::Error => {
38 IS_DIRTY.with(|c| c.set(true));
39 PLevel::Error
40 }
41 _ => unreachable!(),
42 };
43
44 let mut res = PDiag::spanned(span, level, msg);
45
46 for (kind, msg, span) in suggestions {
47 res = match (kind, span) {
48 (SuggestionKind::Note, Some(span_range)) => {
49 res.span_note(span_range.collapse().unwrap(), msg)
50 }
51 (SuggestionKind::Help, Some(span_range)) => {
52 res.span_help(span_range.collapse().unwrap(), msg)
53 }
54 (SuggestionKind::Note, None) => res.note(msg),
55 (SuggestionKind::Help, None) => res.help(msg),
56 }
57 }
58
59 for (span_range, msg) in children {
60 let span = span_range.collapse().unwrap();
61 res = res.span_error(span, msg);
62 }
63
64 res.emit()
65 }
66
67 thread_local! {
68 static IS_DIRTY: Cell<bool> = Cell::new(false);
69 }
70