flux_errors/
lib.rs

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