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