]> git.lizzy.rs Git - rust.git/blob - src/librustc_errors/lib.rs
8ee28875c625931bd277ad2cb8814aa854cc686d
[rust.git] / src / librustc_errors / lib.rs
1 //! Diagnostics creation and emission for `rustc`.
2 //!
3 //! This module contains the code for creating and emitting diagnostics.
4
5 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
6
7 #![feature(crate_visibility_modifier)]
8 #![cfg_attr(unix, feature(libc))]
9 #![feature(nll)]
10 #![feature(optin_builtin_traits)]
11
12 pub use emitter::ColorConfig;
13
14 use Level::*;
15
16 use emitter::{Emitter, EmitterWriter, is_case_difference};
17 use registry::Registry;
18 use rustc_data_structures::sync::{self, Lrc, Lock};
19 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
20 use rustc_data_structures::stable_hasher::StableHasher;
21
22 use std::borrow::Cow;
23 use std::cell::Cell;
24 use std::{error, fmt};
25 use std::panic;
26 use std::path::Path;
27
28 use termcolor::{ColorSpec, Color};
29
30 mod diagnostic;
31 mod diagnostic_builder;
32 pub mod emitter;
33 pub mod annotate_snippet_emitter_writer;
34 mod snippet;
35 pub mod registry;
36 mod styled_buffer;
37 mod lock;
38
39 use syntax_pos::{
40     BytePos,
41     FileLinesResult,
42     FileName,
43     Loc,
44     MultiSpan,
45     SourceFile,
46     Span,
47     SpanSnippetError,
48 };
49
50 pub type PResult<'a, T> = Result<T, DiagnosticBuilder<'a>>;
51
52 // `PResult` is used a lot. Make sure it doesn't unintentionally get bigger.
53 // (See also the comment on `DiagnosticBuilderInner`.)
54 #[cfg(target_arch = "x86_64")]
55 rustc_data_structures::static_assert_size!(PResult<'_, bool>, 16);
56
57 /// Indicates the confidence in the correctness of a suggestion.
58 ///
59 /// All suggestions are marked with an `Applicability`. Tools use the applicability of a suggestion
60 /// to determine whether it should be automatically applied or if the user should be consulted
61 /// before applying the suggestion.
62 #[derive(Copy, Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
63 pub enum Applicability {
64     /// The suggestion is definitely what the user intended. This suggestion should be
65     /// automatically applied.
66     MachineApplicable,
67
68     /// The suggestion may be what the user intended, but it is uncertain. The suggestion should
69     /// result in valid Rust code if it is applied.
70     MaybeIncorrect,
71
72     /// The suggestion contains placeholders like `(...)` or `{ /* fields */ }`. The suggestion
73     /// cannot be applied automatically because it will not result in valid Rust code. The user
74     /// will need to fill in the placeholders.
75     HasPlaceholders,
76
77     /// The applicability of the suggestion is unknown.
78     Unspecified,
79 }
80
81 #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, RustcEncodable, RustcDecodable)]
82 pub enum SuggestionStyle {
83     /// Hide the suggested code when displaying this suggestion inline.
84     HideCodeInline,
85     /// Always hide the suggested code but display the message.
86     HideCodeAlways,
87     /// Do not display this suggestion in the cli output, it is only meant for tools.
88     CompletelyHidden,
89     /// Always show the suggested code.
90     /// This will *not* show the code if the suggestion is inline *and* the suggested code is
91     /// empty.
92     ShowCode,
93     /// Always show the suggested code independently.
94     ShowAlways,
95 }
96
97 impl SuggestionStyle {
98     fn hide_inline(&self) -> bool {
99         match *self {
100             SuggestionStyle::ShowCode => false,
101             _ => true,
102         }
103     }
104 }
105
106 #[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
107 pub struct CodeSuggestion {
108     /// Each substitute can have multiple variants due to multiple
109     /// applicable suggestions
110     ///
111     /// `foo.bar` might be replaced with `a.b` or `x.y` by replacing
112     /// `foo` and `bar` on their own:
113     ///
114     /// ```
115     /// vec![
116     ///     Substitution { parts: vec![(0..3, "a"), (4..7, "b")] },
117     ///     Substitution { parts: vec![(0..3, "x"), (4..7, "y")] },
118     /// ]
119     /// ```
120     ///
121     /// or by replacing the entire span:
122     ///
123     /// ```
124     /// vec![
125     ///     Substitution { parts: vec![(0..7, "a.b")] },
126     ///     Substitution { parts: vec![(0..7, "x.y")] },
127     /// ]
128     /// ```
129     pub substitutions: Vec<Substitution>,
130     pub msg: String,
131     /// Visual representation of this suggestion.
132     pub style: SuggestionStyle,
133     /// Whether or not the suggestion is approximate
134     ///
135     /// Sometimes we may show suggestions with placeholders,
136     /// which are useful for users but not useful for
137     /// tools like rustfix
138     pub applicability: Applicability,
139 }
140
141 #[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
142 /// See the docs on `CodeSuggestion::substitutions`
143 pub struct Substitution {
144     pub parts: Vec<SubstitutionPart>,
145 }
146
147 #[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
148 pub struct SubstitutionPart {
149     pub span: Span,
150     pub snippet: String,
151 }
152
153 pub type SourceMapperDyn = dyn SourceMapper + sync::Send + sync::Sync;
154
155 pub trait SourceMapper {
156     fn lookup_char_pos(&self, pos: BytePos) -> Loc;
157     fn span_to_lines(&self, sp: Span) -> FileLinesResult;
158     fn span_to_string(&self, sp: Span) -> String;
159     fn span_to_snippet(&self, sp: Span) -> Result<String, SpanSnippetError>;
160     fn span_to_filename(&self, sp: Span) -> FileName;
161     fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option<Span>;
162     fn call_span_if_macro(&self, sp: Span) -> Span;
163     fn ensure_source_file_source_present(&self, source_file: Lrc<SourceFile>) -> bool;
164     fn doctest_offset_line(&self, file: &FileName, line: usize) -> usize;
165 }
166
167 impl CodeSuggestion {
168     /// Returns the assembled code suggestions, whether they should be shown with an underline
169     /// and whether the substitution only differs in capitalization.
170     pub fn splice_lines(
171         &self,
172         cm: &SourceMapperDyn,
173     ) -> Vec<(String, Vec<SubstitutionPart>, bool)> {
174         use syntax_pos::{CharPos, Pos};
175
176         fn push_trailing(buf: &mut String,
177                          line_opt: Option<&Cow<'_, str>>,
178                          lo: &Loc,
179                          hi_opt: Option<&Loc>) {
180             let (lo, hi_opt) = (lo.col.to_usize(), hi_opt.map(|hi| hi.col.to_usize()));
181             if let Some(line) = line_opt {
182                 if let Some(lo) = line.char_indices().map(|(i, _)| i).nth(lo) {
183                     let hi_opt = hi_opt.and_then(|hi| line.char_indices().map(|(i, _)| i).nth(hi));
184                     match hi_opt {
185                         Some(hi) if hi > lo => buf.push_str(&line[lo..hi]),
186                         Some(_) => (),
187                         None => buf.push_str(&line[lo..]),
188                     }
189                 }
190                 if let None = hi_opt {
191                     buf.push('\n');
192                 }
193             }
194         }
195
196         assert!(!self.substitutions.is_empty());
197
198         self.substitutions.iter().cloned().map(|mut substitution| {
199             // Assumption: all spans are in the same file, and all spans
200             // are disjoint. Sort in ascending order.
201             substitution.parts.sort_by_key(|part| part.span.lo());
202
203             // Find the bounding span.
204             let lo = substitution.parts.iter().map(|part| part.span.lo()).min().unwrap();
205             let hi = substitution.parts.iter().map(|part| part.span.hi()).min().unwrap();
206             let bounding_span = Span::with_root_ctxt(lo, hi);
207             let lines = cm.span_to_lines(bounding_span).unwrap();
208             assert!(!lines.lines.is_empty());
209
210             // To build up the result, we do this for each span:
211             // - push the line segment trailing the previous span
212             //   (at the beginning a "phantom" span pointing at the start of the line)
213             // - push lines between the previous and current span (if any)
214             // - if the previous and current span are not on the same line
215             //   push the line segment leading up to the current span
216             // - splice in the span substitution
217             //
218             // Finally push the trailing line segment of the last span
219             let fm = &lines.file;
220             let mut prev_hi = cm.lookup_char_pos(bounding_span.lo());
221             prev_hi.col = CharPos::from_usize(0);
222
223             let mut prev_line = fm.get_line(lines.lines[0].line_index);
224             let mut buf = String::new();
225
226             for part in &substitution.parts {
227                 let cur_lo = cm.lookup_char_pos(part.span.lo());
228                 if prev_hi.line == cur_lo.line {
229                     push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, Some(&cur_lo));
230                 } else {
231                     push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
232                     // push lines between the previous and current span (if any)
233                     for idx in prev_hi.line..(cur_lo.line - 1) {
234                         if let Some(line) = fm.get_line(idx) {
235                             buf.push_str(line.as_ref());
236                             buf.push('\n');
237                         }
238                     }
239                     if let Some(cur_line) = fm.get_line(cur_lo.line - 1) {
240                         let end = std::cmp::min(cur_line.len(), cur_lo.col.to_usize());
241                         buf.push_str(&cur_line[..end]);
242                     }
243                 }
244                 buf.push_str(&part.snippet);
245                 prev_hi = cm.lookup_char_pos(part.span.hi());
246                 prev_line = fm.get_line(prev_hi.line - 1);
247             }
248             let only_capitalization = is_case_difference(cm, &buf, bounding_span);
249             // if the replacement already ends with a newline, don't print the next line
250             if !buf.ends_with('\n') {
251                 push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
252             }
253             // remove trailing newlines
254             while buf.ends_with('\n') {
255                 buf.pop();
256             }
257             (buf, substitution.parts, only_capitalization)
258         }).collect()
259     }
260 }
261
262 /// Used as a return value to signify a fatal error occurred. (It is also
263 /// used as the argument to panic at the moment, but that will eventually
264 /// not be true.)
265 #[derive(Copy, Clone, Debug)]
266 #[must_use]
267 pub struct FatalError;
268
269 pub struct FatalErrorMarker;
270
271 // Don't implement Send on FatalError. This makes it impossible to panic!(FatalError).
272 // We don't want to invoke the panic handler and print a backtrace for fatal errors.
273 impl !Send for FatalError {}
274
275 impl FatalError {
276     pub fn raise(self) -> ! {
277         panic::resume_unwind(Box::new(FatalErrorMarker))
278     }
279 }
280
281 impl fmt::Display for FatalError {
282     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
283         write!(f, "parser fatal error")
284     }
285 }
286
287 impl error::Error for FatalError {
288     fn description(&self) -> &str {
289         "The parser has encountered a fatal error"
290     }
291 }
292
293 /// Signifies that the compiler died with an explicit call to `.bug`
294 /// or `.span_bug` rather than a failed assertion, etc.
295 #[derive(Copy, Clone, Debug)]
296 pub struct ExplicitBug;
297
298 impl fmt::Display for ExplicitBug {
299     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
300         write!(f, "parser internal bug")
301     }
302 }
303
304 impl error::Error for ExplicitBug {
305     fn description(&self) -> &str {
306         "The parser has encountered an internal bug"
307     }
308 }
309
310 pub use diagnostic::{Diagnostic, SubDiagnostic, DiagnosticStyledString, DiagnosticId};
311 pub use diagnostic_builder::DiagnosticBuilder;
312
313 /// A handler deals with errors and other compiler output.
314 /// Certain errors (fatal, bug, unimpl) may cause immediate exit,
315 /// others log errors for later reporting.
316 pub struct Handler {
317     flags: HandlerFlags,
318     inner: Lock<HandlerInner>,
319 }
320
321 /// This inner struct exists to keep it all behind a single lock;
322 /// this is done to prevent possible deadlocks in a multi-threaded compiler,
323 /// as well as inconsistent state observation.
324 struct HandlerInner {
325     flags: HandlerFlags,
326     /// The number of errors that have been emitted, including duplicates.
327     ///
328     /// This is not necessarily the count that's reported to the user once
329     /// compilation ends.
330     err_count: usize,
331     deduplicated_err_count: usize,
332     emitter: Box<dyn Emitter + sync::Send>,
333     continue_after_error: bool,
334     delayed_span_bugs: Vec<Diagnostic>,
335
336     /// This set contains the `DiagnosticId` of all emitted diagnostics to avoid
337     /// emitting the same diagnostic with extended help (`--teach`) twice, which
338     /// would be uneccessary repetition.
339     taught_diagnostics: FxHashSet<DiagnosticId>,
340
341     /// Used to suggest rustc --explain <error code>
342     emitted_diagnostic_codes: FxHashSet<DiagnosticId>,
343
344     /// This set contains a hash of every diagnostic that has been emitted by
345     /// this handler. These hashes is used to avoid emitting the same error
346     /// twice.
347     emitted_diagnostics: FxHashSet<u128>,
348
349     /// Stashed diagnostics emitted in one stage of the compiler that may be
350     /// stolen by other stages (e.g. to improve them and add more information).
351     /// The stashed diagnostics count towards the total error count.
352     /// When `.abort_if_errors()` is called, these are also emitted.
353     stashed_diagnostics: FxIndexMap<(Span, StashKey), Diagnostic>,
354 }
355
356 /// A key denoting where from a diagnostic was stashed.
357 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
358 pub enum StashKey {
359     ItemNoType,
360 }
361
362 fn default_track_diagnostic(_: &Diagnostic) {}
363
364 thread_local!(pub static TRACK_DIAGNOSTICS: Cell<fn(&Diagnostic)> =
365                 Cell::new(default_track_diagnostic));
366
367 #[derive(Copy, Clone, Default)]
368 pub struct HandlerFlags {
369     /// If false, warning-level lints are suppressed.
370     /// (rustc: see `--allow warnings` and `--cap-lints`)
371     pub can_emit_warnings: bool,
372     /// If true, error-level diagnostics are upgraded to bug-level.
373     /// (rustc: see `-Z treat-err-as-bug`)
374     pub treat_err_as_bug: Option<usize>,
375     /// If true, immediately emit diagnostics that would otherwise be buffered.
376     /// (rustc: see `-Z dont-buffer-diagnostics` and `-Z treat-err-as-bug`)
377     pub dont_buffer_diagnostics: bool,
378     /// If true, immediately print bugs registered with `delay_span_bug`.
379     /// (rustc: see `-Z report-delayed-bugs`)
380     pub report_delayed_bugs: bool,
381     /// show macro backtraces even for non-local macros.
382     /// (rustc: see `-Z external-macro-backtrace`)
383     pub external_macro_backtrace: bool,
384 }
385
386 impl Drop for HandlerInner {
387     fn drop(&mut self) {
388         self.emit_stashed_diagnostics();
389
390         if !self.has_errors() {
391             let bugs = std::mem::replace(&mut self.delayed_span_bugs, Vec::new());
392             let has_bugs = !bugs.is_empty();
393             for bug in bugs {
394                 self.emit_diagnostic(&bug);
395             }
396             if has_bugs {
397                 panic!("no errors encountered even though `delay_span_bug` issued");
398             }
399         }
400     }
401 }
402
403 impl Handler {
404     pub fn with_tty_emitter(
405         color_config: ColorConfig,
406         can_emit_warnings: bool,
407         treat_err_as_bug: Option<usize>,
408         cm: Option<Lrc<SourceMapperDyn>>,
409     ) -> Self {
410         Self::with_tty_emitter_and_flags(
411             color_config,
412             cm,
413             HandlerFlags {
414                 can_emit_warnings,
415                 treat_err_as_bug,
416                 .. Default::default()
417             },
418         )
419     }
420
421     pub fn with_tty_emitter_and_flags(
422         color_config: ColorConfig,
423         cm: Option<Lrc<SourceMapperDyn>>,
424         flags: HandlerFlags,
425     ) -> Self {
426         let emitter = Box::new(EmitterWriter::stderr(
427             color_config,
428             cm,
429             false,
430             false,
431             None,
432             flags.external_macro_backtrace,
433         ));
434         Self::with_emitter_and_flags(emitter, flags)
435     }
436
437     pub fn with_emitter(
438         can_emit_warnings: bool,
439         treat_err_as_bug: Option<usize>,
440         emitter: Box<dyn Emitter + sync::Send>,
441     ) -> Self {
442         Handler::with_emitter_and_flags(
443             emitter,
444             HandlerFlags {
445                 can_emit_warnings,
446                 treat_err_as_bug,
447                 .. Default::default()
448             },
449         )
450     }
451
452     pub fn with_emitter_and_flags(
453         emitter: Box<dyn Emitter + sync::Send>,
454         flags: HandlerFlags
455     ) -> Self {
456         Self {
457             flags,
458             inner: Lock::new(HandlerInner {
459                 flags,
460                 err_count: 0,
461                 deduplicated_err_count: 0,
462                 emitter,
463                 continue_after_error: true,
464                 delayed_span_bugs: Vec::new(),
465                 taught_diagnostics: Default::default(),
466                 emitted_diagnostic_codes: Default::default(),
467                 emitted_diagnostics: Default::default(),
468                 stashed_diagnostics: Default::default(),
469             }),
470         }
471     }
472
473     pub fn set_continue_after_error(&self, continue_after_error: bool) {
474         self.inner.borrow_mut().continue_after_error = continue_after_error;
475     }
476
477     // This is here to not allow mutation of flags;
478     // as of this writing it's only used in tests in librustc.
479     pub fn can_emit_warnings(&self) -> bool {
480         self.flags.can_emit_warnings
481     }
482
483     /// Resets the diagnostic error count as well as the cached emitted diagnostics.
484     ///
485     /// NOTE: *do not* call this function from rustc. It is only meant to be called from external
486     /// tools that want to reuse a `Parser` cleaning the previously emitted diagnostics as well as
487     /// the overall count of emitted error diagnostics.
488     pub fn reset_err_count(&self) {
489         let mut inner = self.inner.borrow_mut();
490         inner.err_count = 0;
491         inner.deduplicated_err_count = 0;
492
493         // actually free the underlying memory (which `clear` would not do)
494         inner.delayed_span_bugs = Default::default();
495         inner.taught_diagnostics = Default::default();
496         inner.emitted_diagnostic_codes = Default::default();
497         inner.emitted_diagnostics = Default::default();
498         inner.stashed_diagnostics = Default::default();
499     }
500
501     /// Stash a given diagnostic with the given `Span` and `StashKey` as the key for later stealing.
502     /// If the diagnostic with this `(span, key)` already exists, this will result in an ICE.
503     pub fn stash_diagnostic(&self, span: Span, key: StashKey, diag: Diagnostic) {
504         let mut inner = self.inner.borrow_mut();
505         if let Some(mut old_diag) = inner.stashed_diagnostics.insert((span, key), diag) {
506             // We are removing a previously stashed diagnostic which should not happen.
507             old_diag.level = Bug;
508             old_diag.note(&format!(
509                 "{}:{}: already existing stashed diagnostic with (span = {:?}, key = {:?})",
510                 file!(), line!(), span, key
511             ));
512             inner.emit_diag_at_span(old_diag, span);
513             panic!(ExplicitBug);
514         }
515     }
516
517     /// Steal a previously stashed diagnostic with the given `Span` and `StashKey` as the key.
518     pub fn steal_diagnostic(&self, span: Span, key: StashKey) -> Option<DiagnosticBuilder<'_>> {
519         self.inner
520             .borrow_mut()
521             .stashed_diagnostics
522             .remove(&(span, key))
523             .map(|diag| DiagnosticBuilder::new_diagnostic(self, diag))
524     }
525
526     /// Emit all stashed diagnostics.
527     pub fn emit_stashed_diagnostics(&self) {
528         self.inner.borrow_mut().emit_stashed_diagnostics();
529     }
530
531     /// Construct a dummy builder with `Level::Cancelled`.
532     ///
533     /// Using this will neither report anything to the user (e.g. a warning),
534     /// nor will compilation cancel as a result.
535     pub fn struct_dummy(&self) -> DiagnosticBuilder<'_> {
536         DiagnosticBuilder::new(self, Level::Cancelled, "")
537     }
538
539     /// Construct a builder at the `Warning` level at the given `span` and with the `msg`.
540     pub fn struct_span_warn(&self, span: impl Into<MultiSpan>, msg: &str) -> DiagnosticBuilder<'_> {
541         let mut result = self.struct_warn(msg);
542         result.set_span(span);
543         result
544     }
545
546     /// Construct a builder at the `Warning` level at the given `span` and with the `msg`.
547     /// Also include a code.
548     pub fn struct_span_warn_with_code(
549         &self,
550         span: impl Into<MultiSpan>,
551         msg: &str,
552         code: DiagnosticId,
553     ) -> DiagnosticBuilder<'_> {
554         let mut result = self.struct_span_warn(span, msg);
555         result.code(code);
556         result
557     }
558
559     /// Construct a builder at the `Warning` level with the `msg`.
560     pub fn struct_warn(&self, msg: &str) -> DiagnosticBuilder<'_> {
561         let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
562         if !self.flags.can_emit_warnings {
563             result.cancel();
564         }
565         result
566     }
567
568     /// Construct a builder at the `Error` level at the given `span` and with the `msg`.
569     pub fn struct_span_err(&self, span: impl Into<MultiSpan>, msg: &str) -> DiagnosticBuilder<'_> {
570         let mut result = self.struct_err(msg);
571         result.set_span(span);
572         result
573     }
574
575     /// Construct a builder at the `Error` level at the given `span`, with the `msg`, and `code`.
576     pub fn struct_span_err_with_code(
577         &self,
578         span: impl Into<MultiSpan>,
579         msg: &str,
580         code: DiagnosticId,
581     ) -> DiagnosticBuilder<'_> {
582         let mut result = self.struct_span_err(span, msg);
583         result.code(code);
584         result
585     }
586
587     /// Construct a builder at the `Error` level with the `msg`.
588     // FIXME: This method should be removed (every error should have an associated error code).
589     pub fn struct_err(&self, msg: &str) -> DiagnosticBuilder<'_> {
590         DiagnosticBuilder::new(self, Level::Error, msg)
591     }
592
593     /// Construct a builder at the `Error` level with the `msg` and the `code`.
594     pub fn struct_err_with_code(&self, msg: &str, code: DiagnosticId) -> DiagnosticBuilder<'_> {
595         let mut result = self.struct_err(msg);
596         result.code(code);
597         result
598     }
599
600     /// Construct a builder at the `Fatal` level at the given `span` and with the `msg`.
601     pub fn struct_span_fatal(
602         &self,
603         span: impl Into<MultiSpan>,
604         msg: &str,
605     ) -> DiagnosticBuilder<'_> {
606         let mut result = self.struct_fatal(msg);
607         result.set_span(span);
608         result
609     }
610
611     /// Construct a builder at the `Fatal` level at the given `span`, with the `msg`, and `code`.
612     pub fn struct_span_fatal_with_code(
613         &self,
614         span: impl Into<MultiSpan>,
615         msg: &str,
616         code: DiagnosticId,
617     ) -> DiagnosticBuilder<'_> {
618         let mut result = self.struct_span_fatal(span, msg);
619         result.code(code);
620         result
621     }
622
623     /// Construct a builder at the `Error` level with the `msg`.
624     pub fn struct_fatal(&self, msg: &str) -> DiagnosticBuilder<'_> {
625         DiagnosticBuilder::new(self, Level::Fatal, msg)
626     }
627
628     pub fn span_fatal(&self, span: impl Into<MultiSpan>, msg: &str) -> FatalError {
629         self.emit_diag_at_span(Diagnostic::new(Fatal, msg), span);
630         FatalError
631     }
632
633     pub fn span_fatal_with_code(
634         &self,
635         span: impl Into<MultiSpan>,
636         msg: &str,
637         code: DiagnosticId,
638     ) -> FatalError {
639         self.emit_diag_at_span(Diagnostic::new_with_code(Fatal, Some(code), msg), span);
640         FatalError
641     }
642
643     pub fn span_err(&self, span: impl Into<MultiSpan>, msg: &str) {
644         self.emit_diag_at_span(Diagnostic::new(Error, msg), span);
645     }
646
647     pub fn span_err_with_code(&self, span: impl Into<MultiSpan>, msg: &str, code: DiagnosticId) {
648         self.emit_diag_at_span(Diagnostic::new_with_code(Error, Some(code), msg), span);
649     }
650
651     pub fn span_warn(&self, span: impl Into<MultiSpan>, msg: &str) {
652         self.emit_diag_at_span(Diagnostic::new(Warning, msg), span);
653     }
654
655     pub fn span_warn_with_code(&self, span: impl Into<MultiSpan>, msg: &str, code: DiagnosticId) {
656         self.emit_diag_at_span(Diagnostic::new_with_code(Warning, Some(code), msg), span);
657     }
658
659     pub fn span_bug(&self, span: impl Into<MultiSpan>, msg: &str) -> ! {
660         self.inner.borrow_mut().span_bug(span, msg)
661     }
662
663     pub fn delay_span_bug(&self, span: impl Into<MultiSpan>, msg: &str) {
664         self.inner.borrow_mut().delay_span_bug(span, msg)
665     }
666
667     pub fn span_bug_no_panic(&self, span: impl Into<MultiSpan>, msg: &str) {
668         self.emit_diag_at_span(Diagnostic::new(Bug, msg), span);
669     }
670
671     pub fn span_note_without_error(&self, span: impl Into<MultiSpan>, msg: &str) {
672         self.emit_diag_at_span(Diagnostic::new(Note, msg), span);
673     }
674
675     pub fn span_note_diag(&self, span: Span, msg: &str) -> DiagnosticBuilder<'_> {
676         let mut db = DiagnosticBuilder::new(self, Note, msg);
677         db.set_span(span);
678         db
679     }
680
681     pub fn failure(&self, msg: &str) {
682         self.inner.borrow_mut().failure(msg);
683     }
684
685     pub fn fatal(&self, msg: &str) -> FatalError {
686         self.inner.borrow_mut().fatal(msg)
687     }
688
689     pub fn err(&self, msg: &str) {
690         self.inner.borrow_mut().err(msg);
691     }
692
693     pub fn warn(&self, msg: &str) {
694         let mut db = DiagnosticBuilder::new(self, Warning, msg);
695         db.emit();
696     }
697
698     pub fn note_without_error(&self, msg: &str) {
699         DiagnosticBuilder::new(self, Note, msg).emit();
700     }
701
702     pub fn bug(&self, msg: &str) -> ! {
703         self.inner.borrow_mut().bug(msg)
704     }
705
706     pub fn err_count(&self) -> usize {
707         self.inner.borrow().err_count()
708     }
709
710     pub fn has_errors(&self) -> bool {
711         self.inner.borrow().has_errors()
712     }
713     pub fn has_errors_or_delayed_span_bugs(&self) -> bool {
714         self.inner.borrow().has_errors_or_delayed_span_bugs()
715     }
716
717     pub fn print_error_count(&self, registry: &Registry) {
718         self.inner.borrow_mut().print_error_count(registry)
719     }
720
721     pub fn abort_if_errors(&self) {
722         self.inner.borrow_mut().abort_if_errors()
723     }
724
725     pub fn abort_if_errors_and_should_abort(&self) {
726         self.inner.borrow_mut().abort_if_errors_and_should_abort()
727     }
728
729     /// `true` if we haven't taught a diagnostic with this code already.
730     /// The caller must then teach the user about such a diagnostic.
731     ///
732     /// Used to suppress emitting the same error multiple times with extended explanation when
733     /// calling `-Zteach`.
734     pub fn must_teach(&self, code: &DiagnosticId) -> bool {
735         self.inner.borrow_mut().must_teach(code)
736     }
737
738     pub fn force_print_diagnostic(&self, db: Diagnostic) {
739         self.inner.borrow_mut().force_print_diagnostic(db)
740     }
741
742     pub fn emit_diagnostic(&self, diagnostic: &Diagnostic) {
743         self.inner.borrow_mut().emit_diagnostic(diagnostic)
744     }
745
746     fn emit_diag_at_span(&self, mut diag: Diagnostic, sp: impl Into<MultiSpan>) {
747         let mut inner = self.inner.borrow_mut();
748         inner.emit_diagnostic(diag.set_span(sp));
749         inner.abort_if_errors_and_should_abort();
750     }
751
752     pub fn emit_artifact_notification(&self, path: &Path, artifact_type: &str) {
753         self.inner.borrow_mut().emit_artifact_notification(path, artifact_type)
754     }
755
756     pub fn delay_as_bug(&self, diagnostic: Diagnostic) {
757         self.inner.borrow_mut().delay_as_bug(diagnostic)
758     }
759 }
760
761 impl HandlerInner {
762     fn must_teach(&mut self, code: &DiagnosticId) -> bool {
763         self.taught_diagnostics.insert(code.clone())
764     }
765
766     fn force_print_diagnostic(&mut self, db: Diagnostic) {
767         self.emitter.emit_diagnostic(&db);
768     }
769
770     /// Emit all stashed diagnostics.
771     fn emit_stashed_diagnostics(&mut self) {
772         let diags = self.stashed_diagnostics.drain(..).map(|x| x.1).collect::<Vec<_>>();
773         diags.iter().for_each(|diag| self.emit_diagnostic(diag));
774     }
775
776     fn emit_diagnostic(&mut self, diagnostic: &Diagnostic) {
777         if diagnostic.cancelled() {
778             return;
779         }
780
781         if diagnostic.level == Warning && !self.flags.can_emit_warnings {
782             return;
783         }
784
785         TRACK_DIAGNOSTICS.with(|track_diagnostics| {
786             track_diagnostics.get()(diagnostic);
787         });
788
789         if let Some(ref code) = diagnostic.code {
790             self.emitted_diagnostic_codes.insert(code.clone());
791         }
792
793         let diagnostic_hash = {
794             use std::hash::Hash;
795             let mut hasher = StableHasher::new();
796             diagnostic.hash(&mut hasher);
797             hasher.finish()
798         };
799
800         // Only emit the diagnostic if we haven't already emitted an equivalent
801         // one:
802         if self.emitted_diagnostics.insert(diagnostic_hash) {
803             self.emitter.emit_diagnostic(diagnostic);
804             if diagnostic.is_error() {
805                 self.deduplicated_err_count += 1;
806             }
807         }
808         if diagnostic.is_error() {
809             self.bump_err_count();
810         }
811     }
812
813     fn emit_artifact_notification(&mut self, path: &Path, artifact_type: &str) {
814         self.emitter.emit_artifact_notification(path, artifact_type);
815     }
816
817     fn treat_err_as_bug(&self) -> bool {
818         self.flags.treat_err_as_bug.map(|c| self.err_count() >= c).unwrap_or(false)
819     }
820
821     fn print_error_count(&mut self, registry: &Registry) {
822         self.emit_stashed_diagnostics();
823
824         let s = match self.deduplicated_err_count {
825             0 => return,
826             1 => "aborting due to previous error".to_string(),
827             count => format!("aborting due to {} previous errors", count)
828         };
829         if self.treat_err_as_bug() {
830             return;
831         }
832
833         let _ = self.fatal(&s);
834
835         let can_show_explain = self.emitter.should_show_explain();
836         let are_there_diagnostics = !self.emitted_diagnostic_codes.is_empty();
837         if can_show_explain && are_there_diagnostics {
838             let mut error_codes = self
839                 .emitted_diagnostic_codes
840                 .iter()
841                 .filter_map(|x| match &x {
842                     DiagnosticId::Error(s) if registry.find_description(s).is_some() => {
843                         Some(s.clone())
844                     }
845                     _ => None,
846                 })
847                 .collect::<Vec<_>>();
848             if !error_codes.is_empty() {
849                 error_codes.sort();
850                 if error_codes.len() > 1 {
851                     let limit = if error_codes.len() > 9 { 9 } else { error_codes.len() };
852                     self.failure(&format!("Some errors have detailed explanations: {}{}",
853                                           error_codes[..limit].join(", "),
854                                           if error_codes.len() > 9 { "..." } else { "." }));
855                     self.failure(&format!("For more information about an error, try \
856                                            `rustc --explain {}`.",
857                                           &error_codes[0]));
858                 } else {
859                     self.failure(&format!("For more information about this error, try \
860                                            `rustc --explain {}`.",
861                                           &error_codes[0]));
862                 }
863             }
864         }
865     }
866
867     fn err_count(&self) -> usize {
868         self.err_count + self.stashed_diagnostics.len()
869     }
870
871     fn has_errors(&self) -> bool {
872         self.err_count() > 0
873     }
874     fn has_errors_or_delayed_span_bugs(&self) -> bool {
875         self.has_errors() || !self.delayed_span_bugs.is_empty()
876     }
877
878     fn abort_if_errors_and_should_abort(&mut self) {
879         self.emit_stashed_diagnostics();
880
881         if self.has_errors() && !self.continue_after_error {
882             FatalError.raise();
883         }
884     }
885
886     fn abort_if_errors(&mut self) {
887         self.emit_stashed_diagnostics();
888
889         if self.has_errors() {
890             FatalError.raise();
891         }
892     }
893
894     fn span_bug(&mut self, sp: impl Into<MultiSpan>, msg: &str) -> ! {
895         self.emit_diag_at_span(Diagnostic::new(Bug, msg), sp);
896         panic!(ExplicitBug);
897     }
898
899     fn emit_diag_at_span(&mut self, mut diag: Diagnostic, sp: impl Into<MultiSpan>) {
900         self.emit_diagnostic(diag.set_span(sp));
901         self.abort_if_errors_and_should_abort();
902     }
903
904     fn delay_span_bug(&mut self, sp: impl Into<MultiSpan>, msg: &str) {
905         if self.treat_err_as_bug() {
906             // FIXME: don't abort here if report_delayed_bugs is off
907             self.span_bug(sp, msg);
908         }
909         let mut diagnostic = Diagnostic::new(Level::Bug, msg);
910         diagnostic.set_span(sp.into());
911         self.delay_as_bug(diagnostic)
912     }
913
914     fn failure(&mut self, msg: &str) {
915         self.emit_diagnostic(&Diagnostic::new(FailureNote, msg));
916     }
917
918     fn fatal(&mut self, msg: &str) -> FatalError {
919         self.emit_error(Fatal, msg);
920         FatalError
921     }
922
923     fn err(&mut self, msg: &str) {
924         self.emit_error(Error, msg);
925     }
926
927     /// Emit an error; level should be `Error` or `Fatal`.
928     fn emit_error(&mut self, level: Level, msg: &str,) {
929         if self.treat_err_as_bug() {
930             self.bug(msg);
931         }
932         self.emit_diagnostic(&Diagnostic::new(level, msg));
933     }
934
935     fn bug(&mut self, msg: &str) -> ! {
936         self.emit_diagnostic(&Diagnostic::new(Bug, msg));
937         panic!(ExplicitBug);
938     }
939
940     fn delay_as_bug(&mut self, diagnostic: Diagnostic) {
941         if self.flags.report_delayed_bugs {
942             self.emit_diagnostic(&diagnostic);
943         }
944         self.delayed_span_bugs.push(diagnostic);
945     }
946
947     fn bump_err_count(&mut self) {
948         self.err_count += 1;
949         self.panic_if_treat_err_as_bug();
950     }
951
952     fn panic_if_treat_err_as_bug(&self) {
953         if self.treat_err_as_bug() {
954             let s = match (self.err_count(), self.flags.treat_err_as_bug.unwrap_or(0)) {
955                 (0, _) => return,
956                 (1, 1) => "aborting due to `-Z treat-err-as-bug=1`".to_string(),
957                 (1, _) => return,
958                 (count, as_bug) => {
959                     format!(
960                         "aborting after {} errors due to `-Z treat-err-as-bug={}`",
961                         count,
962                         as_bug,
963                     )
964                 }
965             };
966             panic!(s);
967         }
968     }
969 }
970
971 #[derive(Copy, PartialEq, Clone, Hash, Debug, RustcEncodable, RustcDecodable)]
972 pub enum Level {
973     Bug,
974     Fatal,
975     Error,
976     Warning,
977     Note,
978     Help,
979     Cancelled,
980     FailureNote,
981 }
982
983 impl fmt::Display for Level {
984     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
985         self.to_str().fmt(f)
986     }
987 }
988
989 impl Level {
990     fn color(self) -> ColorSpec {
991         let mut spec = ColorSpec::new();
992         match self {
993             Bug | Fatal | Error => {
994                 spec.set_fg(Some(Color::Red))
995                     .set_intense(true);
996             }
997             Warning => {
998                 spec.set_fg(Some(Color::Yellow))
999                     .set_intense(cfg!(windows));
1000             }
1001             Note => {
1002                 spec.set_fg(Some(Color::Green))
1003                     .set_intense(true);
1004             }
1005             Help => {
1006                 spec.set_fg(Some(Color::Cyan))
1007                     .set_intense(true);
1008             }
1009             FailureNote => {}
1010             Cancelled => unreachable!(),
1011         }
1012         spec
1013     }
1014
1015     pub fn to_str(self) -> &'static str {
1016         match self {
1017             Bug => "error: internal compiler error",
1018             Fatal | Error => "error",
1019             Warning => "warning",
1020             Note => "note",
1021             Help => "help",
1022             FailureNote => "failure-note",
1023             Cancelled => panic!("Shouldn't call on cancelled error"),
1024         }
1025     }
1026
1027     pub fn is_failure_note(&self) -> bool {
1028         match *self {
1029             FailureNote => true,
1030             _ => false,
1031         }
1032     }
1033 }
1034
1035 #[macro_export]
1036 macro_rules! pluralize {
1037     ($x:expr) => {
1038         if $x != 1 { "s" } else { "" }
1039     };
1040 }