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