2012-12-03 18:48:01 -06:00
|
|
|
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2013-05-17 17:28:44 -05:00
|
|
|
use core::prelude::*;
|
|
|
|
|
2013-01-25 18:57:39 -06:00
|
|
|
use codemap::{Pos, span};
|
2012-12-23 16:41:37 -06:00
|
|
|
use codemap;
|
|
|
|
|
2013-05-24 21:35:29 -05:00
|
|
|
use core::io;
|
|
|
|
use core::uint;
|
|
|
|
use core::vec;
|
2013-05-18 14:39:17 -05:00
|
|
|
use extra::term;
|
2012-01-13 18:05:58 -06:00
|
|
|
|
2013-03-01 15:30:06 -06:00
|
|
|
pub type Emitter = @fn(cmsp: Option<(@codemap::CodeMap, span)>,
|
|
|
|
msg: &str,
|
|
|
|
lvl: level);
|
2012-01-13 21:00:09 -06:00
|
|
|
|
2013-02-11 15:36:24 -06:00
|
|
|
// a handler deals with errors; certain errors
|
|
|
|
// (fatal, bug, unimpl) may cause immediate exit,
|
|
|
|
// others log errors for later reporting.
|
2013-01-29 15:54:06 -06:00
|
|
|
pub trait handler {
|
2013-02-04 16:02:01 -06:00
|
|
|
fn fatal(@mut self, msg: &str) -> !;
|
|
|
|
fn err(@mut self, msg: &str);
|
|
|
|
fn bump_err_count(@mut self);
|
2013-05-06 08:00:37 -05:00
|
|
|
fn err_count(@mut self) -> uint;
|
2013-02-04 16:02:01 -06:00
|
|
|
fn has_errors(@mut self) -> bool;
|
|
|
|
fn abort_if_errors(@mut self);
|
|
|
|
fn warn(@mut self, msg: &str);
|
|
|
|
fn note(@mut self, msg: &str);
|
2013-02-11 15:36:24 -06:00
|
|
|
// used to indicate a bug in the compiler:
|
2013-02-04 16:02:01 -06:00
|
|
|
fn bug(@mut self, msg: &str) -> !;
|
|
|
|
fn unimpl(@mut self, msg: &str) -> !;
|
|
|
|
fn emit(@mut self,
|
|
|
|
cmsp: Option<(@codemap::CodeMap, span)>,
|
|
|
|
msg: &str,
|
|
|
|
lvl: level);
|
|
|
|
}
|
|
|
|
|
2013-02-11 15:36:24 -06:00
|
|
|
// a span-handler is like a handler but also
|
|
|
|
// accepts span information for source-location
|
|
|
|
// reporting.
|
|
|
|
pub trait span_handler {
|
|
|
|
fn span_fatal(@mut self, sp: span, msg: &str) -> !;
|
|
|
|
fn span_err(@mut self, sp: span, msg: &str);
|
|
|
|
fn span_warn(@mut self, sp: span, msg: &str);
|
|
|
|
fn span_note(@mut self, sp: span, msg: &str);
|
|
|
|
fn span_bug(@mut self, sp: span, msg: &str) -> !;
|
|
|
|
fn span_unimpl(@mut self, sp: span, msg: &str) -> !;
|
2013-03-12 15:00:50 -05:00
|
|
|
fn handler(@mut self) -> @handler;
|
2013-02-11 15:36:24 -06:00
|
|
|
}
|
|
|
|
|
2013-02-04 16:02:01 -06:00
|
|
|
struct HandlerT {
|
|
|
|
err_count: uint,
|
|
|
|
emit: Emitter,
|
|
|
|
}
|
|
|
|
|
|
|
|
struct CodemapT {
|
2013-03-12 15:00:50 -05:00
|
|
|
handler: @handler,
|
2013-01-17 10:55:28 -06:00
|
|
|
cm: @codemap::CodeMap,
|
|
|
|
}
|
2012-01-13 19:03:51 -06:00
|
|
|
|
2013-02-14 13:47:00 -06:00
|
|
|
impl span_handler for CodemapT {
|
2013-02-04 16:02:01 -06:00
|
|
|
fn span_fatal(@mut self, sp: span, msg: &str) -> ! {
|
2012-08-20 14:23:37 -05:00
|
|
|
self.handler.emit(Some((self.cm, sp)), msg, fatal);
|
2013-02-11 21:26:38 -06:00
|
|
|
fail!();
|
2012-01-13 19:03:51 -06:00
|
|
|
}
|
2013-02-04 16:02:01 -06:00
|
|
|
fn span_err(@mut self, sp: span, msg: &str) {
|
2012-08-20 14:23:37 -05:00
|
|
|
self.handler.emit(Some((self.cm, sp)), msg, error);
|
2012-01-24 23:42:54 -06:00
|
|
|
self.handler.bump_err_count();
|
|
|
|
}
|
2013-02-04 16:02:01 -06:00
|
|
|
fn span_warn(@mut self, sp: span, msg: &str) {
|
2013-04-22 19:47:49 -05:00
|
|
|
self.handler.emit(Some((self.cm, sp)), msg, warning);
|
2012-01-24 23:42:54 -06:00
|
|
|
}
|
2013-02-04 16:02:01 -06:00
|
|
|
fn span_note(@mut self, sp: span, msg: &str) {
|
2012-08-20 14:23:37 -05:00
|
|
|
self.handler.emit(Some((self.cm, sp)), msg, note);
|
2012-01-24 23:42:54 -06:00
|
|
|
}
|
2013-02-04 16:02:01 -06:00
|
|
|
fn span_bug(@mut self, sp: span, msg: &str) -> ! {
|
2012-01-24 23:42:54 -06:00
|
|
|
self.span_fatal(sp, ice_msg(msg));
|
|
|
|
}
|
2013-02-04 16:02:01 -06:00
|
|
|
fn span_unimpl(@mut self, sp: span, msg: &str) -> ! {
|
2012-07-14 00:57:48 -05:00
|
|
|
self.span_bug(sp, ~"unimplemented " + msg);
|
2012-01-24 23:42:54 -06:00
|
|
|
}
|
2013-03-12 15:00:50 -05:00
|
|
|
fn handler(@mut self) -> @handler {
|
2012-01-24 23:42:54 -06:00
|
|
|
self.handler
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-14 13:47:00 -06:00
|
|
|
impl handler for HandlerT {
|
2013-02-04 16:02:01 -06:00
|
|
|
fn fatal(@mut self, msg: &str) -> ! {
|
2013-04-22 19:47:49 -05:00
|
|
|
(self.emit)(None, msg, fatal);
|
2013-02-11 21:26:38 -06:00
|
|
|
fail!();
|
2012-01-13 19:03:51 -06:00
|
|
|
}
|
2013-02-04 16:02:01 -06:00
|
|
|
fn err(@mut self, msg: &str) {
|
2013-04-22 19:47:49 -05:00
|
|
|
(self.emit)(None, msg, error);
|
2012-01-25 01:07:16 -06:00
|
|
|
self.bump_err_count();
|
2012-01-24 23:42:54 -06:00
|
|
|
}
|
2013-02-04 16:02:01 -06:00
|
|
|
fn bump_err_count(@mut self) {
|
2012-01-13 19:03:51 -06:00
|
|
|
self.err_count += 1u;
|
|
|
|
}
|
2013-05-06 08:00:37 -05:00
|
|
|
fn err_count(@mut self) -> uint {
|
|
|
|
self.err_count
|
|
|
|
}
|
|
|
|
fn has_errors(@mut self) -> bool {
|
|
|
|
self.err_count > 0u
|
|
|
|
}
|
2013-02-04 16:02:01 -06:00
|
|
|
fn abort_if_errors(@mut self) {
|
2012-06-06 16:28:59 -05:00
|
|
|
let s;
|
2012-08-06 14:34:08 -05:00
|
|
|
match self.err_count {
|
2012-08-03 21:59:04 -05:00
|
|
|
0u => return,
|
|
|
|
1u => s = ~"aborting due to previous error",
|
|
|
|
_ => {
|
2012-08-22 19:24:52 -05:00
|
|
|
s = fmt!("aborting due to %u previous errors",
|
|
|
|
self.err_count);
|
2012-08-03 21:59:04 -05:00
|
|
|
}
|
2012-01-13 19:03:51 -06:00
|
|
|
}
|
2012-06-06 16:28:59 -05:00
|
|
|
self.fatal(s);
|
2012-01-13 19:03:51 -06:00
|
|
|
}
|
2013-02-04 16:02:01 -06:00
|
|
|
fn warn(@mut self, msg: &str) {
|
2013-04-22 19:47:49 -05:00
|
|
|
(self.emit)(None, msg, warning);
|
2012-01-13 19:03:51 -06:00
|
|
|
}
|
2013-02-04 16:02:01 -06:00
|
|
|
fn note(@mut self, msg: &str) {
|
2013-04-22 19:47:49 -05:00
|
|
|
(self.emit)(None, msg, note);
|
2012-01-13 19:03:51 -06:00
|
|
|
}
|
2013-02-04 16:02:01 -06:00
|
|
|
fn bug(@mut self, msg: &str) -> ! {
|
2012-01-14 02:35:16 -06:00
|
|
|
self.fatal(ice_msg(msg));
|
2012-01-13 19:03:51 -06:00
|
|
|
}
|
2013-02-04 16:02:01 -06:00
|
|
|
fn unimpl(@mut self, msg: &str) -> ! {
|
|
|
|
self.bug(~"unimplemented " + msg);
|
|
|
|
}
|
|
|
|
fn emit(@mut self,
|
|
|
|
cmsp: Option<(@codemap::CodeMap, span)>,
|
|
|
|
msg: &str,
|
|
|
|
lvl: level) {
|
2012-11-29 19:51:16 -06:00
|
|
|
(self.emit)(cmsp, msg, lvl);
|
2012-01-24 23:42:54 -06:00
|
|
|
}
|
2012-01-13 19:03:51 -06:00
|
|
|
}
|
|
|
|
|
2013-01-29 15:54:06 -06:00
|
|
|
pub fn ice_msg(msg: &str) -> ~str {
|
2012-08-22 19:24:52 -05:00
|
|
|
fmt!("internal compiler error: %s", msg)
|
2012-01-14 02:35:16 -06:00
|
|
|
}
|
|
|
|
|
2013-03-12 15:00:50 -05:00
|
|
|
pub fn mk_span_handler(handler: @handler, cm: @codemap::CodeMap)
|
|
|
|
-> @span_handler {
|
2013-02-04 16:02:01 -06:00
|
|
|
@mut CodemapT { handler: handler, cm: cm } as @span_handler
|
2012-01-24 23:42:54 -06:00
|
|
|
}
|
|
|
|
|
2013-02-04 16:02:01 -06:00
|
|
|
pub fn mk_handler(emitter: Option<Emitter>) -> @handler {
|
|
|
|
let emit: Emitter = match emitter {
|
|
|
|
Some(e) => e,
|
|
|
|
None => {
|
|
|
|
let emit: Emitter = |cmsp, msg, t| emit(cmsp, msg, t);
|
|
|
|
emit
|
|
|
|
}
|
2012-01-13 21:00:09 -06:00
|
|
|
};
|
|
|
|
|
2013-04-22 19:47:49 -05:00
|
|
|
@mut HandlerT { err_count: 0, emit: emit } as @handler
|
2012-01-13 19:03:51 -06:00
|
|
|
}
|
2012-01-13 18:05:58 -06:00
|
|
|
|
2013-03-20 10:52:45 -05:00
|
|
|
#[deriving(Eq)]
|
2013-01-29 15:54:06 -06:00
|
|
|
pub enum level {
|
2012-01-19 19:56:05 -06:00
|
|
|
fatal,
|
|
|
|
error,
|
|
|
|
warning,
|
|
|
|
note,
|
2012-01-13 18:05:58 -06:00
|
|
|
}
|
|
|
|
|
2012-07-14 00:57:48 -05:00
|
|
|
fn diagnosticstr(lvl: level) -> ~str {
|
2012-08-06 14:34:08 -05:00
|
|
|
match lvl {
|
2013-02-04 16:02:01 -06:00
|
|
|
fatal => ~"error",
|
|
|
|
error => ~"error",
|
|
|
|
warning => ~"warning",
|
|
|
|
note => ~"note"
|
2012-01-13 18:05:58 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-14 00:11:29 -06:00
|
|
|
fn diagnosticcolor(lvl: level) -> u8 {
|
2012-08-06 14:34:08 -05:00
|
|
|
match lvl {
|
2013-02-04 16:02:01 -06:00
|
|
|
fatal => term::color_bright_red,
|
|
|
|
error => term::color_bright_red,
|
|
|
|
warning => term::color_bright_yellow,
|
|
|
|
note => term::color_bright_green
|
2012-01-13 18:05:58 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-19 06:42:47 -05:00
|
|
|
fn print_maybe_colored(msg: &str, color: u8) {
|
2013-05-30 01:13:35 -05:00
|
|
|
let stderr = io::stderr();
|
|
|
|
|
2013-06-19 06:42:47 -05:00
|
|
|
let t = term::Terminal::new(stderr);
|
2013-05-30 01:13:35 -05:00
|
|
|
|
2013-05-30 18:14:40 -05:00
|
|
|
match t {
|
|
|
|
Ok(term) => {
|
2013-05-30 01:13:35 -05:00
|
|
|
if stderr.get_type() == io::Screen {
|
2013-06-19 06:42:47 -05:00
|
|
|
term.fg(color);
|
|
|
|
stderr.write_str(msg);
|
2013-05-30 18:14:40 -05:00
|
|
|
term.reset();
|
|
|
|
} else {
|
2013-06-19 06:42:47 -05:00
|
|
|
stderr.write_str(msg);
|
2013-05-30 01:13:35 -05:00
|
|
|
}
|
2013-05-30 18:14:40 -05:00
|
|
|
},
|
2013-06-19 06:42:47 -05:00
|
|
|
_ => stderr.write_str(msg)
|
2012-01-13 18:05:58 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-19 06:42:47 -05:00
|
|
|
fn print_diagnostic(topic: &str, lvl: level, msg: &str) {
|
|
|
|
let stderr = io::stderr();
|
|
|
|
|
|
|
|
if !topic.is_empty() {
|
|
|
|
stderr.write_str(fmt!("%s ", topic));
|
|
|
|
}
|
|
|
|
|
|
|
|
print_maybe_colored(fmt!("%s: ", diagnosticstr(lvl)), diagnosticcolor(lvl));
|
|
|
|
stderr.write_str(fmt!("%s\n", msg));
|
|
|
|
}
|
|
|
|
|
2013-03-07 17:37:22 -06:00
|
|
|
pub fn collect(messages: @mut ~[~str])
|
2013-03-01 15:30:06 -06:00
|
|
|
-> @fn(Option<(@codemap::CodeMap, span)>, &str, level) {
|
2013-01-15 18:33:20 -06:00
|
|
|
let f: @fn(Option<(@codemap::CodeMap, span)>, &str, level) =
|
|
|
|
|_o, msg: &str, _l| { messages.push(msg.to_str()); };
|
|
|
|
f
|
2012-12-05 17:13:24 -06:00
|
|
|
}
|
|
|
|
|
2013-04-22 19:47:49 -05:00
|
|
|
pub fn emit(cmsp: Option<(@codemap::CodeMap, span)>, msg: &str, lvl: level) {
|
2012-08-06 14:34:08 -05:00
|
|
|
match cmsp {
|
2012-08-20 14:23:37 -05:00
|
|
|
Some((cm, sp)) => {
|
2012-11-12 20:24:56 -06:00
|
|
|
let sp = cm.adjust_span(sp);
|
|
|
|
let ss = cm.span_to_str(sp);
|
2013-04-22 19:47:49 -05:00
|
|
|
let lines = cm.span_to_lines(sp);
|
2012-01-14 00:11:29 -06:00
|
|
|
print_diagnostic(ss, lvl, msg);
|
2013-04-22 19:47:49 -05:00
|
|
|
highlight_lines(cm, sp, lines);
|
|
|
|
print_macro_backtrace(cm, sp);
|
2012-01-13 18:05:58 -06:00
|
|
|
}
|
2012-08-20 14:23:37 -05:00
|
|
|
None => {
|
2013-05-19 00:07:44 -05:00
|
|
|
print_diagnostic("", lvl, msg);
|
2012-01-13 18:05:58 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-22 19:47:49 -05:00
|
|
|
fn highlight_lines(cm: @codemap::CodeMap,
|
2013-02-04 16:02:01 -06:00
|
|
|
sp: span,
|
2012-11-12 20:59:37 -06:00
|
|
|
lines: @codemap::FileLines) {
|
2012-02-01 03:18:59 -06:00
|
|
|
let fm = lines.file;
|
2012-01-13 18:05:58 -06:00
|
|
|
|
|
|
|
// arbitrarily only print up to six lines of the error
|
|
|
|
let max_lines = 6u;
|
2012-03-15 08:47:03 -05:00
|
|
|
let mut elided = false;
|
2012-06-21 18:44:10 -05:00
|
|
|
let mut display_lines = /* FIXME (#2543) */ copy lines.lines;
|
2013-05-14 04:52:12 -05:00
|
|
|
if display_lines.len() > max_lines {
|
2013-06-17 18:43:22 -05:00
|
|
|
display_lines = vec::slice(display_lines, 0u, max_lines).to_owned();
|
2012-01-13 18:05:58 -06:00
|
|
|
elided = true;
|
|
|
|
}
|
|
|
|
// Print the offending lines
|
2012-06-30 18:19:07 -05:00
|
|
|
for display_lines.each |line| {
|
2012-09-19 18:55:01 -05:00
|
|
|
io::stderr().write_str(fmt!("%s:%u ", fm.name, *line + 1u));
|
2013-05-23 11:09:11 -05:00
|
|
|
let s = fm.get_line(*line as int) + "\n";
|
2012-02-08 07:31:17 -06:00
|
|
|
io::stderr().write_str(s);
|
2012-01-13 18:05:58 -06:00
|
|
|
}
|
|
|
|
if elided {
|
2013-05-14 04:52:12 -05:00
|
|
|
let last_line = display_lines[display_lines.len() - 1u];
|
2012-08-22 19:24:52 -05:00
|
|
|
let s = fmt!("%s:%u ", fm.name, last_line + 1u);
|
2013-06-09 09:44:58 -05:00
|
|
|
let mut indent = s.len();
|
2012-07-14 00:57:48 -05:00
|
|
|
let mut out = ~"";
|
2013-05-23 11:09:11 -05:00
|
|
|
while indent > 0u { out += " "; indent -= 1u; }
|
|
|
|
out += "...\n";
|
2012-02-08 07:31:17 -06:00
|
|
|
io::stderr().write_str(out);
|
2012-01-13 18:05:58 -06:00
|
|
|
}
|
|
|
|
|
2013-02-08 18:01:39 -06:00
|
|
|
// FIXME (#3260)
|
2012-01-13 18:05:58 -06:00
|
|
|
// If there's one line at fault we can easily point to the problem
|
2013-05-14 04:52:12 -05:00
|
|
|
if lines.lines.len() == 1u {
|
2012-11-12 20:24:56 -06:00
|
|
|
let lo = cm.lookup_char_pos(sp.lo);
|
2012-03-15 08:47:03 -05:00
|
|
|
let mut digits = 0u;
|
|
|
|
let mut num = (lines.lines[0] + 1u) / 10u;
|
2012-01-13 18:05:58 -06:00
|
|
|
|
|
|
|
// how many digits must be indent past?
|
|
|
|
while num > 0u { num /= 10u; digits += 1u; }
|
|
|
|
|
|
|
|
// indent past |name:## | and the 0-offset column location
|
2013-06-09 09:44:58 -05:00
|
|
|
let left = fm.name.len() + digits + lo.col.to_uint() + 3u;
|
2012-07-14 00:57:48 -05:00
|
|
|
let mut s = ~"";
|
2013-02-08 17:45:00 -06:00
|
|
|
// Skip is the number of characters we need to skip because they are
|
|
|
|
// part of the 'filename:line ' part of the previous line.
|
2013-06-09 09:44:58 -05:00
|
|
|
let skip = fm.name.len() + digits + 3u;
|
2013-02-08 17:45:00 -06:00
|
|
|
for skip.times() {
|
2013-05-23 11:09:11 -05:00
|
|
|
s += " ";
|
2013-02-08 17:45:00 -06:00
|
|
|
}
|
|
|
|
let orig = fm.get_line(lines.lines[0] as int);
|
|
|
|
for uint::range(0u,left-skip) |pos| {
|
|
|
|
let curChar = (orig[pos] as char);
|
|
|
|
s += match curChar { // Whenever a tab occurs on the previous
|
|
|
|
'\t' => "\t", // line, we insert one on the error-point-
|
|
|
|
_ => " " // -squigly-line as well (instead of a
|
|
|
|
}; // space). This way the squigly-line will
|
|
|
|
} // usually appear in the correct position.
|
2013-06-19 06:42:47 -05:00
|
|
|
io::stderr().write_str(s);
|
|
|
|
let mut s = ~"^";
|
2012-11-12 20:24:56 -06:00
|
|
|
let hi = cm.lookup_char_pos(sp.hi);
|
2012-01-13 18:05:58 -06:00
|
|
|
if hi.col != lo.col {
|
|
|
|
// the ^ already takes up one space
|
2013-02-08 17:45:00 -06:00
|
|
|
let num_squiglies = hi.col.to_uint()-lo.col.to_uint()-1u;
|
2013-05-23 11:09:11 -05:00
|
|
|
for num_squiglies.times() { s += "~"; }
|
2012-01-13 18:05:58 -06:00
|
|
|
}
|
2013-06-19 06:42:47 -05:00
|
|
|
print_maybe_colored(s + "\n", term::color_bright_green);
|
2012-01-13 18:05:58 -06:00
|
|
|
}
|
|
|
|
}
|
2012-02-04 19:37:24 -06:00
|
|
|
|
2013-04-22 19:47:49 -05:00
|
|
|
fn print_macro_backtrace(cm: @codemap::CodeMap, sp: span) {
|
2013-06-10 16:50:12 -05:00
|
|
|
for sp.expn_info.iter().advance |ei| {
|
2013-06-12 12:02:55 -05:00
|
|
|
let ss = ei.callee.span.map_default(~"", |span| cm.span_to_str(*span));
|
|
|
|
print_diagnostic(ss, note,
|
2013-02-21 02:16:31 -06:00
|
|
|
fmt!("in expansion of %s!", ei.callee.name));
|
2012-11-12 20:24:56 -06:00
|
|
|
let ss = cm.span_to_str(ei.call_site);
|
2013-05-19 00:07:44 -05:00
|
|
|
print_diagnostic(ss, note, "expansion site");
|
2013-04-22 19:47:49 -05:00
|
|
|
print_macro_backtrace(cm, ei.call_site);
|
2012-02-04 19:37:24 -06:00
|
|
|
}
|
|
|
|
}
|
2012-05-22 16:55:39 -05:00
|
|
|
|
2013-03-12 15:00:50 -05:00
|
|
|
pub fn expect<T:Copy>(diag: @span_handler,
|
2013-01-29 15:54:06 -06:00
|
|
|
opt: Option<T>,
|
2013-03-07 16:38:38 -06:00
|
|
|
msg: &fn() -> ~str) -> T {
|
2012-08-06 14:34:08 -05:00
|
|
|
match opt {
|
2013-06-15 19:26:59 -05:00
|
|
|
Some(ref t) => copy *t,
|
2012-08-20 14:23:37 -05:00
|
|
|
None => diag.handler().bug(msg())
|
2012-05-22 16:55:39 -05:00
|
|
|
}
|
|
|
|
}
|