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};
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
29// FIXME(nilehmann) We probably need to move out of this error reporting
30pub 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
131/// Convenience struct implementing [`ErrorEmitter`] and [`ErrorCollector`]
132pub 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}