]> git.proxmox.com Git - rustc.git/blob - src/librustc_errors/lib.rs
New upstream version 1.12.0+dfsg1
[rustc.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 #![crate_name = "rustc_errors"]
12 #![unstable(feature = "rustc_private", issue = "27812")]
13 #![crate_type = "dylib"]
14 #![crate_type = "rlib"]
15 #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
16 html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
17 html_root_url = "https://doc.rust-lang.org/nightly/")]
18 #![cfg_attr(not(stage0), deny(warnings))]
19
20 #![feature(custom_attribute)]
21 #![allow(unused_attributes)]
22 #![feature(rustc_private)]
23 #![feature(staged_api)]
24 #![feature(question_mark)]
25 #![feature(range_contains)]
26 #![feature(libc)]
27 #![feature(unicode)]
28
29 extern crate serialize;
30 extern crate term;
31 #[macro_use] extern crate log;
32 #[macro_use] extern crate libc;
33 extern crate rustc_unicode;
34 extern crate serialize as rustc_serialize; // used by deriving
35 extern crate syntax_pos;
36
37 pub use emitter::ColorConfig;
38
39 use self::Level::*;
40 use self::RenderSpan::*;
41
42 use emitter::{Emitter, EmitterWriter};
43
44 use std::cell::{RefCell, Cell};
45 use std::{error, fmt};
46 use std::rc::Rc;
47 use std::thread::panicking;
48
49 pub mod emitter;
50 pub mod snippet;
51 pub mod registry;
52 pub mod styled_buffer;
53
54 use syntax_pos::{BytePos, Loc, FileLinesResult, FileName, MultiSpan, Span, NO_EXPANSION };
55 use syntax_pos::{MacroBacktrace};
56
57 #[derive(Clone)]
58 pub enum RenderSpan {
59 /// A FullSpan renders with both with an initial line for the
60 /// message, prefixed by file:linenum, followed by a summary of
61 /// the source code covered by the span.
62 FullSpan(MultiSpan),
63
64 /// A suggestion renders with both with an initial line for the
65 /// message, prefixed by file:linenum, followed by a summary
66 /// of hypothetical source code, where each `String` is spliced
67 /// into the lines in place of the code covered by each span.
68 Suggestion(CodeSuggestion),
69 }
70
71 #[derive(Clone)]
72 pub struct CodeSuggestion {
73 pub msp: MultiSpan,
74 pub substitutes: Vec<String>,
75 }
76
77 pub trait CodeMapper {
78 fn lookup_char_pos(&self, pos: BytePos) -> Loc;
79 fn span_to_lines(&self, sp: Span) -> FileLinesResult;
80 fn span_to_string(&self, sp: Span) -> String;
81 fn span_to_filename(&self, sp: Span) -> FileName;
82 fn macro_backtrace(&self, span: Span) -> Vec<MacroBacktrace>;
83 }
84
85 impl CodeSuggestion {
86 /// Returns the assembled code suggestion.
87 pub fn splice_lines(&self, cm: &CodeMapper) -> String {
88 use syntax_pos::{CharPos, Loc, Pos};
89
90 fn push_trailing(buf: &mut String, line_opt: Option<&str>,
91 lo: &Loc, hi_opt: Option<&Loc>) {
92 let (lo, hi_opt) = (lo.col.to_usize(), hi_opt.map(|hi|hi.col.to_usize()));
93 if let Some(line) = line_opt {
94 if line.len() > lo {
95 buf.push_str(match hi_opt {
96 Some(hi) => &line[lo..hi],
97 None => &line[lo..],
98 });
99 }
100 if let None = hi_opt {
101 buf.push('\n');
102 }
103 }
104 }
105
106 let mut primary_spans = self.msp.primary_spans().to_owned();
107
108 assert_eq!(primary_spans.len(), self.substitutes.len());
109 if primary_spans.is_empty() {
110 return format!("");
111 }
112
113 // Assumption: all spans are in the same file, and all spans
114 // are disjoint. Sort in ascending order.
115 primary_spans.sort_by_key(|sp| sp.lo);
116
117 // Find the bounding span.
118 let lo = primary_spans.iter().map(|sp| sp.lo).min().unwrap();
119 let hi = primary_spans.iter().map(|sp| sp.hi).min().unwrap();
120 let bounding_span = Span { lo: lo, hi: hi, expn_id: NO_EXPANSION };
121 let lines = cm.span_to_lines(bounding_span).unwrap();
122 assert!(!lines.lines.is_empty());
123
124 // To build up the result, we do this for each span:
125 // - push the line segment trailing the previous span
126 // (at the beginning a "phantom" span pointing at the start of the line)
127 // - push lines between the previous and current span (if any)
128 // - if the previous and current span are not on the same line
129 // push the line segment leading up to the current span
130 // - splice in the span substitution
131 //
132 // Finally push the trailing line segment of the last span
133 let fm = &lines.file;
134 let mut prev_hi = cm.lookup_char_pos(bounding_span.lo);
135 prev_hi.col = CharPos::from_usize(0);
136
137 let mut prev_line = fm.get_line(lines.lines[0].line_index);
138 let mut buf = String::new();
139
140 for (sp, substitute) in primary_spans.iter().zip(self.substitutes.iter()) {
141 let cur_lo = cm.lookup_char_pos(sp.lo);
142 if prev_hi.line == cur_lo.line {
143 push_trailing(&mut buf, prev_line, &prev_hi, Some(&cur_lo));
144 } else {
145 push_trailing(&mut buf, prev_line, &prev_hi, None);
146 // push lines between the previous and current span (if any)
147 for idx in prev_hi.line..(cur_lo.line - 1) {
148 if let Some(line) = fm.get_line(idx) {
149 buf.push_str(line);
150 buf.push('\n');
151 }
152 }
153 if let Some(cur_line) = fm.get_line(cur_lo.line - 1) {
154 buf.push_str(&cur_line[.. cur_lo.col.to_usize()]);
155 }
156 }
157 buf.push_str(substitute);
158 prev_hi = cm.lookup_char_pos(sp.hi);
159 prev_line = fm.get_line(prev_hi.line - 1);
160 }
161 push_trailing(&mut buf, prev_line, &prev_hi, None);
162 // remove trailing newline
163 buf.pop();
164 buf
165 }
166 }
167
168 /// Used as a return value to signify a fatal error occurred. (It is also
169 /// used as the argument to panic at the moment, but that will eventually
170 /// not be true.)
171 #[derive(Copy, Clone, Debug)]
172 #[must_use]
173 pub struct FatalError;
174
175 impl fmt::Display for FatalError {
176 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
177 write!(f, "parser fatal error")
178 }
179 }
180
181 impl error::Error for FatalError {
182 fn description(&self) -> &str {
183 "The parser has encountered a fatal error"
184 }
185 }
186
187 /// Signifies that the compiler died with an explicit call to `.bug`
188 /// or `.span_bug` rather than a failed assertion, etc.
189 #[derive(Copy, Clone, Debug)]
190 pub struct ExplicitBug;
191
192 impl fmt::Display for ExplicitBug {
193 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
194 write!(f, "parser internal bug")
195 }
196 }
197
198 impl error::Error for ExplicitBug {
199 fn description(&self) -> &str {
200 "The parser has encountered an internal bug"
201 }
202 }
203
204 /// Used for emitting structured error messages and other diagnostic information.
205 #[must_use]
206 #[derive(Clone)]
207 pub struct DiagnosticBuilder<'a> {
208 handler: &'a Handler,
209 pub level: Level,
210 pub message: String,
211 pub code: Option<String>,
212 pub span: MultiSpan,
213 pub children: Vec<SubDiagnostic>,
214 }
215
216 /// For example a note attached to an error.
217 #[derive(Clone)]
218 pub struct SubDiagnostic {
219 pub level: Level,
220 pub message: String,
221 pub span: MultiSpan,
222 pub render_span: Option<RenderSpan>,
223 }
224
225 impl<'a> DiagnosticBuilder<'a> {
226 /// Emit the diagnostic.
227 pub fn emit(&mut self) {
228 if self.cancelled() {
229 return;
230 }
231
232 self.handler.emitter.borrow_mut().emit(&self);
233 self.cancel();
234 self.handler.panic_if_treat_err_as_bug();
235
236 // if self.is_fatal() {
237 // panic!(FatalError);
238 // }
239 }
240
241 /// Cancel the diagnostic (a structured diagnostic must either be emitted or
242 /// cancelled or it will panic when dropped).
243 /// BEWARE: if this DiagnosticBuilder is an error, then creating it will
244 /// bump the error count on the Handler and cancelling it won't undo that.
245 /// If you want to decrement the error count you should use `Handler::cancel`.
246 pub fn cancel(&mut self) {
247 self.level = Level::Cancelled;
248 }
249
250 pub fn cancelled(&self) -> bool {
251 self.level == Level::Cancelled
252 }
253
254 pub fn is_fatal(&self) -> bool {
255 self.level == Level::Fatal
256 }
257
258 /// Add a span/label to be included in the resulting snippet.
259 /// This is pushed onto the `MultiSpan` that was created when the
260 /// diagnostic was first built. If you don't call this function at
261 /// all, and you just supplied a `Span` to create the diagnostic,
262 /// then the snippet will just include that `Span`, which is
263 /// called the primary span.
264 pub fn span_label(&mut self, span: Span, label: &fmt::Display)
265 -> &mut DiagnosticBuilder<'a> {
266 self.span.push_span_label(span, format!("{}", label));
267 self
268 }
269
270 pub fn note_expected_found(&mut self,
271 label: &fmt::Display,
272 expected: &fmt::Display,
273 found: &fmt::Display)
274 -> &mut DiagnosticBuilder<'a>
275 {
276 // For now, just attach these as notes
277 self.note(&format!("expected {} `{}`", label, expected));
278 self.note(&format!(" found {} `{}`", label, found));
279 self
280 }
281
282 pub fn note(&mut self, msg: &str) -> &mut DiagnosticBuilder<'a> {
283 self.sub(Level::Note, msg, MultiSpan::new(), None);
284 self
285 }
286 pub fn span_note<S: Into<MultiSpan>>(&mut self,
287 sp: S,
288 msg: &str)
289 -> &mut DiagnosticBuilder<'a> {
290 self.sub(Level::Note, msg, sp.into(), None);
291 self
292 }
293 pub fn warn(&mut self, msg: &str) -> &mut DiagnosticBuilder<'a> {
294 self.sub(Level::Warning, msg, MultiSpan::new(), None);
295 self
296 }
297 pub fn span_warn<S: Into<MultiSpan>>(&mut self,
298 sp: S,
299 msg: &str)
300 -> &mut DiagnosticBuilder<'a> {
301 self.sub(Level::Warning, msg, sp.into(), None);
302 self
303 }
304 pub fn help(&mut self , msg: &str) -> &mut DiagnosticBuilder<'a> {
305 self.sub(Level::Help, msg, MultiSpan::new(), None);
306 self
307 }
308 pub fn span_help<S: Into<MultiSpan>>(&mut self,
309 sp: S,
310 msg: &str)
311 -> &mut DiagnosticBuilder<'a> {
312 self.sub(Level::Help, msg, sp.into(), None);
313 self
314 }
315 /// Prints out a message with a suggested edit of the code.
316 ///
317 /// See `diagnostic::RenderSpan::Suggestion` for more information.
318 pub fn span_suggestion<S: Into<MultiSpan>>(&mut self,
319 sp: S,
320 msg: &str,
321 suggestion: String)
322 -> &mut DiagnosticBuilder<'a> {
323 self.sub(Level::Help, msg, MultiSpan::new(), Some(Suggestion(CodeSuggestion {
324 msp: sp.into(),
325 substitutes: vec![suggestion],
326 })));
327 self
328 }
329
330 pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self {
331 self.span = sp.into();
332 self
333 }
334
335 pub fn code(&mut self, s: String) -> &mut Self {
336 self.code = Some(s);
337 self
338 }
339
340 pub fn message(&self) -> &str {
341 &self.message
342 }
343
344 pub fn level(&self) -> Level {
345 self.level
346 }
347
348 /// Convenience function for internal use, clients should use one of the
349 /// struct_* methods on Handler.
350 fn new(handler: &'a Handler,
351 level: Level,
352 message: &str) -> DiagnosticBuilder<'a> {
353 DiagnosticBuilder::new_with_code(handler, level, None, message)
354 }
355
356 /// Convenience function for internal use, clients should use one of the
357 /// struct_* methods on Handler.
358 fn new_with_code(handler: &'a Handler,
359 level: Level,
360 code: Option<String>,
361 message: &str) -> DiagnosticBuilder<'a> {
362 DiagnosticBuilder {
363 handler: handler,
364 level: level,
365 message: message.to_owned(),
366 code: code,
367 span: MultiSpan::new(),
368 children: vec![],
369 }
370 }
371
372 /// Convenience function for internal use, clients should use one of the
373 /// public methods above.
374 fn sub(&mut self,
375 level: Level,
376 message: &str,
377 span: MultiSpan,
378 render_span: Option<RenderSpan>) {
379 let sub = SubDiagnostic {
380 level: level,
381 message: message.to_owned(),
382 span: span,
383 render_span: render_span,
384 };
385 self.children.push(sub);
386 }
387 }
388
389 impl<'a> fmt::Debug for DiagnosticBuilder<'a> {
390 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
391 self.message.fmt(f)
392 }
393 }
394
395 /// Destructor bomb - a DiagnosticBuilder must be either emitted or cancelled or
396 /// we emit a bug.
397 impl<'a> Drop for DiagnosticBuilder<'a> {
398 fn drop(&mut self) {
399 if !panicking() && !self.cancelled() {
400 let mut db = DiagnosticBuilder::new(self.handler,
401 Bug,
402 "Error constructed but not emitted");
403 db.emit();
404 panic!();
405 }
406 }
407 }
408
409 /// A handler deals with errors; certain errors
410 /// (fatal, bug, unimpl) may cause immediate exit,
411 /// others log errors for later reporting.
412 pub struct Handler {
413 err_count: Cell<usize>,
414 emitter: RefCell<Box<Emitter>>,
415 pub can_emit_warnings: bool,
416 treat_err_as_bug: bool,
417 continue_after_error: Cell<bool>,
418 delayed_span_bug: RefCell<Option<(MultiSpan, String)>>,
419 }
420
421 impl Handler {
422 pub fn with_tty_emitter(color_config: ColorConfig,
423 can_emit_warnings: bool,
424 treat_err_as_bug: bool,
425 cm: Option<Rc<CodeMapper>>)
426 -> Handler {
427 let emitter = Box::new(EmitterWriter::stderr(color_config, cm));
428 Handler::with_emitter(can_emit_warnings, treat_err_as_bug, emitter)
429 }
430
431 pub fn with_emitter(can_emit_warnings: bool,
432 treat_err_as_bug: bool,
433 e: Box<Emitter>) -> Handler {
434 Handler {
435 err_count: Cell::new(0),
436 emitter: RefCell::new(e),
437 can_emit_warnings: can_emit_warnings,
438 treat_err_as_bug: treat_err_as_bug,
439 continue_after_error: Cell::new(true),
440 delayed_span_bug: RefCell::new(None),
441 }
442 }
443
444 pub fn set_continue_after_error(&self, continue_after_error: bool) {
445 self.continue_after_error.set(continue_after_error);
446 }
447
448 pub fn struct_dummy<'a>(&'a self) -> DiagnosticBuilder<'a> {
449 DiagnosticBuilder::new(self, Level::Cancelled, "")
450 }
451
452 pub fn struct_span_warn<'a, S: Into<MultiSpan>>(&'a self,
453 sp: S,
454 msg: &str)
455 -> DiagnosticBuilder<'a> {
456 let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
457 result.set_span(sp);
458 if !self.can_emit_warnings {
459 result.cancel();
460 }
461 result
462 }
463 pub fn struct_span_warn_with_code<'a, S: Into<MultiSpan>>(&'a self,
464 sp: S,
465 msg: &str,
466 code: &str)
467 -> DiagnosticBuilder<'a> {
468 let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
469 result.set_span(sp);
470 result.code(code.to_owned());
471 if !self.can_emit_warnings {
472 result.cancel();
473 }
474 result
475 }
476 pub fn struct_warn<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
477 let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
478 if !self.can_emit_warnings {
479 result.cancel();
480 }
481 result
482 }
483 pub fn struct_span_err<'a, S: Into<MultiSpan>>(&'a self,
484 sp: S,
485 msg: &str)
486 -> DiagnosticBuilder<'a> {
487 self.bump_err_count();
488 let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
489 result.set_span(sp);
490 result
491 }
492 pub fn struct_span_err_with_code<'a, S: Into<MultiSpan>>(&'a self,
493 sp: S,
494 msg: &str,
495 code: &str)
496 -> DiagnosticBuilder<'a> {
497 self.bump_err_count();
498 let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
499 result.set_span(sp);
500 result.code(code.to_owned());
501 result
502 }
503 pub fn struct_err<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
504 self.bump_err_count();
505 DiagnosticBuilder::new(self, Level::Error, msg)
506 }
507 pub fn struct_span_fatal<'a, S: Into<MultiSpan>>(&'a self,
508 sp: S,
509 msg: &str)
510 -> DiagnosticBuilder<'a> {
511 self.bump_err_count();
512 let mut result = DiagnosticBuilder::new(self, Level::Fatal, msg);
513 result.set_span(sp);
514 result
515 }
516 pub fn struct_span_fatal_with_code<'a, S: Into<MultiSpan>>(&'a self,
517 sp: S,
518 msg: &str,
519 code: &str)
520 -> DiagnosticBuilder<'a> {
521 self.bump_err_count();
522 let mut result = DiagnosticBuilder::new(self, Level::Fatal, msg);
523 result.set_span(sp);
524 result.code(code.to_owned());
525 result
526 }
527 pub fn struct_fatal<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
528 self.bump_err_count();
529 DiagnosticBuilder::new(self, Level::Fatal, msg)
530 }
531
532 pub fn cancel(&self, err: &mut DiagnosticBuilder) {
533 if err.level == Level::Error || err.level == Level::Fatal {
534 self.err_count.set(
535 self.err_count.get().checked_sub(1)
536 .expect("cancelled an error but err_count is 0")
537 );
538 }
539 err.cancel();
540 }
541
542 fn panic_if_treat_err_as_bug(&self) {
543 if self.treat_err_as_bug {
544 panic!("encountered error with `-Z treat_err_as_bug");
545 }
546 }
547
548 pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: &str)
549 -> FatalError {
550 self.emit(&sp.into(), msg, Fatal);
551 self.bump_err_count();
552 self.panic_if_treat_err_as_bug();
553 return FatalError;
554 }
555 pub fn span_fatal_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str)
556 -> FatalError {
557 self.emit_with_code(&sp.into(), msg, code, Fatal);
558 self.bump_err_count();
559 self.panic_if_treat_err_as_bug();
560 return FatalError;
561 }
562 pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
563 self.emit(&sp.into(), msg, Error);
564 self.bump_err_count();
565 self.panic_if_treat_err_as_bug();
566 }
567 pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) {
568 self.emit_with_code(&sp.into(), msg, code, Error);
569 self.bump_err_count();
570 self.panic_if_treat_err_as_bug();
571 }
572 pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
573 self.emit(&sp.into(), msg, Warning);
574 }
575 pub fn span_warn_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) {
576 self.emit_with_code(&sp.into(), msg, code, Warning);
577 }
578 pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
579 self.emit(&sp.into(), msg, Bug);
580 panic!(ExplicitBug);
581 }
582 pub fn delay_span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
583 let mut delayed = self.delayed_span_bug.borrow_mut();
584 *delayed = Some((sp.into(), msg.to_string()));
585 }
586 pub fn span_bug_no_panic<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
587 self.emit(&sp.into(), msg, Bug);
588 self.bump_err_count();
589 }
590 pub fn span_note_without_error<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
591 self.emit(&sp.into(), msg, Note);
592 }
593 pub fn span_unimpl<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
594 self.span_bug(sp, &format!("unimplemented {}", msg));
595 }
596 pub fn fatal(&self, msg: &str) -> FatalError {
597 if self.treat_err_as_bug {
598 self.bug(msg);
599 }
600 let mut db = DiagnosticBuilder::new(self,
601 Fatal,
602 msg);
603 db.emit();
604 self.bump_err_count();
605 FatalError
606 }
607 pub fn err(&self, msg: &str) {
608 if self.treat_err_as_bug {
609 self.bug(msg);
610 }
611 let mut db = DiagnosticBuilder::new(self,
612 Error,
613 msg);
614 db.emit();
615 self.bump_err_count();
616 }
617 pub fn warn(&self, msg: &str) {
618 let mut db = DiagnosticBuilder::new(self,
619 Warning,
620 msg);
621 db.emit();
622 }
623 pub fn note_without_error(&self, msg: &str) {
624 let mut db = DiagnosticBuilder::new(self,
625 Note,
626 msg);
627 db.emit();
628 }
629 pub fn bug(&self, msg: &str) -> ! {
630 let mut db = DiagnosticBuilder::new(self,
631 Bug,
632 msg);
633 db.emit();
634 panic!(ExplicitBug);
635 }
636 pub fn unimpl(&self, msg: &str) -> ! {
637 self.bug(&format!("unimplemented {}", msg));
638 }
639
640 pub fn bump_err_count(&self) {
641 self.err_count.set(self.err_count.get() + 1);
642 }
643
644 pub fn err_count(&self) -> usize {
645 self.err_count.get()
646 }
647
648 pub fn has_errors(&self) -> bool {
649 self.err_count.get() > 0
650 }
651 pub fn abort_if_errors(&self) {
652 let s;
653 match self.err_count.get() {
654 0 => {
655 let delayed_bug = self.delayed_span_bug.borrow();
656 match *delayed_bug {
657 Some((ref span, ref errmsg)) => {
658 self.span_bug(span.clone(), errmsg);
659 },
660 _ => {}
661 }
662
663 return;
664 }
665 1 => s = "aborting due to previous error".to_string(),
666 _ => {
667 s = format!("aborting due to {} previous errors",
668 self.err_count.get());
669 }
670 }
671
672 panic!(self.fatal(&s));
673 }
674 pub fn emit(&self,
675 msp: &MultiSpan,
676 msg: &str,
677 lvl: Level) {
678 if lvl == Warning && !self.can_emit_warnings { return }
679 let mut db = DiagnosticBuilder::new(self, lvl, msg);
680 db.set_span(msp.clone());
681 db.emit();
682 if !self.continue_after_error.get() { self.abort_if_errors(); }
683 }
684 pub fn emit_with_code(&self,
685 msp: &MultiSpan,
686 msg: &str,
687 code: &str,
688 lvl: Level) {
689 if lvl == Warning && !self.can_emit_warnings { return }
690 let mut db = DiagnosticBuilder::new_with_code(self,
691 lvl,
692 Some(code.to_owned()),
693 msg);
694 db.set_span(msp.clone());
695 db.emit();
696 if !self.continue_after_error.get() { self.abort_if_errors(); }
697 }
698 }
699
700
701 #[derive(Copy, PartialEq, Clone, Debug)]
702 pub enum Level {
703 Bug,
704 Fatal,
705 // An error which while not immediately fatal, should stop the compiler
706 // progressing beyond the current phase.
707 PhaseFatal,
708 Error,
709 Warning,
710 Note,
711 Help,
712 Cancelled,
713 }
714
715 impl fmt::Display for Level {
716 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
717 self.to_str().fmt(f)
718 }
719 }
720
721 impl Level {
722 pub fn color(self) -> term::color::Color {
723 match self {
724 Bug | Fatal | PhaseFatal | Error => term::color::BRIGHT_RED,
725 Warning => term::color::YELLOW,
726 Note => term::color::BRIGHT_GREEN,
727 Help => term::color::BRIGHT_CYAN,
728 Cancelled => unreachable!(),
729 }
730 }
731
732 pub fn to_str(self) -> &'static str {
733 match self {
734 Bug => "error: internal compiler error",
735 Fatal | PhaseFatal | Error => "error",
736 Warning => "warning",
737 Note => "note",
738 Help => "help",
739 Cancelled => panic!("Shouldn't call on cancelled error"),
740 }
741 }
742 }
743
744 pub fn expect<T, M>(diag: &Handler, opt: Option<T>, msg: M) -> T where
745 M: FnOnce() -> String,
746 {
747 match opt {
748 Some(t) => t,
749 None => diag.bug(&msg()),
750 }
751 }