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