1#![feature(rustc_private, never_type)]
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, FatalAbort, FatalError, LazyFallbackBundle,
15 annotate_snippet_emitter_writer::AnnotateSnippetEmitter,
16 emitter::{Emitter, HumanEmitter, HumanReadableErrorType, stderr_destination},
17 json::JsonEmitter,
18};
19use rustc_session::{
20 config::{self, ErrorOutputType},
21 parse::ParseSess,
22};
23use rustc_span::source_map::SourceMap;
24
25pub struct FluxSession {
26 pub parse_sess: ParseSess,
27}
28
29pub const E0999: ErrCode = ErrCode::from_u32(999);
31
32impl FluxSession {
33 pub fn new(
34 opts: &config::Options,
35 source_map: Arc<SourceMap>,
36 fallback_bundle: LazyFallbackBundle,
37 ) -> Self {
38 let emitter = emitter(opts, source_map.clone(), fallback_bundle);
39 let dcx = rustc_errors::DiagCtxt::new(emitter);
40 Self { parse_sess: ParseSess::with_dcx(dcx, source_map) }
41 }
42
43 pub fn err_count(&self) -> usize {
44 self.parse_sess.dcx().err_count()
45 }
46
47 #[track_caller]
48 pub fn emit_err<'a>(&'a self, err: impl Diagnostic<'a>) -> ErrorGuaranteed {
49 self.parse_sess.dcx().emit_err(err)
50 }
51
52 #[track_caller]
53 pub fn emit_fatal<'a>(&'a self, fatal: impl Diagnostic<'a, FatalAbort>) -> ! {
54 self.parse_sess.dcx().emit_fatal(fatal)
55 }
56
57 pub fn abort(&self, _: ErrorGuaranteed) -> ! {
58 self.parse_sess.dcx().abort_if_errors();
59 FatalError.raise()
60 }
61
62 pub fn abort_if_errors(&self) {
63 self.parse_sess.dcx().abort_if_errors();
64 }
65
66 pub fn finish_diagnostics(&self) {
67 self.parse_sess.dcx().print_error_count();
68 self.abort_if_errors();
69 }
70
71 pub fn dcx(&self) -> &rustc_errors::DiagCtxt {
72 &self.parse_sess.dcx()
73 }
74}
75
76fn emitter(
77 opts: &config::Options,
78 source_map: Arc<SourceMap>,
79 fallback_bundle: LazyFallbackBundle,
80) -> Box<dyn Emitter + sync::DynSend> {
81 let bundle = None;
82 let track_diagnostics = opts.unstable_opts.track_diagnostics;
83
84 match opts.error_format {
85 ErrorOutputType::HumanReadable(err_type, color_config) => {
86 if let HumanReadableErrorType::AnnotateSnippet = err_type {
87 let emitter = AnnotateSnippetEmitter::new(
88 Some(source_map),
89 None,
90 fallback_bundle,
91 false,
92 false,
93 );
94 Box::new(emitter)
95 } else {
96 let dst = stderr_destination(color_config);
97 let emitter = HumanEmitter::new(dst, fallback_bundle)
98 .sm(Some(source_map))
99 .short_message(err_type.short())
100 .diagnostic_width(opts.diagnostic_width)
101 .track_diagnostics(track_diagnostics)
102 .terminal_url(opts.unstable_opts.terminal_urls);
103 Box::new(emitter)
104 }
105 }
106 ErrorOutputType::Json { pretty, json_rendered, color_config } => {
107 Box::new(
108 JsonEmitter::new(
109 Box::new(io::BufWriter::new(io::stderr())),
110 Some(source_map),
111 fallback_bundle,
112 pretty,
113 json_rendered,
114 color_config,
115 )
116 .fluent_bundle(bundle)
117 .track_diagnostics(track_diagnostics)
118 .diagnostic_width(opts.diagnostic_width)
119 .terminal_url(opts.unstable_opts.terminal_urls),
120 )
121 }
122 }
123}
124
125impl ErrorEmitter for FluxSession {
126 fn emit<'a>(&'a self, err: impl Diagnostic<'a>) -> ErrorGuaranteed {
127 self.emit_err(err)
128 }
129}
130
131pub struct Errors<'sess> {
133 sess: &'sess FluxSession,
134 err: Cell<Option<ErrorGuaranteed>>,
135}
136
137impl<'sess> Errors<'sess> {
138 pub fn new(sess: &'sess FluxSession) -> Self {
139 Self { sess, err: Cell::new(None) }
140 }
141
142 pub fn has_errors(&self) -> bool {
143 self.err.get().is_some()
144 }
145
146 #[track_caller]
147 pub fn emit<'a>(&'a self, err: impl Diagnostic<'a>) -> ErrorGuaranteed {
148 let err = self.sess.emit_err(err);
149 self.err.set(Some(err));
150 err
151 }
152
153 pub fn into_result(self) -> Result<(), ErrorGuaranteed> {
154 if let Some(err) = self.err.into_inner() { Err(err) } else { Ok(()) }
155 }
156}
157
158impl ErrorEmitter for Errors<'_> {
159 #[track_caller]
160 fn emit<'a>(&'a self, err: impl Diagnostic<'a>) -> ErrorGuaranteed {
161 Errors::emit(self, err)
162 }
163}
164
165impl ErrorCollector<ErrorGuaranteed> for Errors<'_> {
166 type Result = Result<(), ErrorGuaranteed>;
167
168 fn collect(&mut self, err: ErrorGuaranteed) {
169 *self.err.get_mut() = Some(err);
170 }
171
172 fn into_result(self) -> Self::Result {
173 Errors::into_result(self)
174 }
175}