1//! This implementation uses [`proc_macro::Diagnostic`], nightly only. 2 3use std::cell::Cell; 4 5use proc_macro::{Diagnostic as PDiag, Level as PLevel}; 6 7use crate::{ 8 abort_now, check_correctness, 9 diagnostic::{Diagnostic, Level, SuggestionKind}, 10}; 11 12pub fn abort_if_dirty() { 13 check_correctness(); 14 if IS_DIRTY.with(|c| c.get()) { 15 abort_now() 16 } 17} 18 19pub(crate) fn cleanup() -> Vec<Diagnostic> { 20 IS_DIRTY.with(|c| c.set(false)); 21 vec![] 22} 23 24pub(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 67thread_local! { 68 static IS_DIRTY: Cell<bool> = Cell::new(false); 69} 70