]> git.lizzy.rs Git - rust.git/blob - src/librustc_errors/lib.rs
Auto merge of #58341 - alexreg:cosmetic-2-doc-comments, r=steveklabnik
[rust.git] / src / librustc_errors / lib.rs
1 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
2
3 #![feature(custom_attribute)]
4 #![allow(unused_attributes)]
5 #![feature(range_contains)]
6 #![cfg_attr(unix, feature(libc))]
7 #![feature(nll)]
8 #![feature(optin_builtin_traits)]
9 #![deny(rust_2018_idioms)]
10
11 #[allow(unused_extern_crates)]
12 extern crate serialize as rustc_serialize; // used by deriving
13
14 pub use emitter::ColorConfig;
15
16 use Level::*;
17
18 use emitter::{Emitter, EmitterWriter};
19
20 use rustc_data_structures::sync::{self, Lrc, Lock, AtomicUsize, AtomicBool, SeqCst};
21 use rustc_data_structures::fx::FxHashSet;
22 use rustc_data_structures::stable_hasher::StableHasher;
23
24 use std::borrow::Cow;
25 use std::cell::Cell;
26 use std::{error, fmt};
27 use std::panic;
28
29 use termcolor::{ColorSpec, Color};
30
31 mod diagnostic;
32 mod diagnostic_builder;
33 pub mod emitter;
34 mod snippet;
35 pub mod registry;
36 mod styled_buffer;
37 mod lock;
38
39 use syntax_pos::{BytePos,
40                  Loc,
41                  FileLinesResult,
42                  SourceFile,
43                  FileName,
44                  MultiSpan,
45                  Span,
46                  NO_EXPANSION};
47
48 /// Indicates the confidence in the correctness of a suggestion.
49 ///
50 /// All suggestions are marked with an `Applicability`. Tools use the applicability of a suggestion
51 /// to determine whether it should be automatically applied or if the user should be consulted
52 /// before applying the suggestion.
53 #[derive(Copy, Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
54 pub enum Applicability {
55     /// The suggestion is definitely what the user intended. This suggestion should be
56     /// automatically applied.
57     MachineApplicable,
58
59     /// The suggestion may be what the user intended, but it is uncertain. The suggestion should
60     /// result in valid Rust code if it is applied.
61     MaybeIncorrect,
62
63     /// The suggestion contains placeholders like `(...)` or `{ /* fields */ }`. The suggestion
64     /// cannot be applied automatically because it will not result in valid Rust code. The user
65     /// will need to fill in the placeholders.
66     HasPlaceholders,
67
68     /// The applicability of the suggestion is unknown.
69     Unspecified,
70 }
71
72 #[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
73 pub 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     /// ```
81     /// vec![
82     ///     Substitution { parts: vec![(0..3, "a"), (4..7, "b")] },
83     ///     Substitution { parts: vec![(0..3, "x"), (4..7, "y")] },
84     /// ]
85     /// ```
86     ///
87     /// or by replacing the entire span:
88     ///
89     /// ```
90     /// vec![
91     ///     Substitution { parts: vec![(0..7, "a.b")] },
92     ///     Substitution { parts: vec![(0..7, "x.y")] },
93     /// ]
94     /// ```
95     pub substitutions: Vec<Substitution>,
96     pub msg: String,
97     pub show_code_when_inline: bool,
98     /// Whether or not the suggestion is approximate
99     ///
100     /// Sometimes we may show suggestions with placeholders,
101     /// which are useful for users but not useful for
102     /// tools like rustfix
103     pub applicability: Applicability,
104 }
105
106 #[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
107 /// See the docs on `CodeSuggestion::substitutions`
108 pub struct Substitution {
109     pub parts: Vec<SubstitutionPart>,
110 }
111
112 #[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
113 pub struct SubstitutionPart {
114     pub span: Span,
115     pub snippet: String,
116 }
117
118 pub type SourceMapperDyn = dyn SourceMapper + sync::Send + sync::Sync;
119
120 pub trait SourceMapper {
121     fn lookup_char_pos(&self, pos: BytePos) -> Loc;
122     fn span_to_lines(&self, sp: Span) -> FileLinesResult;
123     fn span_to_string(&self, sp: Span) -> String;
124     fn span_to_filename(&self, sp: Span) -> FileName;
125     fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option<Span>;
126     fn call_span_if_macro(&self, sp: Span) -> Span;
127     fn ensure_source_file_source_present(&self, source_file: Lrc<SourceFile>) -> bool;
128     fn doctest_offset_line(&self, file: &FileName, line: usize) -> usize;
129 }
130
131 impl CodeSuggestion {
132     /// Returns the assembled code suggestions and whether they should be shown with an underline.
133     pub fn splice_lines(&self, cm: &SourceMapperDyn)
134                         -> Vec<(String, Vec<SubstitutionPart>)> {
135         use syntax_pos::{CharPos, Loc, Pos};
136
137         fn push_trailing(buf: &mut String,
138                          line_opt: Option<&Cow<'_, str>>,
139                          lo: &Loc,
140                          hi_opt: Option<&Loc>) {
141             let (lo, hi_opt) = (lo.col.to_usize(), hi_opt.map(|hi| hi.col.to_usize()));
142             if let Some(line) = line_opt {
143                 if let Some(lo) = line.char_indices().map(|(i, _)| i).nth(lo) {
144                     let hi_opt = hi_opt.and_then(|hi| line.char_indices().map(|(i, _)| i).nth(hi));
145                     match hi_opt {
146                         Some(hi) if hi > lo => buf.push_str(&line[lo..hi]),
147                         Some(_) => (),
148                         None => buf.push_str(&line[lo..]),
149                     }
150                 }
151                 if let None = hi_opt {
152                     buf.push('\n');
153                 }
154             }
155         }
156
157         assert!(!self.substitutions.is_empty());
158
159         self.substitutions.iter().cloned().map(|mut substitution| {
160             // Assumption: all spans are in the same file, and all spans
161             // are disjoint. Sort in ascending order.
162             substitution.parts.sort_by_key(|part| part.span.lo());
163
164             // Find the bounding span.
165             let lo = substitution.parts.iter().map(|part| part.span.lo()).min().unwrap();
166             let hi = substitution.parts.iter().map(|part| part.span.hi()).min().unwrap();
167             let bounding_span = Span::new(lo, hi, NO_EXPANSION);
168             let lines = cm.span_to_lines(bounding_span).unwrap();
169             assert!(!lines.lines.is_empty());
170
171             // To build up the result, we do this for each span:
172             // - push the line segment trailing the previous span
173             //   (at the beginning a "phantom" span pointing at the start of the line)
174             // - push lines between the previous and current span (if any)
175             // - if the previous and current span are not on the same line
176             //   push the line segment leading up to the current span
177             // - splice in the span substitution
178             //
179             // Finally push the trailing line segment of the last span
180             let fm = &lines.file;
181             let mut prev_hi = cm.lookup_char_pos(bounding_span.lo());
182             prev_hi.col = CharPos::from_usize(0);
183
184             let mut prev_line = fm.get_line(lines.lines[0].line_index);
185             let mut buf = String::new();
186
187             for part in &substitution.parts {
188                 let cur_lo = cm.lookup_char_pos(part.span.lo());
189                 if prev_hi.line == cur_lo.line {
190                     push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, Some(&cur_lo));
191                 } else {
192                     push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
193                     // push lines between the previous and current span (if any)
194                     for idx in prev_hi.line..(cur_lo.line - 1) {
195                         if let Some(line) = fm.get_line(idx) {
196                             buf.push_str(line.as_ref());
197                             buf.push('\n');
198                         }
199                     }
200                     if let Some(cur_line) = fm.get_line(cur_lo.line - 1) {
201                         buf.push_str(&cur_line[..cur_lo.col.to_usize()]);
202                     }
203                 }
204                 buf.push_str(&part.snippet);
205                 prev_hi = cm.lookup_char_pos(part.span.hi());
206                 prev_line = fm.get_line(prev_hi.line - 1);
207             }
208             // if the replacement already ends with a newline, don't print the next line
209             if !buf.ends_with('\n') {
210                 push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
211             }
212             // remove trailing newlines
213             while buf.ends_with('\n') {
214                 buf.pop();
215             }
216             (buf, substitution.parts)
217         }).collect()
218     }
219 }
220
221 /// Used as a return value to signify a fatal error occurred. (It is also
222 /// used as the argument to panic at the moment, but that will eventually
223 /// not be true.)
224 #[derive(Copy, Clone, Debug)]
225 #[must_use]
226 pub struct FatalError;
227
228 pub struct FatalErrorMarker;
229
230 // Don't implement Send on FatalError. This makes it impossible to panic!(FatalError).
231 // We don't want to invoke the panic handler and print a backtrace for fatal errors.
232 impl !Send for FatalError {}
233
234 impl FatalError {
235     pub fn raise(self) -> ! {
236         panic::resume_unwind(Box::new(FatalErrorMarker))
237     }
238 }
239
240 impl fmt::Display for FatalError {
241     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
242         write!(f, "parser fatal error")
243     }
244 }
245
246 impl error::Error for FatalError {
247     fn description(&self) -> &str {
248         "The parser has encountered a fatal error"
249     }
250 }
251
252 /// Signifies that the compiler died with an explicit call to `.bug`
253 /// or `.span_bug` rather than a failed assertion, etc.
254 #[derive(Copy, Clone, Debug)]
255 pub struct ExplicitBug;
256
257 impl fmt::Display for ExplicitBug {
258     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
259         write!(f, "parser internal bug")
260     }
261 }
262
263 impl error::Error for ExplicitBug {
264     fn description(&self) -> &str {
265         "The parser has encountered an internal bug"
266     }
267 }
268
269 pub use diagnostic::{Diagnostic, SubDiagnostic, DiagnosticStyledString, DiagnosticId};
270 pub use diagnostic_builder::DiagnosticBuilder;
271
272 /// A handler deals with errors; certain errors
273 /// (fatal, bug, unimpl) may cause immediate exit,
274 /// others log errors for later reporting.
275 pub struct Handler {
276     pub flags: HandlerFlags,
277
278     err_count: AtomicUsize,
279     emitter: Lock<Box<dyn Emitter + sync::Send>>,
280     continue_after_error: AtomicBool,
281     delayed_span_bugs: Lock<Vec<Diagnostic>>,
282
283     // This set contains the `DiagnosticId` of all emitted diagnostics to avoid
284     // emitting the same diagnostic with extended help (`--teach`) twice, which
285     // would be uneccessary repetition.
286     taught_diagnostics: Lock<FxHashSet<DiagnosticId>>,
287
288     /// Used to suggest rustc --explain <error code>
289     emitted_diagnostic_codes: Lock<FxHashSet<DiagnosticId>>,
290
291     // This set contains a hash of every diagnostic that has been emitted by
292     // this handler. These hashes is used to avoid emitting the same error
293     // twice.
294     emitted_diagnostics: Lock<FxHashSet<u128>>,
295 }
296
297 fn default_track_diagnostic(_: &Diagnostic) {}
298
299 thread_local!(pub static TRACK_DIAGNOSTICS: Cell<fn(&Diagnostic)> =
300                 Cell::new(default_track_diagnostic));
301
302 #[derive(Default)]
303 pub struct HandlerFlags {
304     /// If false, warning-level lints are suppressed.
305     /// (rustc: see `--allow warnings` and `--cap-lints`)
306     pub can_emit_warnings: bool,
307     /// If true, error-level diagnostics are upgraded to bug-level.
308     /// (rustc: see `-Z treat-err-as-bug`)
309     pub treat_err_as_bug: bool,
310     /// If true, immediately emit diagnostics that would otherwise be buffered.
311     /// (rustc: see `-Z dont-buffer-diagnostics` and `-Z treat-err-as-bug`)
312     pub dont_buffer_diagnostics: bool,
313     /// If true, immediately print bugs registered with `delay_span_bug`.
314     /// (rustc: see `-Z report-delayed-bugs`)
315     pub report_delayed_bugs: bool,
316     /// show macro backtraces even for non-local macros.
317     /// (rustc: see `-Z external-macro-backtrace`)
318     pub external_macro_backtrace: bool,
319 }
320
321 impl Drop for Handler {
322     fn drop(&mut self) {
323         if self.err_count() == 0 {
324             let mut bugs = self.delayed_span_bugs.borrow_mut();
325             let has_bugs = !bugs.is_empty();
326             for bug in bugs.drain(..) {
327                 DiagnosticBuilder::new_diagnostic(self, bug).emit();
328             }
329             if has_bugs {
330                 panic!("no errors encountered even though `delay_span_bug` issued");
331             }
332         }
333     }
334 }
335
336 impl Handler {
337     pub fn with_tty_emitter(color_config: ColorConfig,
338                             can_emit_warnings: bool,
339                             treat_err_as_bug: bool,
340                             cm: Option<Lrc<SourceMapperDyn>>)
341                             -> Handler {
342         Handler::with_tty_emitter_and_flags(
343             color_config,
344             cm,
345             HandlerFlags {
346                 can_emit_warnings,
347                 treat_err_as_bug,
348                 .. Default::default()
349             })
350     }
351
352     pub fn with_tty_emitter_and_flags(color_config: ColorConfig,
353                                       cm: Option<Lrc<SourceMapperDyn>>,
354                                       flags: HandlerFlags)
355                                       -> Handler {
356         let emitter = Box::new(EmitterWriter::stderr(color_config, cm, false, false));
357         Handler::with_emitter_and_flags(emitter, flags)
358     }
359
360     pub fn with_emitter(can_emit_warnings: bool,
361                         treat_err_as_bug: bool,
362                         e: Box<dyn Emitter + sync::Send>)
363                         -> Handler {
364         Handler::with_emitter_and_flags(
365             e,
366             HandlerFlags {
367                 can_emit_warnings,
368                 treat_err_as_bug,
369                 .. Default::default()
370             })
371     }
372
373     pub fn with_emitter_and_flags(e: Box<dyn Emitter + sync::Send>, flags: HandlerFlags) -> Handler
374     {
375         Handler {
376             flags,
377             err_count: AtomicUsize::new(0),
378             emitter: Lock::new(e),
379             continue_after_error: AtomicBool::new(true),
380             delayed_span_bugs: Lock::new(Vec::new()),
381             taught_diagnostics: Default::default(),
382             emitted_diagnostic_codes: Default::default(),
383             emitted_diagnostics: Default::default(),
384         }
385     }
386
387     pub fn set_continue_after_error(&self, continue_after_error: bool) {
388         self.continue_after_error.store(continue_after_error, SeqCst);
389     }
390
391     /// Resets the diagnostic error count as well as the cached emitted diagnostics.
392     ///
393     /// NOTE: *do not* call this function from rustc. It is only meant to be called from external
394     /// tools that want to reuse a `Parser` cleaning the previously emitted diagnostics as well as
395     /// the overall count of emitted error diagnostics.
396     pub fn reset_err_count(&self) {
397         // actually frees the underlying memory (which `clear` would not do)
398         *self.emitted_diagnostics.borrow_mut() = Default::default();
399         self.err_count.store(0, SeqCst);
400     }
401
402     pub fn struct_dummy<'a>(&'a self) -> DiagnosticBuilder<'a> {
403         DiagnosticBuilder::new(self, Level::Cancelled, "")
404     }
405
406     pub fn struct_span_warn<'a, S: Into<MultiSpan>>(&'a self,
407                                                     sp: S,
408                                                     msg: &str)
409                                                     -> DiagnosticBuilder<'a> {
410         let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
411         result.set_span(sp);
412         if !self.flags.can_emit_warnings {
413             result.cancel();
414         }
415         result
416     }
417     pub fn struct_span_warn_with_code<'a, S: Into<MultiSpan>>(&'a self,
418                                                               sp: S,
419                                                               msg: &str,
420                                                               code: DiagnosticId)
421                                                               -> DiagnosticBuilder<'a> {
422         let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
423         result.set_span(sp);
424         result.code(code);
425         if !self.flags.can_emit_warnings {
426             result.cancel();
427         }
428         result
429     }
430     pub fn struct_warn<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
431         let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
432         if !self.flags.can_emit_warnings {
433             result.cancel();
434         }
435         result
436     }
437     pub fn struct_span_err<'a, S: Into<MultiSpan>>(&'a self,
438                                                    sp: S,
439                                                    msg: &str)
440                                                    -> DiagnosticBuilder<'a> {
441         let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
442         result.set_span(sp);
443         result
444     }
445     pub fn struct_span_err_with_code<'a, S: Into<MultiSpan>>(&'a self,
446                                                              sp: S,
447                                                              msg: &str,
448                                                              code: DiagnosticId)
449                                                              -> DiagnosticBuilder<'a> {
450         let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
451         result.set_span(sp);
452         result.code(code);
453         result
454     }
455     // FIXME: This method should be removed (every error should have an associated error code).
456     pub fn struct_err<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
457         DiagnosticBuilder::new(self, Level::Error, msg)
458     }
459     pub fn struct_err_with_code<'a>(
460         &'a self,
461         msg: &str,
462         code: DiagnosticId,
463     ) -> DiagnosticBuilder<'a> {
464         let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
465         result.code(code);
466         result
467     }
468     pub fn struct_span_fatal<'a, S: Into<MultiSpan>>(&'a self,
469                                                      sp: S,
470                                                      msg: &str)
471                                                      -> DiagnosticBuilder<'a> {
472         let mut result = DiagnosticBuilder::new(self, Level::Fatal, msg);
473         result.set_span(sp);
474         result
475     }
476     pub fn struct_span_fatal_with_code<'a, S: Into<MultiSpan>>(&'a self,
477                                                                sp: S,
478                                                                msg: &str,
479                                                                code: DiagnosticId)
480                                                                -> DiagnosticBuilder<'a> {
481         let mut result = DiagnosticBuilder::new(self, Level::Fatal, msg);
482         result.set_span(sp);
483         result.code(code);
484         result
485     }
486     pub fn struct_fatal<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
487         DiagnosticBuilder::new(self, Level::Fatal, msg)
488     }
489
490     pub fn cancel(&self, err: &mut DiagnosticBuilder<'_>) {
491         err.cancel();
492     }
493
494     fn panic_if_treat_err_as_bug(&self) {
495         if self.flags.treat_err_as_bug {
496             panic!("encountered error with `-Z treat_err_as_bug");
497         }
498     }
499
500     pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> FatalError {
501         self.emit(&sp.into(), msg, Fatal);
502         FatalError
503     }
504     pub fn span_fatal_with_code<S: Into<MultiSpan>>(&self,
505                                                     sp: S,
506                                                     msg: &str,
507                                                     code: DiagnosticId)
508                                                     -> FatalError {
509         self.emit_with_code(&sp.into(), msg, code, Fatal);
510         FatalError
511     }
512     pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
513         self.emit(&sp.into(), msg, Error);
514     }
515     pub fn mut_span_err<'a, S: Into<MultiSpan>>(&'a self,
516                                                 sp: S,
517                                                 msg: &str)
518                                                 -> DiagnosticBuilder<'a> {
519         let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
520         result.set_span(sp);
521         result
522     }
523     pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: DiagnosticId) {
524         self.emit_with_code(&sp.into(), msg, code, Error);
525     }
526     pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
527         self.emit(&sp.into(), msg, Warning);
528     }
529     pub fn span_warn_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: DiagnosticId) {
530         self.emit_with_code(&sp.into(), msg, code, Warning);
531     }
532     pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
533         self.emit(&sp.into(), msg, Bug);
534         panic!(ExplicitBug);
535     }
536     pub fn delay_span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
537         if self.flags.treat_err_as_bug {
538             // FIXME: don't abort here if report_delayed_bugs is off
539             self.span_bug(sp, msg);
540         }
541         let mut diagnostic = Diagnostic::new(Level::Bug, msg);
542         diagnostic.set_span(sp.into());
543         self.delay_as_bug(diagnostic);
544     }
545     fn delay_as_bug(&self, diagnostic: Diagnostic) {
546         if self.flags.report_delayed_bugs {
547             DiagnosticBuilder::new_diagnostic(self, diagnostic.clone()).emit();
548         }
549         self.delayed_span_bugs.borrow_mut().push(diagnostic);
550     }
551     pub fn span_bug_no_panic<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
552         self.emit(&sp.into(), msg, Bug);
553     }
554     pub fn span_note_without_error<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
555         self.emit(&sp.into(), msg, Note);
556     }
557     pub fn span_note_diag<'a>(&'a self,
558                               sp: Span,
559                               msg: &str)
560                               -> DiagnosticBuilder<'a> {
561         let mut db = DiagnosticBuilder::new(self, Note, msg);
562         db.set_span(sp);
563         db
564     }
565     pub fn span_unimpl<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
566         self.span_bug(sp, &format!("unimplemented {}", msg));
567     }
568     pub fn failure(&self, msg: &str) {
569         DiagnosticBuilder::new(self, FailureNote, msg).emit()
570     }
571     pub fn fatal(&self, msg: &str) -> FatalError {
572         if self.flags.treat_err_as_bug {
573             self.bug(msg);
574         }
575         DiagnosticBuilder::new(self, Fatal, msg).emit();
576         FatalError
577     }
578     pub fn err(&self, msg: &str) {
579         if self.flags.treat_err_as_bug {
580             self.bug(msg);
581         }
582         let mut db = DiagnosticBuilder::new(self, Error, msg);
583         db.emit();
584     }
585     pub fn warn(&self, msg: &str) {
586         let mut db = DiagnosticBuilder::new(self, Warning, msg);
587         db.emit();
588     }
589     pub fn note_without_error(&self, msg: &str) {
590         let mut db = DiagnosticBuilder::new(self, Note, msg);
591         db.emit();
592     }
593     pub fn bug(&self, msg: &str) -> ! {
594         let mut db = DiagnosticBuilder::new(self, Bug, msg);
595         db.emit();
596         panic!(ExplicitBug);
597     }
598     pub fn unimpl(&self, msg: &str) -> ! {
599         self.bug(&format!("unimplemented {}", msg));
600     }
601
602     fn bump_err_count(&self) {
603         self.panic_if_treat_err_as_bug();
604         self.err_count.fetch_add(1, SeqCst);
605     }
606
607     pub fn err_count(&self) -> usize {
608         self.err_count.load(SeqCst)
609     }
610
611     pub fn has_errors(&self) -> bool {
612         self.err_count() > 0
613     }
614
615     pub fn print_error_count(&self) {
616         let s = match self.err_count() {
617             0 => return,
618             1 => "aborting due to previous error".to_string(),
619             _ => format!("aborting due to {} previous errors", self.err_count())
620         };
621
622         let _ = self.fatal(&s);
623
624         let can_show_explain = self.emitter.borrow().should_show_explain();
625         let are_there_diagnostics = !self.emitted_diagnostic_codes.borrow().is_empty();
626         if can_show_explain && are_there_diagnostics {
627             let mut error_codes =
628                 self.emitted_diagnostic_codes.borrow()
629                                              .iter()
630                                              .filter_map(|x| match *x {
631                                                  DiagnosticId::Error(ref s) => Some(s.clone()),
632                                                  _ => None,
633                                              })
634                                              .collect::<Vec<_>>();
635             if !error_codes.is_empty() {
636                 error_codes.sort();
637                 if error_codes.len() > 1 {
638                     let limit = if error_codes.len() > 9 { 9 } else { error_codes.len() };
639                     self.failure(&format!("Some errors occurred: {}{}",
640                                           error_codes[..limit].join(", "),
641                                           if error_codes.len() > 9 { "..." } else { "." }));
642                     self.failure(&format!("For more information about an error, try \
643                                            `rustc --explain {}`.",
644                                           &error_codes[0]));
645                 } else {
646                     self.failure(&format!("For more information about this error, try \
647                                            `rustc --explain {}`.",
648                                           &error_codes[0]));
649                 }
650             }
651         }
652     }
653
654     pub fn abort_if_errors(&self) {
655         if self.err_count() == 0 {
656             return;
657         }
658         FatalError.raise();
659     }
660     pub fn emit(&self, msp: &MultiSpan, msg: &str, lvl: Level) {
661         if lvl == Warning && !self.flags.can_emit_warnings {
662             return;
663         }
664         let mut db = DiagnosticBuilder::new(self, lvl, msg);
665         db.set_span(msp.clone());
666         db.emit();
667         if !self.continue_after_error.load(SeqCst) {
668             self.abort_if_errors();
669         }
670     }
671     pub fn emit_with_code(&self, msp: &MultiSpan, msg: &str, code: DiagnosticId, lvl: Level) {
672         if lvl == Warning && !self.flags.can_emit_warnings {
673             return;
674         }
675         let mut db = DiagnosticBuilder::new_with_code(self, lvl, Some(code), msg);
676         db.set_span(msp.clone());
677         db.emit();
678         if !self.continue_after_error.load(SeqCst) {
679             self.abort_if_errors();
680         }
681     }
682
683     /// `true` if we haven't taught a diagnostic with this code already.
684     /// The caller must then teach the user about such a diagnostic.
685     ///
686     /// Used to suppress emitting the same error multiple times with extended explanation when
687     /// calling `-Zteach`.
688     pub fn must_teach(&self, code: &DiagnosticId) -> bool {
689         self.taught_diagnostics.borrow_mut().insert(code.clone())
690     }
691
692     pub fn force_print_db(&self, mut db: DiagnosticBuilder<'_>) {
693         self.emitter.borrow_mut().emit(&db);
694         db.cancel();
695     }
696
697     fn emit_db(&self, db: &DiagnosticBuilder<'_>) {
698         let diagnostic = &**db;
699
700         TRACK_DIAGNOSTICS.with(|track_diagnostics| {
701             track_diagnostics.get()(diagnostic);
702         });
703
704         if let Some(ref code) = diagnostic.code {
705             self.emitted_diagnostic_codes.borrow_mut().insert(code.clone());
706         }
707
708         let diagnostic_hash = {
709             use std::hash::Hash;
710             let mut hasher = StableHasher::new();
711             diagnostic.hash(&mut hasher);
712             hasher.finish()
713         };
714
715         // Only emit the diagnostic if we haven't already emitted an equivalent
716         // one:
717         if self.emitted_diagnostics.borrow_mut().insert(diagnostic_hash) {
718             self.emitter.borrow_mut().emit(db);
719             if db.is_error() {
720                 self.bump_err_count();
721             }
722         }
723     }
724 }
725
726
727 #[derive(Copy, PartialEq, Clone, Hash, Debug, RustcEncodable, RustcDecodable)]
728 pub enum Level {
729     Bug,
730     Fatal,
731     // An error which while not immediately fatal, should stop the compiler
732     // progressing beyond the current phase.
733     PhaseFatal,
734     Error,
735     Warning,
736     Note,
737     Help,
738     Cancelled,
739     FailureNote,
740 }
741
742 impl fmt::Display for Level {
743     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
744         self.to_str().fmt(f)
745     }
746 }
747
748 impl Level {
749     fn color(self) -> ColorSpec {
750         let mut spec = ColorSpec::new();
751         match self {
752             Bug | Fatal | PhaseFatal | Error => {
753                 spec.set_fg(Some(Color::Red))
754                     .set_intense(true);
755             }
756             Warning => {
757                 spec.set_fg(Some(Color::Yellow))
758                     .set_intense(cfg!(windows));
759             }
760             Note => {
761                 spec.set_fg(Some(Color::Green))
762                     .set_intense(true);
763             }
764             Help => {
765                 spec.set_fg(Some(Color::Cyan))
766                     .set_intense(true);
767             }
768             FailureNote => {}
769             Cancelled => unreachable!(),
770         }
771         spec
772     }
773
774     pub fn to_str(self) -> &'static str {
775         match self {
776             Bug => "error: internal compiler error",
777             Fatal | PhaseFatal | Error => "error",
778             Warning => "warning",
779             Note => "note",
780             Help => "help",
781             FailureNote => "",
782             Cancelled => panic!("Shouldn't call on cancelled error"),
783         }
784     }
785
786     pub fn is_failure_note(&self) -> bool {
787         match *self {
788             FailureNote => true,
789             _ => false,
790         }
791     }
792 }