swc_common/errors/
mod.rs

1// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
2// file at the top-level directory of this distribution and at
3// http://rust-lang.org/COPYRIGHT.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
11use std::{
12    borrow::Cow,
13    cell::RefCell,
14    error, fmt,
15    io::Write,
16    panic,
17    sync::atomic::{AtomicUsize, Ordering::SeqCst},
18};
19
20use rustc_hash::FxHashSet;
21#[cfg(feature = "tty-emitter")]
22use termcolor::{Color, ColorSpec};
23
24use self::Level::*;
25pub use self::{
26    diagnostic::{Diagnostic, DiagnosticId, DiagnosticStyledString, SubDiagnostic},
27    diagnostic_builder::DiagnosticBuilder,
28    emitter::{ColorConfig, Emitter, EmitterWriter},
29};
30use crate::{
31    rustc_data_structures::stable_hasher::StableHasher,
32    sync::{Lock, LockCell, Lrc},
33    syntax_pos::{BytePos, FileLinesResult, FileName, Loc, MultiSpan, Span},
34    SpanSnippetError,
35};
36
37mod diagnostic;
38mod diagnostic_builder;
39pub mod emitter;
40mod lock;
41mod snippet;
42mod styled_buffer;
43
44#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
45#[cfg_attr(
46    feature = "diagnostic-serde",
47    derive(serde::Serialize, serde::Deserialize)
48)]
49#[cfg_attr(
50    any(feature = "rkyv-impl"),
51    derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
52)]
53#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
54#[cfg_attr(feature = "rkyv-impl", repr(u32))]
55pub enum Applicability {
56    MachineApplicable,
57    HasPlaceholders,
58    MaybeIncorrect,
59    Unspecified,
60}
61
62#[derive(Clone, Debug, PartialEq, Eq, Hash)]
63#[cfg_attr(
64    feature = "diagnostic-serde",
65    derive(serde::Serialize, serde::Deserialize)
66)]
67#[cfg_attr(
68    any(feature = "rkyv-impl"),
69    derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
70)]
71#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
72#[cfg_attr(feature = "rkyv-impl", repr(C))]
73pub struct CodeSuggestion {
74    /// Each substitute can have multiple variants due to multiple
75    /// applicable suggestions
76    ///
77    /// `foo.bar` might be replaced with `a.b` or `x.y` by replacing
78    /// `foo` and `bar` on their own:
79    ///
80    /// ```rust,ignore
81    /// vec![
82    ///     Substitution {
83    ///         parts: vec![(0..3, "a"), (4..7, "b")],
84    ///     },
85    ///     Substitution {
86    ///         parts: vec![(0..3, "x"), (4..7, "y")],
87    ///     },
88    /// ]
89    /// ```
90    ///
91    /// or by replacing the entire span:
92    ///
93    /// ```rust,ignore
94    /// vec![
95    ///     Substitution {
96    ///         parts: vec![(0..7, "a.b")],
97    ///     },
98    ///     Substitution {
99    ///         parts: vec![(0..7, "x.y")],
100    ///     },
101    /// ]
102    /// ```
103    pub substitutions: Vec<Substitution>,
104    pub msg: String,
105    pub show_code_when_inline: bool,
106    /// Whether or not the suggestion is approximate
107    ///
108    /// Sometimes we may show suggestions with placeholders,
109    /// which are useful for users but not useful for
110    /// tools like rustfix
111    pub applicability: Applicability,
112}
113
114#[derive(Clone, Debug, PartialEq, Eq, Hash)]
115/// See the docs on `CodeSuggestion::substitutions`
116#[cfg_attr(
117    feature = "diagnostic-serde",
118    derive(serde::Serialize, serde::Deserialize)
119)]
120#[cfg_attr(
121    any(feature = "rkyv-impl"),
122    derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
123)]
124#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
125#[cfg_attr(feature = "rkyv-impl", repr(C))]
126pub struct Substitution {
127    pub parts: Vec<SubstitutionPart>,
128}
129
130#[derive(Clone, Debug, PartialEq, Eq, Hash)]
131#[cfg_attr(
132    feature = "diagnostic-serde",
133    derive(serde::Serialize, serde::Deserialize)
134)]
135#[cfg_attr(
136    any(feature = "rkyv-impl"),
137    derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
138)]
139#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
140#[cfg_attr(feature = "rkyv-impl", repr(C))]
141pub struct SubstitutionPart {
142    pub span: Span,
143    pub snippet: String,
144}
145
146pub type SourceMapperDyn = dyn SourceMapper;
147
148pub trait SourceMapper: crate::sync::Send + crate::sync::Sync {
149    fn lookup_char_pos(&self, pos: BytePos) -> Loc;
150    fn span_to_lines(&self, sp: Span) -> FileLinesResult;
151    fn span_to_string(&self, sp: Span) -> String;
152    fn span_to_filename(&self, sp: Span) -> Lrc<FileName>;
153    fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option<Span>;
154    fn call_span_if_macro(&self, sp: Span) -> Span;
155    fn doctest_offset_line(&self, line: usize) -> usize;
156    fn span_to_snippet(&self, sp: Span) -> Result<String, Box<SpanSnippetError>>;
157}
158
159impl CodeSuggestion {
160    /// Returns the assembled code suggestions and whether they should be shown
161    /// with an underline.
162    pub fn splice_lines(&self, cm: &SourceMapperDyn) -> Vec<(String, Vec<SubstitutionPart>)> {
163        use crate::syntax_pos::{CharPos, SmallPos};
164
165        fn push_trailing(
166            buf: &mut String,
167            line_opt: Option<&Cow<'_, str>>,
168            lo: &Loc,
169            hi_opt: Option<&Loc>,
170        ) {
171            let (lo, hi_opt) = (lo.col.to_usize(), hi_opt.map(|hi| hi.col.to_usize()));
172            if let Some(line) = line_opt {
173                if let Some(lo) = line.char_indices().map(|(i, _)| i).nth(lo) {
174                    let hi_opt = hi_opt.and_then(|hi| line.char_indices().map(|(i, _)| i).nth(hi));
175                    buf.push_str(match hi_opt {
176                        Some(hi) => &line[lo..hi],
177                        None => &line[lo..],
178                    });
179                }
180                if hi_opt.is_none() {
181                    buf.push('\n');
182                }
183            }
184        }
185
186        assert!(!self.substitutions.is_empty());
187
188        self.substitutions
189            .iter()
190            .cloned()
191            .map(|mut substitution| {
192                // Assumption: all spans are in the same file, and all spans
193                // are disjoint. Sort in ascending order.
194                substitution.parts.sort_by_key(|part| part.span.lo());
195
196                // Find the bounding span.
197                let lo = substitution
198                    .parts
199                    .iter()
200                    .map(|part| part.span.lo())
201                    .min()
202                    .unwrap();
203                let hi = substitution
204                    .parts
205                    .iter()
206                    .map(|part| part.span.hi())
207                    .min()
208                    .unwrap();
209                let bounding_span = Span::new(lo, hi);
210                let lines = cm.span_to_lines(bounding_span).unwrap();
211                assert!(!lines.lines.is_empty());
212
213                // To build up the result, we do this for each span:
214                // - push the line segment trailing the previous span (at the beginning a
215                //   "phantom" span pointing at the start of the line)
216                // - push lines between the previous and current span (if any)
217                // - if the previous and current span are not on the same line push the line
218                //   segment leading up to the current span
219                // - splice in the span substitution
220                //
221                // Finally push the trailing line segment of the last span
222                let fm = &lines.file;
223                let mut prev_hi = cm.lookup_char_pos(bounding_span.lo());
224                prev_hi.col = CharPos::from_usize(0);
225
226                let mut prev_line = fm.get_line(lines.lines[0].line_index);
227                let mut buf = String::new();
228
229                for part in &substitution.parts {
230                    let cur_lo = cm.lookup_char_pos(part.span.lo());
231                    if prev_hi.line == cur_lo.line {
232                        push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, Some(&cur_lo));
233                    } else {
234                        push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
235                        // push lines between the previous and current span (if any)
236                        for idx in prev_hi.line..(cur_lo.line - 1) {
237                            if let Some(line) = fm.get_line(idx) {
238                                buf.push_str(line.as_ref());
239                                buf.push('\n');
240                            }
241                        }
242                        if let Some(cur_line) = fm.get_line(cur_lo.line - 1) {
243                            buf.push_str(&cur_line[..cur_lo.col.to_usize()]);
244                        }
245                    }
246                    buf.push_str(&part.snippet);
247                    prev_hi = cm.lookup_char_pos(part.span.hi());
248                    prev_line = fm.get_line(prev_hi.line - 1);
249                }
250                // if the replacement already ends with a newline, don't print the next line
251                if !buf.ends_with('\n') {
252                    push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
253                }
254                // remove trailing newlines
255                while buf.ends_with('\n') {
256                    buf.pop();
257                }
258                (buf, substitution.parts)
259            })
260            .collect()
261    }
262}
263
264/// Used as a return value to signify a fatal error occurred. (It is also
265/// used as the argument to panic at the moment, but that will eventually
266/// not be true.)
267#[derive(Copy, Clone, Debug)]
268#[must_use]
269pub struct FatalError;
270
271pub struct FatalErrorMarker;
272
273// // Don't implement Send on FatalError. This makes it impossible to
274// // panic!(FatalError). We don't want to invoke the panic handler and print a
275// // backtrace for fatal errors.
276// impl !Send for FatalError {}
277
278impl FatalError {
279    pub fn raise(self) -> ! {
280        panic::resume_unwind(Box::new(FatalErrorMarker))
281    }
282}
283
284impl fmt::Display for FatalError {
285    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
286        write!(f, "parser fatal error")
287    }
288}
289
290impl error::Error for FatalError {
291    fn description(&self) -> &str {
292        "The parser has encountered a fatal error"
293    }
294}
295
296/// Signifies that the compiler died with an explicit call to `.bug`
297/// or `.span_bug` rather than a failed assertion, etc.
298#[derive(Copy, Clone, Debug)]
299pub struct ExplicitBug;
300
301impl fmt::Display for ExplicitBug {
302    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
303        write!(f, "parser internal bug")
304    }
305}
306
307impl error::Error for ExplicitBug {
308    fn description(&self) -> &str {
309        "The parser has encountered an internal bug"
310    }
311}
312
313/// A handler deals with errors; certain errors
314/// (fatal, bug, unimpl) may cause immediate exit,
315/// others log errors for later reporting.
316///
317/// # Example
318///
319/// `swc` provides a global-like variable ([HANDLER]) of type `Handler` that can
320/// be used to report errors.
321///
322/// You can refer to [the lint rules](https://github.com/swc-project/swc/tree/main/crates/swc_ecma_lints/src/rules) for other example usages.
323/// All lint rules have code for error reporting.
324///
325/// ## Error reporting in swc
326///
327/// ```rust,ignore
328/// use swc_common::errors::HANDLER;
329///
330/// # fn main() {
331///     HANDLER.with(|handler| {
332///         // You can access the handler for the current file using HANDLER.with.
333///
334///         // We now report an error
335///
336///         // `struct_span_err` creates a builder for a diagnostic.
337///         // The span passed to `struct_span_err` will used to point the problematic code.
338///         //
339///         // You may provide additional information, like a previous declaration of parameter.
340///         handler
341///             .struct_span_err(
342///                 span,
343///                 &format!("`{}` used as parameter more than once", atom),
344///             )
345///             .span_note(
346///                 old_span,
347///                 &format!("previous definition of `{}` here", atom),
348///             )
349///             .emit();
350///     });
351/// # }
352/// ```
353pub struct Handler {
354    pub flags: HandlerFlags,
355
356    err_count: AtomicUsize,
357    emitter: Lock<Box<dyn Emitter>>,
358    continue_after_error: LockCell<bool>,
359    delayed_span_bugs: Lock<Vec<Diagnostic>>,
360
361    // This set contains the `DiagnosticId` of all emitted diagnostics to avoid
362    // emitting the same diagnostic with extended help (`--teach`) twice, which
363    // would be unnecessary repetition.
364    taught_diagnostics: Lock<FxHashSet<DiagnosticId>>,
365
366    /// Used to suggest rustc --explain <error code>
367    emitted_diagnostic_codes: Lock<FxHashSet<DiagnosticId>>,
368
369    // This set contains a hash of every diagnostic that has been emitted by
370    // this handler. These hashes is used to avoid emitting the same error
371    // twice.
372    emitted_diagnostics: Lock<FxHashSet<u128>>,
373}
374
375fn default_track_diagnostic(_: &Diagnostic) {}
376
377thread_local!(pub static TRACK_DIAGNOSTICS: RefCell<Box<dyn Fn(&Diagnostic)>> =
378                RefCell::new(Box::new(default_track_diagnostic)));
379
380#[derive(Default)]
381pub struct HandlerFlags {
382    /// If false, warning-level lints are suppressed.
383    /// (rustc: see `--allow warnings` and `--cap-lints`)
384    pub can_emit_warnings: bool,
385    /// If true, error-level diagnostics are upgraded to bug-level.
386    /// (rustc: see `-Z treat-err-as-bug`)
387    pub treat_err_as_bug: bool,
388    /// If true, immediately emit diagnostics that would otherwise be buffered.
389    /// (rustc: see `-Z dont-buffer-diagnostics` and `-Z treat-err-as-bug`)
390    pub dont_buffer_diagnostics: bool,
391    /// If true, immediately print bugs registered with `delay_span_bug`.
392    /// (rustc: see `-Z report-delayed-bugs`)
393    pub report_delayed_bugs: bool,
394    /// show macro backtraces even for non-local macros.
395    /// (rustc: see `-Z external-macro-backtrace`)
396    pub external_macro_backtrace: bool,
397}
398
399impl Drop for Handler {
400    fn drop(&mut self) {
401        if self.err_count() == 0 {
402            let mut bugs = self.delayed_span_bugs.borrow_mut();
403            let has_bugs = !bugs.is_empty();
404            for bug in bugs.drain(..) {
405                DiagnosticBuilder::new_diagnostic(self, bug).emit();
406            }
407            if has_bugs {
408                panic!("no errors encountered even though `delay_span_bug` issued");
409            }
410        }
411    }
412}
413
414impl Handler {
415    #[cfg(feature = "tty-emitter")]
416    #[cfg_attr(docsrs, doc(cfg(feature = "tty-emitter")))]
417    pub fn with_tty_emitter(
418        color_config: ColorConfig,
419        can_emit_warnings: bool,
420        treat_err_as_bug: bool,
421        cm: Option<Lrc<SourceMapperDyn>>,
422    ) -> Handler {
423        Handler::with_tty_emitter_and_flags(
424            color_config,
425            cm,
426            HandlerFlags {
427                can_emit_warnings,
428                treat_err_as_bug,
429                ..Default::default()
430            },
431        )
432    }
433
434    #[cfg(feature = "tty-emitter")]
435    #[cfg_attr(docsrs, doc(cfg(feature = "tty-emitter")))]
436    pub fn with_tty_emitter_and_flags(
437        color_config: ColorConfig,
438        cm: Option<Lrc<SourceMapperDyn>>,
439        flags: HandlerFlags,
440    ) -> Handler {
441        let emitter = Box::new(EmitterWriter::stderr(color_config, cm, false, false));
442        Handler::with_emitter_and_flags(emitter, flags)
443    }
444
445    /// Example implementation of [Emitter] is [EmitterWriter]
446    pub fn with_emitter(
447        can_emit_warnings: bool,
448        treat_err_as_bug: bool,
449        emitter: Box<dyn Emitter>,
450    ) -> Handler {
451        Handler::with_emitter_and_flags(
452            emitter,
453            HandlerFlags {
454                can_emit_warnings,
455                treat_err_as_bug,
456                ..Default::default()
457            },
458        )
459    }
460
461    /// Calls [Self::with_emitter] with [EmitterWriter].
462    pub fn with_emitter_writer(
463        dst: Box<dyn Write + Send>,
464        cm: Option<Lrc<SourceMapperDyn>>,
465    ) -> Handler {
466        Handler::with_emitter(
467            true,
468            false,
469            Box::new(EmitterWriter::new(dst, cm, false, true)),
470        )
471    }
472
473    pub fn with_emitter_and_flags(e: Box<dyn Emitter>, flags: HandlerFlags) -> Handler {
474        Handler {
475            flags,
476            err_count: AtomicUsize::new(0),
477            emitter: Lock::new(e),
478            continue_after_error: LockCell::new(true),
479            delayed_span_bugs: Lock::new(Vec::new()),
480            taught_diagnostics: Default::default(),
481            emitted_diagnostic_codes: Default::default(),
482            emitted_diagnostics: Default::default(),
483        }
484    }
485
486    pub fn set_continue_after_error(&self, continue_after_error: bool) {
487        self.continue_after_error.set(continue_after_error);
488    }
489
490    /// Resets the diagnostic error count as well as the cached emitted
491    /// diagnostics.
492    ///
493    /// NOTE: DO NOT call this function from rustc. It is only meant to be
494    /// called from external tools that want to reuse a `Parser` cleaning
495    /// the previously emitted diagnostics as well as the overall count of
496    /// emitted error diagnostics.
497    pub fn reset_err_count(&self) {
498        // actually frees the underlying memory (which `clear` would not do)
499        *self.emitted_diagnostics.borrow_mut() = Default::default();
500        self.err_count.store(0, SeqCst);
501    }
502
503    pub fn struct_dummy(&self) -> DiagnosticBuilder<'_> {
504        DiagnosticBuilder::new(self, Level::Cancelled, "")
505    }
506
507    pub fn struct_span_warn<'a, S: Into<MultiSpan>>(
508        &'a self,
509        sp: S,
510        msg: &str,
511    ) -> DiagnosticBuilder<'a> {
512        let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
513        result.set_span(sp);
514        if !self.flags.can_emit_warnings {
515            result.cancel();
516        }
517        result
518    }
519
520    pub fn struct_span_warn_with_code<'a, S: Into<MultiSpan>>(
521        &'a self,
522        sp: S,
523        msg: &str,
524        code: DiagnosticId,
525    ) -> DiagnosticBuilder<'a> {
526        let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
527        result.set_span(sp);
528        result.code(code);
529        if !self.flags.can_emit_warnings {
530            result.cancel();
531        }
532        result
533    }
534
535    pub fn struct_warn<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
536        let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
537        if !self.flags.can_emit_warnings {
538            result.cancel();
539        }
540        result
541    }
542
543    pub fn struct_span_err<'a, S: Into<MultiSpan>>(
544        &'a self,
545        sp: S,
546        msg: &str,
547    ) -> DiagnosticBuilder<'a> {
548        let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
549        result.set_span(sp);
550        result
551    }
552
553    pub fn struct_span_err_with_code<'a, S: Into<MultiSpan>>(
554        &'a self,
555        sp: S,
556        msg: &str,
557        code: DiagnosticId,
558    ) -> DiagnosticBuilder<'a> {
559        let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
560        result.set_span(sp);
561        result.code(code);
562        result
563    }
564
565    // FIXME: This method should be removed (every error should have an associated
566    // error code).
567    pub fn struct_err<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
568        DiagnosticBuilder::new(self, Level::Error, msg)
569    }
570
571    pub fn struct_err_with_code<'a>(
572        &'a self,
573        msg: &str,
574        code: DiagnosticId,
575    ) -> DiagnosticBuilder<'a> {
576        let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
577        result.code(code);
578        result
579    }
580
581    pub fn struct_span_fatal<'a, S: Into<MultiSpan>>(
582        &'a self,
583        sp: S,
584        msg: &str,
585    ) -> DiagnosticBuilder<'a> {
586        let mut result = DiagnosticBuilder::new(self, Level::Fatal, msg);
587        result.set_span(sp);
588        result
589    }
590
591    pub fn struct_span_fatal_with_code<'a, S: Into<MultiSpan>>(
592        &'a self,
593        sp: S,
594        msg: &str,
595        code: DiagnosticId,
596    ) -> DiagnosticBuilder<'a> {
597        let mut result = DiagnosticBuilder::new(self, Level::Fatal, msg);
598        result.set_span(sp);
599        result.code(code);
600        result
601    }
602
603    pub fn struct_fatal<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
604        DiagnosticBuilder::new(self, Level::Fatal, msg)
605    }
606
607    pub fn cancel(&self, err: &mut DiagnosticBuilder<'_>) {
608        err.cancel();
609    }
610
611    fn panic_if_treat_err_as_bug(&self) {
612        if self.flags.treat_err_as_bug {
613            panic!("encountered error with `-Z treat_err_as_bug");
614        }
615    }
616
617    pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> FatalError {
618        self.emit(&sp.into(), msg, Fatal);
619        FatalError
620    }
621
622    pub fn span_fatal_with_code<S: Into<MultiSpan>>(
623        &self,
624        sp: S,
625        msg: &str,
626        code: DiagnosticId,
627    ) -> FatalError {
628        self.emit_with_code(&sp.into(), msg, code, Fatal);
629        FatalError
630    }
631
632    pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
633        self.emit(&sp.into(), msg, Error);
634    }
635
636    pub fn mut_span_err<'a, S: Into<MultiSpan>>(
637        &'a self,
638        sp: S,
639        msg: &str,
640    ) -> DiagnosticBuilder<'a> {
641        let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
642        result.set_span(sp);
643        result
644    }
645
646    pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: DiagnosticId) {
647        self.emit_with_code(&sp.into(), msg, code, Error);
648    }
649
650    pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
651        self.emit(&sp.into(), msg, Warning);
652    }
653
654    pub fn span_warn_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: DiagnosticId) {
655        self.emit_with_code(&sp.into(), msg, code, Warning);
656    }
657
658    pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
659        self.emit(&sp.into(), msg, Bug);
660        panic!("{}", ExplicitBug);
661    }
662
663    pub fn delay_span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
664        if self.flags.treat_err_as_bug {
665            // FIXME: don't abort here if report_delayed_bugs is off
666            self.span_bug(sp, msg);
667        }
668        let mut diagnostic = Diagnostic::new(Level::Bug, msg);
669        diagnostic.set_span(sp.into());
670        self.delay_as_bug(diagnostic);
671    }
672
673    fn delay_as_bug(&self, diagnostic: Diagnostic) {
674        if self.flags.report_delayed_bugs {
675            DiagnosticBuilder::new_diagnostic(self, diagnostic.clone()).emit();
676        }
677        self.delayed_span_bugs.borrow_mut().push(diagnostic);
678    }
679
680    pub fn span_bug_no_panic<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
681        self.emit(&sp.into(), msg, Bug);
682    }
683
684    pub fn span_note_without_error<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
685        self.emit(&sp.into(), msg, Note);
686    }
687
688    pub fn span_note_diag<'a>(&'a self, sp: Span, msg: &str) -> DiagnosticBuilder<'a> {
689        let mut db = DiagnosticBuilder::new(self, Note, msg);
690        db.set_span(sp);
691        db
692    }
693
694    pub fn span_unimpl<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
695        self.span_bug(sp, &format!("unimplemented {}", msg));
696    }
697
698    pub fn failure(&self, msg: &str) {
699        DiagnosticBuilder::new(self, FailureNote, msg).emit()
700    }
701
702    pub fn fatal(&self, msg: &str) -> FatalError {
703        if self.flags.treat_err_as_bug {
704            self.bug(msg);
705        }
706        DiagnosticBuilder::new(self, Fatal, msg).emit();
707        FatalError
708    }
709
710    pub fn err(&self, msg: &str) {
711        if self.flags.treat_err_as_bug {
712            self.bug(msg);
713        }
714        let mut db = DiagnosticBuilder::new(self, Error, msg);
715        db.emit();
716    }
717
718    pub fn warn(&self, msg: &str) {
719        let mut db = DiagnosticBuilder::new(self, Warning, msg);
720        db.emit();
721    }
722
723    pub fn note_without_error(&self, msg: &str) {
724        let mut db = DiagnosticBuilder::new(self, Note, msg);
725        db.emit();
726    }
727
728    pub fn bug(&self, msg: &str) -> ! {
729        let mut db = DiagnosticBuilder::new(self, Bug, msg);
730        db.emit();
731        panic!("{}", ExplicitBug);
732    }
733
734    pub fn unimpl(&self, msg: &str) -> ! {
735        self.bug(&format!("unimplemented {}", msg));
736    }
737
738    fn bump_err_count(&self) {
739        self.panic_if_treat_err_as_bug();
740        self.err_count.fetch_add(1, SeqCst);
741    }
742
743    pub fn err_count(&self) -> usize {
744        self.err_count.load(SeqCst)
745    }
746
747    pub fn has_errors(&self) -> bool {
748        self.err_count() > 0
749    }
750
751    pub fn print_error_count(&self) {
752        let s = match self.err_count() {
753            0 => return,
754            1 => "aborting due to previous error".to_string(),
755            _ => format!("aborting due to {} previous errors", self.err_count()),
756        };
757
758        let _ = self.fatal(&s);
759
760        let can_show_explain = self.emitter.borrow().should_show_explain();
761        let are_there_diagnostics = !self.emitted_diagnostic_codes.borrow().is_empty();
762        if can_show_explain && are_there_diagnostics {
763            let mut error_codes = self
764                .emitted_diagnostic_codes
765                .borrow()
766                .iter()
767                .filter_map(|x| match *x {
768                    DiagnosticId::Error(ref s) => Some(s.clone()),
769                    _ => None,
770                })
771                .collect::<Vec<_>>();
772            if !error_codes.is_empty() {
773                error_codes.sort();
774                if error_codes.len() > 1 {
775                    let limit = if error_codes.len() > 9 {
776                        9
777                    } else {
778                        error_codes.len()
779                    };
780                    self.failure(&format!(
781                        "Some errors occurred: {}{}",
782                        error_codes[..limit].join(", "),
783                        if error_codes.len() > 9 { "..." } else { "." }
784                    ));
785                    self.failure(&format!(
786                        "For more information about an error, try `rustc --explain {}`.",
787                        &error_codes[0]
788                    ));
789                } else {
790                    self.failure(&format!(
791                        "For more information about this error, try `rustc --explain {}`.",
792                        &error_codes[0]
793                    ));
794                }
795            }
796        }
797    }
798
799    pub fn abort_if_errors(&self) {
800        if self.err_count() == 0 {
801            return;
802        }
803        FatalError.raise();
804    }
805
806    pub fn emit(&self, msp: &MultiSpan, msg: &str, lvl: Level) {
807        if lvl == Warning && !self.flags.can_emit_warnings {
808            return;
809        }
810        let mut db = DiagnosticBuilder::new(self, lvl, msg);
811        db.set_span(msp.clone());
812        db.emit();
813        if !self.continue_after_error.get() {
814            self.abort_if_errors();
815        }
816    }
817
818    pub fn emit_with_code(&self, msp: &MultiSpan, msg: &str, code: DiagnosticId, lvl: Level) {
819        if lvl == Warning && !self.flags.can_emit_warnings {
820            return;
821        }
822        let mut db = DiagnosticBuilder::new_with_code(self, lvl, Some(code), msg);
823        db.set_span(msp.clone());
824        db.emit();
825        if !self.continue_after_error.get() {
826            self.abort_if_errors();
827        }
828    }
829
830    /// `true` if we haven't taught a diagnostic with this code already.
831    /// The caller must then teach the user about such a diagnostic.
832    ///
833    /// Used to suppress emitting the same error multiple times with extended
834    /// explanation when calling `-Z teach`.
835    pub fn must_teach(&self, code: &DiagnosticId) -> bool {
836        self.taught_diagnostics.borrow_mut().insert(code.clone())
837    }
838
839    pub fn force_print_db(&self, mut db: DiagnosticBuilder<'_>) {
840        self.emitter.borrow_mut().emit(&db);
841        db.cancel();
842    }
843
844    fn emit_db(&self, db: &DiagnosticBuilder<'_>) {
845        let diagnostic = &**db;
846
847        TRACK_DIAGNOSTICS.with(|track_diagnostics| {
848            track_diagnostics.borrow()(diagnostic);
849        });
850
851        if let Some(ref code) = diagnostic.code {
852            self.emitted_diagnostic_codes
853                .borrow_mut()
854                .insert(code.clone());
855        }
856
857        let diagnostic_hash = {
858            use std::hash::Hash;
859            let mut hasher = StableHasher::new();
860            diagnostic.hash(&mut hasher);
861            hasher.finish()
862        };
863
864        // Only emit the diagnostic if we haven't already emitted an equivalent
865        // one:
866        if self
867            .emitted_diagnostics
868            .borrow_mut()
869            .insert(diagnostic_hash)
870        {
871            self.emitter.borrow_mut().emit(db);
872            if db.is_error() {
873                self.bump_err_count();
874            }
875        }
876    }
877
878    pub fn take_diagnostics(&self) -> Vec<String> {
879        self.emitter.borrow_mut().take_diagnostics()
880    }
881}
882
883#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)]
884#[cfg_attr(
885    feature = "diagnostic-serde",
886    derive(serde::Serialize, serde::Deserialize)
887)]
888#[cfg_attr(
889    any(feature = "rkyv-impl"),
890    derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
891)]
892#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
893#[cfg_attr(feature = "rkyv-impl", repr(u32))]
894pub enum Level {
895    Bug,
896    Fatal,
897    // An error which while not immediately fatal, should stop the compiler
898    // progressing beyond the current phase.
899    PhaseFatal,
900    Error,
901    Warning,
902    Note,
903    Help,
904    Cancelled,
905    FailureNote,
906}
907
908impl fmt::Display for Level {
909    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
910        self.to_str().fmt(f)
911    }
912}
913
914impl Level {
915    #[cfg(feature = "tty-emitter")]
916    fn color(self) -> ColorSpec {
917        let mut spec = ColorSpec::new();
918        match self {
919            Bug | Fatal | PhaseFatal | Error => {
920                spec.set_fg(Some(Color::Red)).set_intense(true);
921            }
922            Warning => {
923                spec.set_fg(Some(Color::Yellow)).set_intense(cfg!(windows));
924            }
925            Note => {
926                spec.set_fg(Some(Color::Green)).set_intense(true);
927            }
928            Help => {
929                spec.set_fg(Some(Color::Cyan)).set_intense(true);
930            }
931            FailureNote => {}
932            Cancelled => unreachable!(),
933        }
934        spec
935    }
936
937    pub fn to_str(self) -> &'static str {
938        match self {
939            Bug => "error: internal compiler error",
940            Fatal | PhaseFatal | Error => "error",
941            Warning => "warning",
942            Note => "note",
943            Help => "help",
944            FailureNote => "",
945            Cancelled => panic!("Shouldn't call on cancelled error"),
946        }
947    }
948
949    pub fn is_failure_note(self) -> bool {
950        matches!(self, FailureNote)
951    }
952}
953
954better_scoped_tls::scoped_tls!(
955    /// Used for error reporting in transform.
956    ///
957    /// This should be only used for errors from the api which does not returning errors.
958    ///
959    /// e.g.
960    ///  - `parser` should not use this.
961    ///  - `transforms` should use this to report error, as it does not return [Result].
962    ///
963    /// See [Handler] for actual usage examples.
964    pub static HANDLER: Handler
965);