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