1#![feature(rustc_private)]
2
3extern crate rustc_data_structures;
4extern crate rustc_errors;
5extern crate rustc_session;
6extern crate rustc_span;
7
8use std::{cell::Cell, io, sync::Arc};
9
10use flux_common::result::{ErrorCollector, ErrorEmitter};
11use rustc_data_structures::sync;
12pub use rustc_errors::ErrorGuaranteed;
13use rustc_errors::{
14 Diagnostic, ErrCode, FatalError, TerminalUrl,
15 annotate_snippet_emitter_writer::AnnotateSnippetEmitter,
16 emitter::{Emitter, HumanReadableErrorType, OutputTheme, stderr_destination},
17 json::JsonEmitter,
18};
19use rustc_session::{config, parse::ParseSess};
20use rustc_span::source_map::SourceMap;
21
22pub struct FluxSession {
23 pub parse_sess: ParseSess,
24}
25
26pub const E0999: ErrCode = ErrCode::from_u32(999);
28
29impl FluxSession {
30 pub fn new(opts: &config::Options, source_map: Arc<SourceMap>) -> Self {
31 let emitter = emitter(opts, source_map.clone());
32 let dcx = rustc_errors::DiagCtxt::new(emitter);
33 Self { parse_sess: ParseSess::with_dcx(dcx, source_map) }
34 }
35
36 pub fn err_count(&self) -> usize {
37 self.parse_sess.dcx().err_count()
38 }
39
40 #[track_caller]
41 pub fn emit_err<'a>(&'a self, err: impl Diagnostic<'a>) -> ErrorGuaranteed {
42 self.parse_sess.dcx().emit_err(err)
43 }
44
45 #[track_caller]
46 pub fn emit_fatal<'a>(&'a self, fatal: impl Diagnostic<'a>) -> ! {
47 self.parse_sess.dcx().emit_fatal(fatal)
48 }
49
50 pub fn abort(&self, _: ErrorGuaranteed) -> ! {
51 self.parse_sess.dcx().abort_if_errors();
52 FatalError.raise()
53 }
54
55 pub fn abort_if_errors(&self) {
56 self.parse_sess.dcx().abort_if_errors();
57 }
58
59 pub fn finish_diagnostics(&self) {
60 self.parse_sess.dcx().print_error_count();
61 self.abort_if_errors();
62 }
63
64 pub fn dcx(&self) -> rustc_errors::DiagCtxtHandle<'_> {
65 self.parse_sess.dcx()
66 }
67}
68
69fn emitter(
70 sopts: &config::Options,
71 source_map: Arc<SourceMap>,
72) -> Box<dyn Emitter + sync::DynSend> {
73 let macro_backtrace = sopts.unstable_opts.macro_backtrace;
75 let track_diagnostics = sopts.unstable_opts.track_diagnostics;
76 let terminal_url = match sopts.unstable_opts.terminal_urls {
77 TerminalUrl::Auto => {
78 match (std::env::var("COLORTERM").as_deref(), std::env::var("TERM").as_deref()) {
79 (Ok("truecolor"), Ok("xterm-256color"))
80 if sopts.unstable_features.is_nightly_build() =>
81 {
82 TerminalUrl::Yes
83 }
84 _ => TerminalUrl::No,
85 }
86 }
87 t => t,
88 };
89
90 let source_map = if sopts.unstable_opts.link_only { None } else { Some(source_map) };
91
92 match sopts.error_format {
93 config::ErrorOutputType::HumanReadable { kind, color_config } => {
94 match kind {
95 HumanReadableErrorType { short, unicode } => {
96 let emitter = AnnotateSnippetEmitter::new(stderr_destination(color_config))
97 .sm(source_map)
98 .short_message(short)
99 .diagnostic_width(sopts.diagnostic_width)
100 .macro_backtrace(macro_backtrace)
101 .track_diagnostics(track_diagnostics)
102 .terminal_url(terminal_url)
103 .theme(if unicode { OutputTheme::Unicode } else { OutputTheme::Ascii })
104 .ignored_directories_in_source_blocks(
105 sopts
106 .unstable_opts
107 .ignore_directory_in_diagnostics_source_blocks
108 .clone(),
109 );
110 Box::new(emitter.ui_testing(sopts.unstable_opts.ui_testing))
111 }
112 }
113 }
114 config::ErrorOutputType::Json { pretty, json_rendered, color_config } => {
115 Box::new(
116 JsonEmitter::new(
117 Box::new(io::BufWriter::new(io::stderr())),
118 source_map,
119 pretty,
120 json_rendered,
121 color_config,
122 )
123 .ui_testing(sopts.unstable_opts.ui_testing)
124 .ignored_directories_in_source_blocks(
125 sopts
126 .unstable_opts
127 .ignore_directory_in_diagnostics_source_blocks
128 .clone(),
129 )
130 .diagnostic_width(sopts.diagnostic_width)
131 .macro_backtrace(macro_backtrace)
132 .track_diagnostics(track_diagnostics)
133 .terminal_url(terminal_url),
134 )
135 }
136 }
137}
138
139impl ErrorEmitter for FluxSession {
140 fn emit<'a>(&'a self, err: impl Diagnostic<'a>) -> ErrorGuaranteed {
141 self.emit_err(err)
142 }
143}
144
145pub struct Errors<'sess> {
147 sess: &'sess FluxSession,
148 err: Cell<Option<ErrorGuaranteed>>,
149}
150
151impl<'sess> Errors<'sess> {
152 pub fn new(sess: &'sess FluxSession) -> Self {
153 Self { sess, err: Cell::new(None) }
154 }
155
156 pub fn has_errors(&self) -> bool {
157 self.err.get().is_some()
158 }
159
160 #[track_caller]
161 pub fn emit<'a>(&'a self, err: impl Diagnostic<'a>) -> ErrorGuaranteed {
162 let err = self.sess.emit_err(err);
163 self.err.set(Some(err));
164 err
165 }
166
167 pub fn to_result(&self) -> Result<(), ErrorGuaranteed> {
168 if let Some(err) = self.err.get() { Err(err) } else { Ok(()) }
169 }
170}
171
172impl ErrorEmitter for Errors<'_> {
173 #[track_caller]
174 fn emit<'a>(&'a self, err: impl Diagnostic<'a>) -> ErrorGuaranteed {
175 Errors::emit(self, err)
176 }
177}
178
179impl ErrorCollector<ErrorGuaranteed> for Errors<'_> {
180 type Result = Result<(), ErrorGuaranteed>;
181
182 fn collect(&mut self, err: ErrorGuaranteed) {
183 *self.err.get_mut() = Some(err);
184 }
185
186 fn into_result(self) -> Self::Result {
187 Errors::to_result(&self)
188 }
189}