solar_interface/diagnostics/emitter/
mod.rs1use super::{Diag, Level};
2use crate::SourceMap;
3use std::{any::Any, sync::Arc};
4
5mod human;
6pub use human::{HumanBufferEmitter, HumanEmitter};
7
8#[cfg(feature = "json")]
9mod json;
10#[cfg(feature = "json")]
11pub use json::JsonEmitter;
12
13mod rustc;
14
15pub type DynEmitter = dyn Emitter + Send;
17
18pub trait Emitter: Any {
20 fn emit_diagnostic(&mut self, diagnostic: &Diag);
22
23 #[inline]
25 fn source_map(&self) -> Option<&Arc<SourceMap>> {
26 None
27 }
28
29 #[inline]
31 fn supports_color(&self) -> bool {
32 false
33 }
34}
35
36impl DynEmitter {
37 pub(crate) fn local_buffer(&self) -> Option<&str> {
38 self.downcast_ref::<HumanBufferEmitter>().map(HumanBufferEmitter::buffer)
39 }
40
41 fn downcast_ref<T: Any>(&self) -> Option<&T> {
43 if self.type_id() == std::any::TypeId::of::<T>() {
44 unsafe { Some(&*(self as *const dyn Emitter as *const T)) }
45 } else {
46 None
47 }
48 }
49}
50
51pub struct SilentEmitter {
55 fatal_emitter: Option<Box<DynEmitter>>,
56 note: Option<String>,
57}
58
59impl SilentEmitter {
60 pub fn new(fatal_emitter: impl Emitter + Send) -> Self {
62 Self::new_boxed(Some(Box::new(fatal_emitter)))
63 }
64
65 pub fn new_boxed(fatal_emitter: Option<Box<DynEmitter>>) -> Self {
67 Self { fatal_emitter, note: None }
68 }
69
70 pub fn new_silent() -> Self {
74 Self::new_boxed(None)
75 }
76
77 pub fn with_note(mut self, note: Option<String>) -> Self {
79 self.note = note;
80 self
81 }
82}
83
84impl Emitter for SilentEmitter {
85 fn emit_diagnostic(&mut self, diagnostic: &Diag) {
86 let Some(fatal_emitter) = self.fatal_emitter.as_deref_mut() else { return };
87 if diagnostic.level != Level::Fatal {
88 return;
89 }
90
91 if let Some(note) = &self.note {
92 let mut diagnostic = diagnostic.clone();
93 diagnostic.note(note.clone());
94 fatal_emitter.emit_diagnostic(&diagnostic);
95 } else {
96 fatal_emitter.emit_diagnostic(diagnostic);
97 }
98 }
99}
100
101#[derive(Clone, Debug)]
103pub struct LocalEmitter {
104 diagnostics: Vec<Diag>,
105}
106
107impl Default for LocalEmitter {
108 fn default() -> Self {
109 Self::new()
110 }
111}
112
113impl LocalEmitter {
114 pub fn new() -> Self {
116 Self { diagnostics: Vec::new() }
117 }
118
119 pub fn diagnostics(&self) -> &[Diag] {
121 &self.diagnostics
122 }
123
124 pub fn into_diagnostics(self) -> Vec<Diag> {
126 self.diagnostics
127 }
128}
129
130impl Emitter for LocalEmitter {
131 fn emit_diagnostic(&mut self, diagnostic: &Diag) {
132 self.diagnostics.push(diagnostic.clone());
133 }
134}
135
136#[cold]
137#[inline(never)]
138fn io_panic(error: std::io::Error) -> ! {
139 panic!("failed to emit diagnostic: {error}");
140}