]> git.lizzy.rs Git - rust.git/blob - src/librustc_errors/lib.rs
Make sure the compiler actually panics on `delay_span_bug`
[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<Vec<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 report_delayed_bugs: bool,
303     pub external_macro_backtrace: bool,
304 }
305
306 impl Drop for Handler {
307     fn drop(&mut self) {
308         if self.err_count() == 0 {
309             let mut bugs = self.delayed_span_bug.borrow_mut();
310             let has_bugs = !bugs.is_empty();
311             for bug in bugs.drain(..) {
312                 DiagnosticBuilder::new_diagnostic(self, bug).emit();
313             }
314             if has_bugs {
315                 panic!("no errors encountered even though `delay_span_bug` issued");
316             }
317         }
318     }
319 }
320
321 impl Handler {
322     pub fn with_tty_emitter(color_config: ColorConfig,
323                             can_emit_warnings: bool,
324                             treat_err_as_bug: bool,
325                             cm: Option<Lrc<CodeMapperDyn>>)
326                             -> Handler {
327         Handler::with_tty_emitter_and_flags(
328             color_config,
329             cm,
330             HandlerFlags {
331                 can_emit_warnings,
332                 treat_err_as_bug,
333                 .. Default::default()
334             })
335     }
336
337     pub fn with_tty_emitter_and_flags(color_config: ColorConfig,
338                                       cm: Option<Lrc<CodeMapperDyn>>,
339                                       flags: HandlerFlags)
340                                       -> Handler {
341         let emitter = Box::new(EmitterWriter::stderr(color_config, cm, false, false));
342         Handler::with_emitter_and_flags(emitter, flags)
343     }
344
345     pub fn with_emitter(can_emit_warnings: bool,
346                         treat_err_as_bug: bool,
347                         e: Box<dyn Emitter + sync::Send>)
348                         -> Handler {
349         Handler::with_emitter_and_flags(
350             e,
351             HandlerFlags {
352                 can_emit_warnings,
353                 treat_err_as_bug,
354                 .. Default::default()
355             })
356     }
357
358     pub fn with_emitter_and_flags(e: Box<dyn Emitter + sync::Send>, flags: HandlerFlags) -> Handler
359     {
360         Handler {
361             flags,
362             err_count: AtomicUsize::new(0),
363             emitter: Lock::new(e),
364             continue_after_error: LockCell::new(true),
365             delayed_span_bug: Lock::new(Vec::new()),
366             taught_diagnostics: Lock::new(FxHashSet()),
367             emitted_diagnostic_codes: Lock::new(FxHashSet()),
368             emitted_diagnostics: Lock::new(FxHashSet()),
369         }
370     }
371
372     pub fn set_continue_after_error(&self, continue_after_error: bool) {
373         self.continue_after_error.set(continue_after_error);
374     }
375
376     /// Resets the diagnostic error count as well as the cached emitted diagnostics.
377     ///
378     /// NOTE: DO NOT call this function from rustc. It is only meant to be called from external
379     /// tools that want to reuse a `Parser` cleaning the previously emitted diagnostics as well as
380     /// the overall count of emitted error diagnostics.
381     pub fn reset_err_count(&self) {
382         *self.emitted_diagnostics.borrow_mut() = FxHashSet();
383         self.err_count.store(0, SeqCst);
384     }
385
386     pub fn struct_dummy<'a>(&'a self) -> DiagnosticBuilder<'a> {
387         DiagnosticBuilder::new(self, Level::Cancelled, "")
388     }
389
390     pub fn struct_span_warn<'a, S: Into<MultiSpan>>(&'a self,
391                                                     sp: S,
392                                                     msg: &str)
393                                                     -> DiagnosticBuilder<'a> {
394         let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
395         result.set_span(sp);
396         if !self.flags.can_emit_warnings {
397             result.cancel();
398         }
399         result
400     }
401     pub fn struct_span_warn_with_code<'a, S: Into<MultiSpan>>(&'a self,
402                                                               sp: S,
403                                                               msg: &str,
404                                                               code: DiagnosticId)
405                                                               -> DiagnosticBuilder<'a> {
406         let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
407         result.set_span(sp);
408         result.code(code);
409         if !self.flags.can_emit_warnings {
410             result.cancel();
411         }
412         result
413     }
414     pub fn struct_warn<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
415         let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
416         if !self.flags.can_emit_warnings {
417             result.cancel();
418         }
419         result
420     }
421     pub fn struct_span_err<'a, S: Into<MultiSpan>>(&'a self,
422                                                    sp: S,
423                                                    msg: &str)
424                                                    -> DiagnosticBuilder<'a> {
425         let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
426         result.set_span(sp);
427         result
428     }
429     pub fn struct_span_err_with_code<'a, S: Into<MultiSpan>>(&'a self,
430                                                              sp: S,
431                                                              msg: &str,
432                                                              code: DiagnosticId)
433                                                              -> DiagnosticBuilder<'a> {
434         let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
435         result.set_span(sp);
436         result.code(code);
437         result
438     }
439     // FIXME: This method should be removed (every error should have an associated error code).
440     pub fn struct_err<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
441         DiagnosticBuilder::new(self, Level::Error, msg)
442     }
443     pub fn struct_err_with_code<'a>(
444         &'a self,
445         msg: &str,
446         code: DiagnosticId,
447     ) -> DiagnosticBuilder<'a> {
448         let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
449         result.code(code);
450         result
451     }
452     pub fn struct_span_fatal<'a, S: Into<MultiSpan>>(&'a self,
453                                                      sp: S,
454                                                      msg: &str)
455                                                      -> DiagnosticBuilder<'a> {
456         let mut result = DiagnosticBuilder::new(self, Level::Fatal, msg);
457         result.set_span(sp);
458         result
459     }
460     pub fn struct_span_fatal_with_code<'a, S: Into<MultiSpan>>(&'a self,
461                                                                sp: S,
462                                                                msg: &str,
463                                                                code: DiagnosticId)
464                                                                -> DiagnosticBuilder<'a> {
465         let mut result = DiagnosticBuilder::new(self, Level::Fatal, msg);
466         result.set_span(sp);
467         result.code(code);
468         result
469     }
470     pub fn struct_fatal<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
471         DiagnosticBuilder::new(self, Level::Fatal, msg)
472     }
473
474     pub fn cancel(&self, err: &mut DiagnosticBuilder) {
475         err.cancel();
476     }
477
478     fn panic_if_treat_err_as_bug(&self) {
479         if self.flags.treat_err_as_bug {
480             panic!("encountered error with `-Z treat_err_as_bug");
481         }
482     }
483
484     pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> FatalError {
485         self.emit(&sp.into(), msg, Fatal);
486         FatalError
487     }
488     pub fn span_fatal_with_code<S: Into<MultiSpan>>(&self,
489                                                     sp: S,
490                                                     msg: &str,
491                                                     code: DiagnosticId)
492                                                     -> FatalError {
493         self.emit_with_code(&sp.into(), msg, code, Fatal);
494         FatalError
495     }
496     pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
497         self.emit(&sp.into(), msg, Error);
498     }
499     pub fn mut_span_err<'a, S: Into<MultiSpan>>(&'a self,
500                                                 sp: S,
501                                                 msg: &str)
502                                                 -> DiagnosticBuilder<'a> {
503         let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
504         result.set_span(sp);
505         result
506     }
507     pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: DiagnosticId) {
508         self.emit_with_code(&sp.into(), msg, code, Error);
509     }
510     pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
511         self.emit(&sp.into(), msg, Warning);
512     }
513     pub fn span_warn_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: DiagnosticId) {
514         self.emit_with_code(&sp.into(), msg, code, Warning);
515     }
516     pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
517         self.emit(&sp.into(), msg, Bug);
518         panic!(ExplicitBug);
519     }
520     pub fn delay_span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
521         if self.flags.treat_err_as_bug {
522             // FIXME: don't abort here if report_delayed_bugs is off
523             self.span_bug(sp, msg);
524         }
525         let mut diagnostic = Diagnostic::new(Level::Bug, msg);
526         diagnostic.set_span(sp.into());
527         self.delay_as_bug(diagnostic);
528     }
529     fn delay_as_bug(&self, diagnostic: Diagnostic) {
530         if self.flags.report_delayed_bugs {
531             DiagnosticBuilder::new_diagnostic(self, diagnostic.clone()).emit();
532         }
533         self.delayed_span_bug.borrow_mut().push(diagnostic);
534     }
535     pub fn span_bug_no_panic<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
536         self.emit(&sp.into(), msg, Bug);
537     }
538     pub fn span_note_without_error<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
539         self.emit(&sp.into(), msg, Note);
540     }
541     pub fn span_note_diag<'a>(&'a self,
542                               sp: Span,
543                               msg: &str)
544                               -> DiagnosticBuilder<'a> {
545         let mut db = DiagnosticBuilder::new(self, Note, msg);
546         db.set_span(sp);
547         db
548     }
549     pub fn span_unimpl<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
550         self.span_bug(sp, &format!("unimplemented {}", msg));
551     }
552     pub fn failure(&self, msg: &str) {
553         DiagnosticBuilder::new(self, FailureNote, msg).emit()
554     }
555     pub fn fatal(&self, msg: &str) -> FatalError {
556         if self.flags.treat_err_as_bug {
557             self.bug(msg);
558         }
559         DiagnosticBuilder::new(self, Fatal, msg).emit();
560         FatalError
561     }
562     pub fn err(&self, msg: &str) {
563         if self.flags.treat_err_as_bug {
564             self.bug(msg);
565         }
566         let mut db = DiagnosticBuilder::new(self, Error, msg);
567         db.emit();
568     }
569     pub fn warn(&self, msg: &str) {
570         let mut db = DiagnosticBuilder::new(self, Warning, msg);
571         db.emit();
572     }
573     pub fn note_without_error(&self, msg: &str) {
574         let mut db = DiagnosticBuilder::new(self, Note, msg);
575         db.emit();
576     }
577     pub fn bug(&self, msg: &str) -> ! {
578         let mut db = DiagnosticBuilder::new(self, Bug, msg);
579         db.emit();
580         panic!(ExplicitBug);
581     }
582     pub fn unimpl(&self, msg: &str) -> ! {
583         self.bug(&format!("unimplemented {}", msg));
584     }
585
586     fn bump_err_count(&self) {
587         self.panic_if_treat_err_as_bug();
588         self.err_count.fetch_add(1, SeqCst);
589     }
590
591     pub fn err_count(&self) -> usize {
592         self.err_count.load(SeqCst)
593     }
594
595     pub fn has_errors(&self) -> bool {
596         self.err_count() > 0
597     }
598
599     pub fn print_error_count(&self) {
600         let s = match self.err_count() {
601             0 => return,
602             1 => "aborting due to previous error".to_string(),
603             _ => format!("aborting due to {} previous errors", self.err_count())
604         };
605
606         let _ = self.fatal(&s);
607
608         let can_show_explain = self.emitter.borrow().should_show_explain();
609         let are_there_diagnostics = !self.emitted_diagnostic_codes.borrow().is_empty();
610         if can_show_explain && are_there_diagnostics {
611             let mut error_codes =
612                 self.emitted_diagnostic_codes.borrow()
613                                              .clone()
614                                              .into_iter()
615                                              .filter_map(|x| match x {
616                                                  DiagnosticId::Error(ref s) => Some(s.clone()),
617                                                  _ => None,
618                                              })
619                                              .collect::<Vec<_>>();
620             if !error_codes.is_empty() {
621                 error_codes.sort();
622                 if error_codes.len() > 1 {
623                     let limit = if error_codes.len() > 9 { 9 } else { error_codes.len() };
624                     self.failure(&format!("Some errors occurred: {}{}",
625                                           error_codes[..limit].join(", "),
626                                           if error_codes.len() > 9 { "..." } else { "." }));
627                     self.failure(&format!("For more information about an error, try \
628                                            `rustc --explain {}`.",
629                                           &error_codes[0]));
630                 } else {
631                     self.failure(&format!("For more information about this error, try \
632                                            `rustc --explain {}`.",
633                                           &error_codes[0]));
634                 }
635             }
636         }
637     }
638
639     pub fn abort_if_errors(&self) {
640         if self.err_count() == 0 {
641             return;
642         }
643         FatalError.raise();
644     }
645     pub fn emit(&self, msp: &MultiSpan, msg: &str, lvl: Level) {
646         if lvl == Warning && !self.flags.can_emit_warnings {
647             return;
648         }
649         let mut db = DiagnosticBuilder::new(self, lvl, msg);
650         db.set_span(msp.clone());
651         db.emit();
652         if !self.continue_after_error.get() {
653             self.abort_if_errors();
654         }
655     }
656     pub fn emit_with_code(&self, msp: &MultiSpan, msg: &str, code: DiagnosticId, lvl: Level) {
657         if lvl == Warning && !self.flags.can_emit_warnings {
658             return;
659         }
660         let mut db = DiagnosticBuilder::new_with_code(self, lvl, Some(code), msg);
661         db.set_span(msp.clone());
662         db.emit();
663         if !self.continue_after_error.get() {
664             self.abort_if_errors();
665         }
666     }
667
668     /// `true` if we haven't taught a diagnostic with this code already.
669     /// The caller must then teach the user about such a diagnostic.
670     ///
671     /// Used to suppress emitting the same error multiple times with extended explanation when
672     /// calling `-Zteach`.
673     pub fn must_teach(&self, code: &DiagnosticId) -> bool {
674         self.taught_diagnostics.borrow_mut().insert(code.clone())
675     }
676
677     pub fn force_print_db(&self, mut db: DiagnosticBuilder) {
678         self.emitter.borrow_mut().emit(&db);
679         db.cancel();
680     }
681
682     fn emit_db(&self, db: &DiagnosticBuilder) {
683         let diagnostic = &**db;
684
685         TRACK_DIAGNOSTICS.with(|track_diagnostics| {
686             track_diagnostics.get()(diagnostic);
687         });
688
689         if let Some(ref code) = diagnostic.code {
690             self.emitted_diagnostic_codes.borrow_mut().insert(code.clone());
691         }
692
693         let diagnostic_hash = {
694             use std::hash::Hash;
695             let mut hasher = StableHasher::new();
696             diagnostic.hash(&mut hasher);
697             hasher.finish()
698         };
699
700         // Only emit the diagnostic if we haven't already emitted an equivalent
701         // one:
702         if self.emitted_diagnostics.borrow_mut().insert(diagnostic_hash) {
703             self.emitter.borrow_mut().emit(db);
704             if db.is_error() {
705                 self.bump_err_count();
706             }
707         }
708     }
709 }
710
711
712 #[derive(Copy, PartialEq, Clone, Hash, Debug, RustcEncodable, RustcDecodable)]
713 pub enum Level {
714     Bug,
715     Fatal,
716     // An error which while not immediately fatal, should stop the compiler
717     // progressing beyond the current phase.
718     PhaseFatal,
719     Error,
720     Warning,
721     Note,
722     Help,
723     Cancelled,
724     FailureNote,
725 }
726
727 impl fmt::Display for Level {
728     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
729         self.to_str().fmt(f)
730     }
731 }
732
733 impl Level {
734     fn color(self) -> ColorSpec {
735         let mut spec = ColorSpec::new();
736         match self {
737             Bug | Fatal | PhaseFatal | Error => {
738                 spec.set_fg(Some(Color::Red))
739                     .set_intense(true);
740             }
741             Warning => {
742                 spec.set_fg(Some(Color::Yellow))
743                     .set_intense(cfg!(windows));
744             }
745             Note => {
746                 spec.set_fg(Some(Color::Green))
747                     .set_intense(true);
748             }
749             Help => {
750                 spec.set_fg(Some(Color::Cyan))
751                     .set_intense(true);
752             }
753             FailureNote => {}
754             Cancelled => unreachable!(),
755         }
756         spec
757     }
758
759     pub fn to_str(self) -> &'static str {
760         match self {
761             Bug => "error: internal compiler error",
762             Fatal | PhaseFatal | Error => "error",
763             Warning => "warning",
764             Note => "note",
765             Help => "help",
766             FailureNote => "",
767             Cancelled => panic!("Shouldn't call on cancelled error"),
768         }
769     }
770
771     pub fn is_failure_note(&self) -> bool {
772         match *self {
773             FailureNote => true,
774             _ => false,
775         }
776     }
777 }