]>
Commit | Line | Data |
---|---|---|
9cc50fc6 SL |
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 | ||
3157f602 XL |
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/")] | |
32a655c1 | 18 | #![deny(warnings)] |
3157f602 XL |
19 | |
20 | #![feature(custom_attribute)] | |
21 | #![allow(unused_attributes)] | |
22 | #![feature(rustc_private)] | |
23 | #![feature(staged_api)] | |
3157f602 XL |
24 | #![feature(range_contains)] |
25 | #![feature(libc)] | |
3157f602 | 26 | |
3157f602 | 27 | extern crate term; |
c30ab7b3 | 28 | extern crate libc; |
8bb4bdeb | 29 | extern crate serialize as rustc_serialize; |
3157f602 XL |
30 | extern crate syntax_pos; |
31 | ||
32 | pub use emitter::ColorConfig; | |
9cc50fc6 SL |
33 | |
34 | use self::Level::*; | |
9cc50fc6 | 35 | |
3157f602 | 36 | use emitter::{Emitter, EmitterWriter}; |
9cc50fc6 SL |
37 | |
38 | use std::cell::{RefCell, Cell}; | |
39 | use std::{error, fmt}; | |
9cc50fc6 | 40 | use std::rc::Rc; |
9cc50fc6 | 41 | |
c30ab7b3 SL |
42 | pub mod diagnostic; |
43 | pub mod diagnostic_builder; | |
9cc50fc6 | 44 | pub mod emitter; |
a7813a04 | 45 | pub mod snippet; |
3157f602 | 46 | pub mod registry; |
5bcae85e | 47 | pub mod styled_buffer; |
9e0c209e | 48 | mod lock; |
3157f602 | 49 | |
c30ab7b3 SL |
50 | use syntax_pos::{BytePos, Loc, FileLinesResult, FileName, MultiSpan, Span, NO_EXPANSION}; |
51 | use syntax_pos::MacroBacktrace; | |
9cc50fc6 | 52 | |
8bb4bdeb | 53 | #[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)] |
9cc50fc6 SL |
54 | pub enum RenderSpan { |
55 | /// A FullSpan renders with both with an initial line for the | |
56 | /// message, prefixed by file:linenum, followed by a summary of | |
57 | /// the source code covered by the span. | |
7453a54e | 58 | FullSpan(MultiSpan), |
9cc50fc6 | 59 | |
9cc50fc6 SL |
60 | /// A suggestion renders with both with an initial line for the |
61 | /// message, prefixed by file:linenum, followed by a summary | |
7453a54e SL |
62 | /// of hypothetical source code, where each `String` is spliced |
63 | /// into the lines in place of the code covered by each span. | |
64 | Suggestion(CodeSuggestion), | |
7453a54e SL |
65 | } |
66 | ||
8bb4bdeb | 67 | #[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)] |
7453a54e | 68 | pub struct CodeSuggestion { |
3157f602 XL |
69 | pub msp: MultiSpan, |
70 | pub substitutes: Vec<String>, | |
71 | } | |
72 | ||
73 | pub trait CodeMapper { | |
74 | fn lookup_char_pos(&self, pos: BytePos) -> Loc; | |
75 | fn span_to_lines(&self, sp: Span) -> FileLinesResult; | |
76 | fn span_to_string(&self, sp: Span) -> String; | |
77 | fn span_to_filename(&self, sp: Span) -> FileName; | |
78 | fn macro_backtrace(&self, span: Span) -> Vec<MacroBacktrace>; | |
9e0c209e | 79 | fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option<Span>; |
9cc50fc6 SL |
80 | } |
81 | ||
7453a54e SL |
82 | impl CodeSuggestion { |
83 | /// Returns the assembled code suggestion. | |
3157f602 XL |
84 | pub fn splice_lines(&self, cm: &CodeMapper) -> String { |
85 | use syntax_pos::{CharPos, Loc, Pos}; | |
7453a54e | 86 | |
c30ab7b3 SL |
87 | fn push_trailing(buf: &mut String, |
88 | line_opt: Option<&str>, | |
89 | lo: &Loc, | |
90 | hi_opt: Option<&Loc>) { | |
91 | let (lo, hi_opt) = (lo.col.to_usize(), hi_opt.map(|hi| hi.col.to_usize())); | |
7453a54e | 92 | if let Some(line) = line_opt { |
8bb4bdeb XL |
93 | if let Some(lo) = line.char_indices().map(|(i, _)| i).nth(lo) { |
94 | let hi_opt = hi_opt.and_then(|hi| line.char_indices().map(|(i, _)| i).nth(hi)); | |
7453a54e SL |
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 | } | |
9cc50fc6 | 104 | } |
7453a54e | 105 | |
a7813a04 XL |
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(); | |
c30ab7b3 SL |
120 | let bounding_span = Span { |
121 | lo: lo, | |
122 | hi: hi, | |
123 | expn_id: NO_EXPANSION, | |
124 | }; | |
a7813a04 XL |
125 | let lines = cm.span_to_lines(bounding_span).unwrap(); |
126 | assert!(!lines.lines.is_empty()); | |
7453a54e SL |
127 | |
128 | // To build up the result, we do this for each span: | |
129 | // - push the line segment trailing the previous span | |
130 | // (at the beginning a "phantom" span pointing at the start of the line) | |
131 | // - push lines between the previous and current span (if any) | |
132 | // - if the previous and current span are not on the same line | |
133 | // push the line segment leading up to the current span | |
134 | // - splice in the span substitution | |
135 | // | |
136 | // Finally push the trailing line segment of the last span | |
137 | let fm = &lines.file; | |
a7813a04 | 138 | let mut prev_hi = cm.lookup_char_pos(bounding_span.lo); |
7453a54e SL |
139 | prev_hi.col = CharPos::from_usize(0); |
140 | ||
141 | let mut prev_line = fm.get_line(lines.lines[0].line_index); | |
142 | let mut buf = String::new(); | |
143 | ||
a7813a04 | 144 | for (sp, substitute) in primary_spans.iter().zip(self.substitutes.iter()) { |
7453a54e SL |
145 | let cur_lo = cm.lookup_char_pos(sp.lo); |
146 | if prev_hi.line == cur_lo.line { | |
147 | push_trailing(&mut buf, prev_line, &prev_hi, Some(&cur_lo)); | |
148 | } else { | |
149 | push_trailing(&mut buf, prev_line, &prev_hi, None); | |
150 | // push lines between the previous and current span (if any) | |
151 | for idx in prev_hi.line..(cur_lo.line - 1) { | |
152 | if let Some(line) = fm.get_line(idx) { | |
153 | buf.push_str(line); | |
154 | buf.push('\n'); | |
155 | } | |
156 | } | |
157 | if let Some(cur_line) = fm.get_line(cur_lo.line - 1) { | |
c30ab7b3 | 158 | buf.push_str(&cur_line[..cur_lo.col.to_usize()]); |
7453a54e SL |
159 | } |
160 | } | |
161 | buf.push_str(substitute); | |
162 | prev_hi = cm.lookup_char_pos(sp.hi); | |
163 | prev_line = fm.get_line(prev_hi.line - 1); | |
164 | } | |
165 | push_trailing(&mut buf, prev_line, &prev_hi, None); | |
166 | // remove trailing newline | |
167 | buf.pop(); | |
168 | buf | |
9cc50fc6 SL |
169 | } |
170 | } | |
171 | ||
172 | /// Used as a return value to signify a fatal error occurred. (It is also | |
173 | /// used as the argument to panic at the moment, but that will eventually | |
174 | /// not be true.) | |
175 | #[derive(Copy, Clone, Debug)] | |
176 | #[must_use] | |
177 | pub struct FatalError; | |
178 | ||
179 | impl fmt::Display for FatalError { | |
180 | fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { | |
181 | write!(f, "parser fatal error") | |
182 | } | |
183 | } | |
184 | ||
185 | impl error::Error for FatalError { | |
186 | fn description(&self) -> &str { | |
187 | "The parser has encountered a fatal error" | |
188 | } | |
189 | } | |
190 | ||
191 | /// Signifies that the compiler died with an explicit call to `.bug` | |
192 | /// or `.span_bug` rather than a failed assertion, etc. | |
193 | #[derive(Copy, Clone, Debug)] | |
194 | pub struct ExplicitBug; | |
195 | ||
196 | impl fmt::Display for ExplicitBug { | |
197 | fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { | |
198 | write!(f, "parser internal bug") | |
199 | } | |
200 | } | |
201 | ||
202 | impl error::Error for ExplicitBug { | |
203 | fn description(&self) -> &str { | |
204 | "The parser has encountered an internal bug" | |
205 | } | |
206 | } | |
207 | ||
c30ab7b3 SL |
208 | pub use diagnostic::{Diagnostic, SubDiagnostic}; |
209 | pub use diagnostic_builder::DiagnosticBuilder; | |
9cc50fc6 SL |
210 | |
211 | /// A handler deals with errors; certain errors | |
212 | /// (fatal, bug, unimpl) may cause immediate exit, | |
213 | /// others log errors for later reporting. | |
214 | pub struct Handler { | |
215 | err_count: Cell<usize>, | |
5bcae85e | 216 | emitter: RefCell<Box<Emitter>>, |
9cc50fc6 SL |
217 | pub can_emit_warnings: bool, |
218 | treat_err_as_bug: bool, | |
7453a54e SL |
219 | continue_after_error: Cell<bool>, |
220 | delayed_span_bug: RefCell<Option<(MultiSpan, String)>>, | |
9cc50fc6 SL |
221 | } |
222 | ||
223 | impl Handler { | |
224 | pub fn with_tty_emitter(color_config: ColorConfig, | |
9cc50fc6 SL |
225 | can_emit_warnings: bool, |
226 | treat_err_as_bug: bool, | |
5bcae85e | 227 | cm: Option<Rc<CodeMapper>>) |
9cc50fc6 | 228 | -> Handler { |
5bcae85e | 229 | let emitter = Box::new(EmitterWriter::stderr(color_config, cm)); |
9cc50fc6 SL |
230 | Handler::with_emitter(can_emit_warnings, treat_err_as_bug, emitter) |
231 | } | |
232 | ||
233 | pub fn with_emitter(can_emit_warnings: bool, | |
234 | treat_err_as_bug: bool, | |
c30ab7b3 SL |
235 | e: Box<Emitter>) |
236 | -> Handler { | |
9cc50fc6 SL |
237 | Handler { |
238 | err_count: Cell::new(0), | |
5bcae85e | 239 | emitter: RefCell::new(e), |
9cc50fc6 SL |
240 | can_emit_warnings: can_emit_warnings, |
241 | treat_err_as_bug: treat_err_as_bug, | |
7453a54e | 242 | continue_after_error: Cell::new(true), |
9cc50fc6 SL |
243 | delayed_span_bug: RefCell::new(None), |
244 | } | |
245 | } | |
246 | ||
7453a54e SL |
247 | pub fn set_continue_after_error(&self, continue_after_error: bool) { |
248 | self.continue_after_error.set(continue_after_error); | |
249 | } | |
250 | ||
9cc50fc6 | 251 | pub fn struct_dummy<'a>(&'a self) -> DiagnosticBuilder<'a> { |
a7813a04 | 252 | DiagnosticBuilder::new(self, Level::Cancelled, "") |
9cc50fc6 SL |
253 | } |
254 | ||
7453a54e SL |
255 | pub fn struct_span_warn<'a, S: Into<MultiSpan>>(&'a self, |
256 | sp: S, | |
257 | msg: &str) | |
258 | -> DiagnosticBuilder<'a> { | |
a7813a04 XL |
259 | let mut result = DiagnosticBuilder::new(self, Level::Warning, msg); |
260 | result.set_span(sp); | |
9cc50fc6 SL |
261 | if !self.can_emit_warnings { |
262 | result.cancel(); | |
263 | } | |
264 | result | |
265 | } | |
7453a54e SL |
266 | pub fn struct_span_warn_with_code<'a, S: Into<MultiSpan>>(&'a self, |
267 | sp: S, | |
268 | msg: &str, | |
269 | code: &str) | |
270 | -> DiagnosticBuilder<'a> { | |
a7813a04 XL |
271 | let mut result = DiagnosticBuilder::new(self, Level::Warning, msg); |
272 | result.set_span(sp); | |
9cc50fc6 SL |
273 | result.code(code.to_owned()); |
274 | if !self.can_emit_warnings { | |
275 | result.cancel(); | |
276 | } | |
277 | result | |
278 | } | |
279 | pub fn struct_warn<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> { | |
a7813a04 | 280 | let mut result = DiagnosticBuilder::new(self, Level::Warning, msg); |
9cc50fc6 SL |
281 | if !self.can_emit_warnings { |
282 | result.cancel(); | |
283 | } | |
284 | result | |
285 | } | |
7453a54e SL |
286 | pub fn struct_span_err<'a, S: Into<MultiSpan>>(&'a self, |
287 | sp: S, | |
288 | msg: &str) | |
289 | -> DiagnosticBuilder<'a> { | |
a7813a04 XL |
290 | let mut result = DiagnosticBuilder::new(self, Level::Error, msg); |
291 | result.set_span(sp); | |
9cc50fc6 SL |
292 | result |
293 | } | |
7453a54e SL |
294 | pub fn struct_span_err_with_code<'a, S: Into<MultiSpan>>(&'a self, |
295 | sp: S, | |
296 | msg: &str, | |
297 | code: &str) | |
298 | -> DiagnosticBuilder<'a> { | |
a7813a04 XL |
299 | let mut result = DiagnosticBuilder::new(self, Level::Error, msg); |
300 | result.set_span(sp); | |
9cc50fc6 SL |
301 | result.code(code.to_owned()); |
302 | result | |
303 | } | |
304 | pub fn struct_err<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> { | |
a7813a04 | 305 | DiagnosticBuilder::new(self, Level::Error, msg) |
9cc50fc6 | 306 | } |
7453a54e SL |
307 | pub fn struct_span_fatal<'a, S: Into<MultiSpan>>(&'a self, |
308 | sp: S, | |
309 | msg: &str) | |
310 | -> DiagnosticBuilder<'a> { | |
a7813a04 XL |
311 | let mut result = DiagnosticBuilder::new(self, Level::Fatal, msg); |
312 | result.set_span(sp); | |
9cc50fc6 SL |
313 | result |
314 | } | |
7453a54e SL |
315 | pub fn struct_span_fatal_with_code<'a, S: Into<MultiSpan>>(&'a self, |
316 | sp: S, | |
317 | msg: &str, | |
318 | code: &str) | |
319 | -> DiagnosticBuilder<'a> { | |
a7813a04 XL |
320 | let mut result = DiagnosticBuilder::new(self, Level::Fatal, msg); |
321 | result.set_span(sp); | |
9cc50fc6 SL |
322 | result.code(code.to_owned()); |
323 | result | |
324 | } | |
325 | pub fn struct_fatal<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> { | |
a7813a04 | 326 | DiagnosticBuilder::new(self, Level::Fatal, msg) |
9cc50fc6 SL |
327 | } |
328 | ||
5bcae85e | 329 | pub fn cancel(&self, err: &mut DiagnosticBuilder) { |
9cc50fc6 SL |
330 | err.cancel(); |
331 | } | |
332 | ||
a7813a04 | 333 | fn panic_if_treat_err_as_bug(&self) { |
9cc50fc6 | 334 | if self.treat_err_as_bug { |
a7813a04 | 335 | panic!("encountered error with `-Z treat_err_as_bug"); |
9cc50fc6 | 336 | } |
a7813a04 XL |
337 | } |
338 | ||
c30ab7b3 | 339 | pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> FatalError { |
a7813a04 | 340 | self.emit(&sp.into(), msg, Fatal); |
a7813a04 | 341 | self.panic_if_treat_err_as_bug(); |
9cc50fc6 SL |
342 | return FatalError; |
343 | } | |
c30ab7b3 SL |
344 | pub fn span_fatal_with_code<S: Into<MultiSpan>>(&self, |
345 | sp: S, | |
346 | msg: &str, | |
347 | code: &str) | |
a7813a04 XL |
348 | -> FatalError { |
349 | self.emit_with_code(&sp.into(), msg, code, Fatal); | |
a7813a04 | 350 | self.panic_if_treat_err_as_bug(); |
9cc50fc6 SL |
351 | return FatalError; |
352 | } | |
7453a54e | 353 | pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) { |
a7813a04 | 354 | self.emit(&sp.into(), msg, Error); |
a7813a04 | 355 | self.panic_if_treat_err_as_bug(); |
9cc50fc6 | 356 | } |
9e0c209e SL |
357 | pub fn mut_span_err<'a, S: Into<MultiSpan>>(&'a self, |
358 | sp: S, | |
359 | msg: &str) | |
360 | -> DiagnosticBuilder<'a> { | |
361 | let mut result = DiagnosticBuilder::new(self, Level::Error, msg); | |
362 | result.set_span(sp); | |
9e0c209e SL |
363 | result |
364 | } | |
7453a54e | 365 | pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) { |
a7813a04 | 366 | self.emit_with_code(&sp.into(), msg, code, Error); |
a7813a04 | 367 | self.panic_if_treat_err_as_bug(); |
9cc50fc6 | 368 | } |
7453a54e | 369 | pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) { |
a7813a04 | 370 | self.emit(&sp.into(), msg, Warning); |
9cc50fc6 | 371 | } |
7453a54e | 372 | pub fn span_warn_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) { |
a7813a04 | 373 | self.emit_with_code(&sp.into(), msg, code, Warning); |
9cc50fc6 | 374 | } |
7453a54e | 375 | pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! { |
a7813a04 | 376 | self.emit(&sp.into(), msg, Bug); |
9cc50fc6 SL |
377 | panic!(ExplicitBug); |
378 | } | |
7453a54e | 379 | pub fn delay_span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) { |
9cc50fc6 | 380 | let mut delayed = self.delayed_span_bug.borrow_mut(); |
7453a54e | 381 | *delayed = Some((sp.into(), msg.to_string())); |
9cc50fc6 | 382 | } |
7453a54e | 383 | pub fn span_bug_no_panic<S: Into<MultiSpan>>(&self, sp: S, msg: &str) { |
a7813a04 | 384 | self.emit(&sp.into(), msg, Bug); |
9cc50fc6 | 385 | } |
7453a54e | 386 | pub fn span_note_without_error<S: Into<MultiSpan>>(&self, sp: S, msg: &str) { |
5bcae85e | 387 | self.emit(&sp.into(), msg, Note); |
9cc50fc6 | 388 | } |
7453a54e | 389 | pub fn span_unimpl<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! { |
9cc50fc6 SL |
390 | self.span_bug(sp, &format!("unimplemented {}", msg)); |
391 | } | |
392 | pub fn fatal(&self, msg: &str) -> FatalError { | |
393 | if self.treat_err_as_bug { | |
394 | self.bug(msg); | |
395 | } | |
c30ab7b3 | 396 | let mut db = DiagnosticBuilder::new(self, Fatal, msg); |
5bcae85e | 397 | db.emit(); |
9cc50fc6 SL |
398 | FatalError |
399 | } | |
400 | pub fn err(&self, msg: &str) { | |
401 | if self.treat_err_as_bug { | |
402 | self.bug(msg); | |
403 | } | |
c30ab7b3 | 404 | let mut db = DiagnosticBuilder::new(self, Error, msg); |
5bcae85e | 405 | db.emit(); |
9cc50fc6 SL |
406 | } |
407 | pub fn warn(&self, msg: &str) { | |
c30ab7b3 | 408 | let mut db = DiagnosticBuilder::new(self, Warning, msg); |
5bcae85e | 409 | db.emit(); |
9cc50fc6 SL |
410 | } |
411 | pub fn note_without_error(&self, msg: &str) { | |
c30ab7b3 | 412 | let mut db = DiagnosticBuilder::new(self, Note, msg); |
5bcae85e | 413 | db.emit(); |
9cc50fc6 SL |
414 | } |
415 | pub fn bug(&self, msg: &str) -> ! { | |
c30ab7b3 | 416 | let mut db = DiagnosticBuilder::new(self, Bug, msg); |
5bcae85e | 417 | db.emit(); |
9cc50fc6 SL |
418 | panic!(ExplicitBug); |
419 | } | |
420 | pub fn unimpl(&self, msg: &str) -> ! { | |
421 | self.bug(&format!("unimplemented {}", msg)); | |
422 | } | |
423 | ||
424 | pub fn bump_err_count(&self) { | |
425 | self.err_count.set(self.err_count.get() + 1); | |
426 | } | |
427 | ||
428 | pub fn err_count(&self) -> usize { | |
429 | self.err_count.get() | |
430 | } | |
431 | ||
432 | pub fn has_errors(&self) -> bool { | |
433 | self.err_count.get() > 0 | |
434 | } | |
9cc50fc6 SL |
435 | pub fn abort_if_errors(&self) { |
436 | let s; | |
437 | match self.err_count.get() { | |
438 | 0 => { | |
439 | let delayed_bug = self.delayed_span_bug.borrow(); | |
440 | match *delayed_bug { | |
7453a54e SL |
441 | Some((ref span, ref errmsg)) => { |
442 | self.span_bug(span.clone(), errmsg); | |
c30ab7b3 | 443 | } |
9cc50fc6 SL |
444 | _ => {} |
445 | } | |
446 | ||
447 | return; | |
448 | } | |
449 | 1 => s = "aborting due to previous error".to_string(), | |
c30ab7b3 SL |
450 | _ => { |
451 | s = format!("aborting due to {} previous errors", self.err_count.get()); | |
9cc50fc6 SL |
452 | } |
453 | } | |
454 | ||
455 | panic!(self.fatal(&s)); | |
456 | } | |
c30ab7b3 SL |
457 | pub fn emit(&self, msp: &MultiSpan, msg: &str, lvl: Level) { |
458 | if lvl == Warning && !self.can_emit_warnings { | |
459 | return; | |
460 | } | |
5bcae85e SL |
461 | let mut db = DiagnosticBuilder::new(self, lvl, msg); |
462 | db.set_span(msp.clone()); | |
463 | db.emit(); | |
c30ab7b3 SL |
464 | if !self.continue_after_error.get() { |
465 | self.abort_if_errors(); | |
466 | } | |
467 | } | |
468 | pub fn emit_with_code(&self, msp: &MultiSpan, msg: &str, code: &str, lvl: Level) { | |
469 | if lvl == Warning && !self.can_emit_warnings { | |
470 | return; | |
471 | } | |
472 | let mut db = DiagnosticBuilder::new_with_code(self, lvl, Some(code.to_owned()), msg); | |
5bcae85e SL |
473 | db.set_span(msp.clone()); |
474 | db.emit(); | |
c30ab7b3 SL |
475 | if !self.continue_after_error.get() { |
476 | self.abort_if_errors(); | |
477 | } | |
9cc50fc6 SL |
478 | } |
479 | } | |
480 | ||
481 | ||
8bb4bdeb | 482 | #[derive(Copy, PartialEq, Clone, Debug, RustcEncodable, RustcDecodable)] |
9cc50fc6 SL |
483 | pub enum Level { |
484 | Bug, | |
485 | Fatal, | |
7453a54e SL |
486 | // An error which while not immediately fatal, should stop the compiler |
487 | // progressing beyond the current phase. | |
488 | PhaseFatal, | |
9cc50fc6 SL |
489 | Error, |
490 | Warning, | |
491 | Note, | |
492 | Help, | |
493 | Cancelled, | |
494 | } | |
495 | ||
496 | impl fmt::Display for Level { | |
497 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
9cc50fc6 SL |
498 | self.to_str().fmt(f) |
499 | } | |
500 | } | |
501 | ||
502 | impl Level { | |
3157f602 | 503 | pub fn color(self) -> term::color::Color { |
9cc50fc6 | 504 | match self { |
7453a54e | 505 | Bug | Fatal | PhaseFatal | Error => term::color::BRIGHT_RED, |
9e0c209e SL |
506 | Warning => { |
507 | if cfg!(windows) { | |
508 | term::color::BRIGHT_YELLOW | |
509 | } else { | |
510 | term::color::YELLOW | |
511 | } | |
c30ab7b3 | 512 | } |
9cc50fc6 SL |
513 | Note => term::color::BRIGHT_GREEN, |
514 | Help => term::color::BRIGHT_CYAN, | |
515 | Cancelled => unreachable!(), | |
516 | } | |
517 | } | |
518 | ||
3157f602 | 519 | pub fn to_str(self) -> &'static str { |
9cc50fc6 SL |
520 | match self { |
521 | Bug => "error: internal compiler error", | |
7453a54e | 522 | Fatal | PhaseFatal | Error => "error", |
9cc50fc6 SL |
523 | Warning => "warning", |
524 | Note => "note", | |
525 | Help => "help", | |
526 | Cancelled => panic!("Shouldn't call on cancelled error"), | |
527 | } | |
528 | } | |
529 | } | |
530 | ||
c30ab7b3 SL |
531 | pub fn expect<T, M>(diag: &Handler, opt: Option<T>, msg: M) -> T |
532 | where M: FnOnce() -> String | |
9cc50fc6 SL |
533 | { |
534 | match opt { | |
535 | Some(t) => t, | |
536 | None => diag.bug(&msg()), | |
537 | } | |
9e0c209e | 538 | } |