From 7a0334944b173811f4c72e29362e24252dc0ab5e Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 15 Dec 2015 14:11:27 +1300 Subject: Add the files I fogot about earlier d'oh --- src/libsyntax/errors/emitter.rs | 631 ++++++++++++++++++++++++++++++++++++++++ src/libsyntax/errors/mod.rs | 396 +++++++++++++++++++++++++ 2 files changed, 1027 insertions(+) create mode 100644 src/libsyntax/errors/emitter.rs create mode 100644 src/libsyntax/errors/mod.rs (limited to 'src/libsyntax/errors') diff --git a/src/libsyntax/errors/emitter.rs b/src/libsyntax/errors/emitter.rs new file mode 100644 index 00000000000..cbb5970bd55 --- /dev/null +++ b/src/libsyntax/errors/emitter.rs @@ -0,0 +1,631 @@ +// Copyright 2012-2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use self::Destination::*; + +use codemap::{self, COMMAND_LINE_SP, COMMAND_LINE_EXPN, Pos, Span}; +use diagnostics; + +use errors::{Level, RenderSpan}; +use errors::RenderSpan::*; +use errors::Level::*; + +use std::{cmp, fmt}; +use std::io::prelude::*; +use std::io; +use std::rc::Rc; +use term; + + +pub trait Emitter { + fn emit(&mut self, span: Option, msg: &str, code: Option<&str>, lvl: Level); + fn custom_emit(&mut self, sp: RenderSpan, msg: &str, lvl: Level); +} + +/// maximum number of lines we will print for each error; arbitrary. +const MAX_LINES: usize = 6; + +#[derive(Clone, Copy)] +pub enum ColorConfig { + Auto, + Always, + Never, +} + +// A basic emitter for when we don't have access to a codemap or registry. Used +// for reporting very early errors, etc. +pub struct BasicEmitter { + dst: Destination, +} + +impl Emitter for BasicEmitter { + fn emit(&mut self, + sp: Option, + msg: &str, + code: Option<&str>, + lvl: Level) { + assert!(sp.is_none(), "BasicEmitter can't handle spans"); + if let Err(e) = print_diagnostic(&mut self.dst, "", lvl, msg, code) { + panic!("failed to print diagnostics: {:?}", e); + } + + } + + fn custom_emit(&mut self, _: RenderSpan, _: &str, _: Level) { + panic!("BasicEmitter can't handle custom_emit"); + } +} + +impl BasicEmitter { + // TODO refactor + pub fn stderr(color_config: ColorConfig) -> BasicEmitter { + let stderr = io::stderr(); + + let use_color = match color_config { + ColorConfig::Always => true, + ColorConfig::Never => false, + ColorConfig::Auto => stderr_isatty(), + }; + + if use_color { + let dst = match term::stderr() { + Some(t) => Terminal(t), + None => Raw(Box::new(stderr)), + }; + BasicEmitter { dst: dst } + } else { + BasicEmitter { dst: Raw(Box::new(stderr)) } + } + } +} + +pub struct EmitterWriter { + dst: Destination, + registry: Option, + cm: Rc, +} + +impl Emitter for EmitterWriter { + fn emit(&mut self, + sp: Option, + msg: &str, + code: Option<&str>, + lvl: Level) { + let error = match sp { + Some(COMMAND_LINE_SP) => self.emit_(FileLine(COMMAND_LINE_SP), msg, code, lvl), + Some(sp) => self.emit_(FullSpan(sp), msg, code, lvl), + None => print_diagnostic(&mut self.dst, "", lvl, msg, code), + }; + + if let Err(e) = error { + panic!("failed to print diagnostics: {:?}", e); + } + } + + fn custom_emit(&mut self, + sp: RenderSpan, + msg: &str, + lvl: Level) { + match self.emit_(sp, msg, None, lvl) { + Ok(()) => {} + Err(e) => panic!("failed to print diagnostics: {:?}", e), + } + } +} + +/// Do not use this for messages that end in `\n` – use `println_maybe_styled` instead. See +/// `EmitterWriter::print_maybe_styled` for details. +macro_rules! print_maybe_styled { + ($dst: expr, $style: expr, $($arg: tt)*) => { + $dst.print_maybe_styled(format_args!($($arg)*), $style, false) + } +} + +macro_rules! println_maybe_styled { + ($dst: expr, $style: expr, $($arg: tt)*) => { + $dst.print_maybe_styled(format_args!($($arg)*), $style, true) + } +} + +impl EmitterWriter { + pub fn stderr(color_config: ColorConfig, + registry: Option, + code_map: Rc) + -> EmitterWriter { + let stderr = io::stderr(); + + let use_color = match color_config { + ColorConfig::Always => true, + ColorConfig::Never => false, + ColorConfig::Auto => stderr_isatty(), + }; + + if use_color { + let dst = match term::stderr() { + Some(t) => Terminal(t), + None => Raw(Box::new(stderr)), + }; + EmitterWriter { dst: dst, registry: registry, cm: code_map } + } else { + EmitterWriter { dst: Raw(Box::new(stderr)), registry: registry, cm: code_map } + } + } + + pub fn new(dst: Box, + registry: Option, + code_map: Rc) + -> EmitterWriter { + EmitterWriter { dst: Raw(dst), registry: registry, cm: code_map } + } + + fn emit_(&mut self, + rsp: RenderSpan, + msg: &str, + code: Option<&str>, + lvl: Level) + -> io::Result<()> { + let sp = rsp.span(); + + // We cannot check equality directly with COMMAND_LINE_SP + // since PartialEq is manually implemented to ignore the ExpnId + let ss = if sp.expn_id == COMMAND_LINE_EXPN { + "".to_string() + } else if let EndSpan(_) = rsp { + let span_end = Span { lo: sp.hi, hi: sp.hi, expn_id: sp.expn_id}; + self.cm.span_to_string(span_end) + } else { + self.cm.span_to_string(sp) + }; + + try!(print_diagnostic(&mut self.dst, &ss[..], lvl, msg, code)); + + match rsp { + FullSpan(_) => { + let lines = self.cm.span_to_lines(sp); + try!(self.highlight_lines(sp, lvl, lines)); + try!(self.print_macro_backtrace(sp)); + } + EndSpan(_) => { + let lines = self.cm.span_to_lines(sp); + try!(self.end_highlight_lines(sp, lvl, lines)); + try!(self.print_macro_backtrace(sp)); + } + Suggestion(_, ref suggestion) => { + try!(self.highlight_suggestion(sp, suggestion)); + try!(self.print_macro_backtrace(sp)); + } + FileLine(..) => { + // no source text in this case! + } + } + + match code { + Some(code) => + match self.registry.as_ref().and_then(|registry| registry.find_description(code)) { + Some(_) => { + try!(print_diagnostic(&mut self.dst, &ss[..], Help, + &format!("run `rustc --explain {}` to see a \ + detailed explanation", code), None)); + } + None => () + }, + None => (), + } + Ok(()) + } + + fn highlight_suggestion(&mut self, + sp: Span, + suggestion: &str) + -> io::Result<()> + { + let lines = self.cm.span_to_lines(sp).unwrap(); + assert!(!lines.lines.is_empty()); + + // To build up the result, we want to take the snippet from the first + // line that precedes the span, prepend that with the suggestion, and + // then append the snippet from the last line that trails the span. + let fm = &lines.file; + + let first_line = &lines.lines[0]; + let prefix = fm.get_line(first_line.line_index) + .map(|l| &l[..first_line.start_col.0]) + .unwrap_or(""); + + let last_line = lines.lines.last().unwrap(); + let suffix = fm.get_line(last_line.line_index) + .map(|l| &l[last_line.end_col.0..]) + .unwrap_or(""); + + let complete = format!("{}{}{}", prefix, suggestion, suffix); + + // print the suggestion without any line numbers, but leave + // space for them. This helps with lining up with previous + // snippets from the actual error being reported. + let fm = &*lines.file; + let mut lines = complete.lines(); + for (line, line_index) in lines.by_ref().take(MAX_LINES).zip(first_line.line_index..) { + let elided_line_num = format!("{}", line_index+1); + try!(write!(&mut self.dst, "{0}:{1:2$} {3}\n", + fm.name, "", elided_line_num.len(), line)); + } + + // if we elided some lines, add an ellipsis + if lines.next().is_some() { + let elided_line_num = format!("{}", first_line.line_index + MAX_LINES + 1); + try!(write!(&mut self.dst, "{0:1$} {0:2$} ...\n", + "", fm.name.len(), elided_line_num.len())); + } + + Ok(()) + } + + fn highlight_lines(&mut self, + sp: Span, + lvl: Level, + lines: codemap::FileLinesResult) + -> io::Result<()> + { + let lines = match lines { + Ok(lines) => lines, + Err(_) => { + try!(write!(&mut self.dst, "(internal compiler error: unprintable span)\n")); + return Ok(()); + } + }; + + let fm = &*lines.file; + + let line_strings: Option> = + lines.lines.iter() + .map(|info| fm.get_line(info.line_index)) + .collect(); + + let line_strings = match line_strings { + None => { return Ok(()); } + Some(line_strings) => line_strings + }; + + // Display only the first MAX_LINES lines. + let all_lines = lines.lines.len(); + let display_lines = cmp::min(all_lines, MAX_LINES); + let display_line_infos = &lines.lines[..display_lines]; + let display_line_strings = &line_strings[..display_lines]; + + // Calculate the widest number to format evenly and fix #11715 + assert!(display_line_infos.len() > 0); + let mut max_line_num = display_line_infos[display_line_infos.len() - 1].line_index + 1; + let mut digits = 0; + while max_line_num > 0 { + max_line_num /= 10; + digits += 1; + } + + // Print the offending lines + for (line_info, line) in display_line_infos.iter().zip(display_line_strings) { + try!(write!(&mut self.dst, "{}:{:>width$} {}\n", + fm.name, + line_info.line_index + 1, + line, + width=digits)); + } + + // If we elided something, put an ellipsis. + if display_lines < all_lines { + let last_line_index = display_line_infos.last().unwrap().line_index; + let s = format!("{}:{} ", fm.name, last_line_index + 1); + try!(write!(&mut self.dst, "{0:1$}...\n", "", s.len())); + } + + // FIXME (#3260) + // If there's one line at fault we can easily point to the problem + if lines.lines.len() == 1 { + let lo = self.cm.lookup_char_pos(sp.lo); + let mut digits = 0; + let mut num = (lines.lines[0].line_index + 1) / 10; + + // how many digits must be indent past? + while num > 0 { num /= 10; digits += 1; } + + let mut s = String::new(); + // Skip is the number of characters we need to skip because they are + // part of the 'filename:line ' part of the previous line. + let skip = fm.name.chars().count() + digits + 3; + for _ in 0..skip { + s.push(' '); + } + if let Some(orig) = fm.get_line(lines.lines[0].line_index) { + let mut col = skip; + let mut lastc = ' '; + let mut iter = orig.chars().enumerate(); + for (pos, ch) in iter.by_ref() { + lastc = ch; + if pos >= lo.col.to_usize() { break; } + // Whenever a tab occurs on the previous line, we insert one on + // the error-point-squiggly-line as well (instead of a space). + // That way the squiggly line will usually appear in the correct + // position. + match ch { + '\t' => { + col += 8 - col%8; + s.push('\t'); + }, + _ => { + col += 1; + s.push(' '); + }, + } + } + + try!(write!(&mut self.dst, "{}", s)); + let mut s = String::from("^"); + let count = match lastc { + // Most terminals have a tab stop every eight columns by default + '\t' => 8 - col%8, + _ => 1, + }; + col += count; + s.extend(::std::iter::repeat('~').take(count)); + + let hi = self.cm.lookup_char_pos(sp.hi); + if hi.col != lo.col { + for (pos, ch) in iter { + if pos >= hi.col.to_usize() { break; } + let count = match ch { + '\t' => 8 - col%8, + _ => 1, + }; + col += count; + s.extend(::std::iter::repeat('~').take(count)); + } + } + + if s.len() > 1 { + // One extra squiggly is replaced by a "^" + s.pop(); + } + + try!(println_maybe_styled!(&mut self.dst, term::Attr::ForegroundColor(lvl.color()), + "{}", s)); + } + } + Ok(()) + } + + /// Here are the differences between this and the normal `highlight_lines`: + /// `end_highlight_lines` will always put arrow on the last byte of the + /// span (instead of the first byte). Also, when the span is too long (more + /// than 6 lines), `end_highlight_lines` will print the first line, then + /// dot dot dot, then last line, whereas `highlight_lines` prints the first + /// six lines. + #[allow(deprecated)] + fn end_highlight_lines(&mut self, + sp: Span, + lvl: Level, + lines: codemap::FileLinesResult) + -> io::Result<()> { + let lines = match lines { + Ok(lines) => lines, + Err(_) => { + try!(write!(&mut self.dst, "(internal compiler error: unprintable span)\n")); + return Ok(()); + } + }; + + let fm = &*lines.file; + + let lines = &lines.lines[..]; + if lines.len() > MAX_LINES { + if let Some(line) = fm.get_line(lines[0].line_index) { + try!(write!(&mut self.dst, "{}:{} {}\n", fm.name, + lines[0].line_index + 1, line)); + } + try!(write!(&mut self.dst, "...\n")); + let last_line_index = lines[lines.len() - 1].line_index; + if let Some(last_line) = fm.get_line(last_line_index) { + try!(write!(&mut self.dst, "{}:{} {}\n", fm.name, + last_line_index + 1, last_line)); + } + } else { + for line_info in lines { + if let Some(line) = fm.get_line(line_info.line_index) { + try!(write!(&mut self.dst, "{}:{} {}\n", fm.name, + line_info.line_index + 1, line)); + } + } + } + let last_line_start = format!("{}:{} ", fm.name, lines[lines.len()-1].line_index + 1); + let hi = self.cm.lookup_char_pos(sp.hi); + let skip = last_line_start.chars().count(); + let mut s = String::new(); + for _ in 0..skip { + s.push(' '); + } + if let Some(orig) = fm.get_line(lines[0].line_index) { + let iter = orig.chars().enumerate(); + for (pos, ch) in iter { + // Span seems to use half-opened interval, so subtract 1 + if pos >= hi.col.to_usize() - 1 { break; } + // Whenever a tab occurs on the previous line, we insert one on + // the error-point-squiggly-line as well (instead of a space). + // That way the squiggly line will usually appear in the correct + // position. + match ch { + '\t' => s.push('\t'), + _ => s.push(' '), + } + } + } + s.push('^'); + println_maybe_styled!(&mut self.dst, term::Attr::ForegroundColor(lvl.color()), + "{}", s) + } + + fn print_macro_backtrace(&mut self, + sp: Span) + -> io::Result<()> { + let mut last_span = codemap::DUMMY_SP; + let mut span = sp; + + loop { + let span_name_span = self.cm.with_expn_info(span.expn_id, |expn_info| { + match expn_info { + Some(ei) => { + let (pre, post) = match ei.callee.format { + codemap::MacroAttribute(..) => ("#[", "]"), + codemap::MacroBang(..) => ("", "!"), + }; + let macro_decl_name = format!("in this expansion of {}{}{}", + pre, + ei.callee.name(), + post); + let def_site_span = ei.callee.span; + Some((ei.call_site, macro_decl_name, def_site_span)) + } + // TODO map + None => None, + } + }); + let (macro_decl_name, def_site_span) = match span_name_span { + None => break, + Some((sp, macro_decl_name, def_site_span)) => { + span = sp; + (macro_decl_name, def_site_span) + } + }; + + // Don't print recursive invocations + if span != last_span { + let mut diag_string = macro_decl_name; + if let Some(def_site_span) = def_site_span { + diag_string.push_str(&format!(" (defined in {})", + self.cm.span_to_filename(def_site_span))); + } + + let snippet = self.cm.span_to_string(span); + try!(print_diagnostic(&mut self.dst, &snippet, Note, &diag_string, None)); + } + last_span = span; + } + + Ok(()) + } +} + +fn print_diagnostic(dst: &mut Destination, + topic: &str, + lvl: Level, + msg: &str, + code: Option<&str>) + -> io::Result<()> { + if !topic.is_empty() { + try!(write!(dst, "{} ", topic)); + } + + try!(print_maybe_styled!(dst, term::Attr::ForegroundColor(lvl.color()), + "{}: ", lvl.to_string())); + try!(print_maybe_styled!(dst, term::Attr::Bold, "{}", msg)); + + match code { + Some(code) => { + let style = term::Attr::ForegroundColor(term::color::BRIGHT_MAGENTA); + try!(print_maybe_styled!(dst, style, " [{}]", code.clone())); + } + None => () + } + try!(write!(dst, "\n")); + Ok(()) +} + +#[cfg(unix)] +fn stderr_isatty() -> bool { + use libc; + unsafe { libc::isatty(libc::STDERR_FILENO) != 0 } +} +#[cfg(windows)] +fn stderr_isatty() -> bool { + type DWORD = u32; + type BOOL = i32; + type HANDLE = *mut u8; + const STD_ERROR_HANDLE: DWORD = -12i32 as DWORD; + extern "system" { + fn GetStdHandle(which: DWORD) -> HANDLE; + fn GetConsoleMode(hConsoleHandle: HANDLE, + lpMode: *mut DWORD) -> BOOL; + } + unsafe { + let handle = GetStdHandle(STD_ERROR_HANDLE); + let mut out = 0; + GetConsoleMode(handle, &mut out) != 0 + } +} + +enum Destination { + Terminal(Box), + Raw(Box), +} + +impl Destination { + fn print_maybe_styled(&mut self, + args: fmt::Arguments, + color: term::Attr, + print_newline_at_end: bool) + -> io::Result<()> { + match *self { + Terminal(ref mut t) => { + try!(t.attr(color)); + // If `msg` ends in a newline, we need to reset the color before + // the newline. We're making the assumption that we end up writing + // to a `LineBufferedWriter`, which means that emitting the reset + // after the newline ends up buffering the reset until we print + // another line or exit. Buffering the reset is a problem if we're + // sharing the terminal with any other programs (e.g. other rustc + // instances via `make -jN`). + // + // Note that if `msg` contains any internal newlines, this will + // result in the `LineBufferedWriter` flushing twice instead of + // once, which still leaves the opportunity for interleaved output + // to be miscolored. We assume this is rare enough that we don't + // have to worry about it. + try!(t.write_fmt(args)); + try!(t.reset()); + if print_newline_at_end { + t.write_all(b"\n") + } else { + Ok(()) + } + } + Raw(ref mut w) => { + try!(w.write_fmt(args)); + if print_newline_at_end { + w.write_all(b"\n") + } else { + Ok(()) + } + } + } + } +} + +impl Write for Destination { + fn write(&mut self, bytes: &[u8]) -> io::Result { + match *self { + Terminal(ref mut t) => t.write(bytes), + Raw(ref mut w) => w.write(bytes), + } + } + fn flush(&mut self) -> io::Result<()> { + match *self { + Terminal(ref mut t) => t.flush(), + Raw(ref mut w) => w.flush(), + } + } +} + diff --git a/src/libsyntax/errors/mod.rs b/src/libsyntax/errors/mod.rs new file mode 100644 index 00000000000..920fd2fdb00 --- /dev/null +++ b/src/libsyntax/errors/mod.rs @@ -0,0 +1,396 @@ +// Copyright 2012-2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub use errors::emitter::ColorConfig; + +use self::Level::*; +use self::RenderSpan::*; + +use codemap::{self, Span}; +use diagnostics; +use errors::emitter::{Emitter, EmitterWriter}; + +use std::cell::{RefCell, Cell}; +use std::{error, fmt}; +use std::io::prelude::*; +use std::rc::Rc; +use term; + +pub mod emitter; + +#[derive(Clone)] +pub enum RenderSpan { + /// A FullSpan renders with both with an initial line for the + /// message, prefixed by file:linenum, followed by a summary of + /// the source code covered by the span. + FullSpan(Span), + + /// Similar to a FullSpan, but the cited position is the end of + /// the span, instead of the start. Used, at least, for telling + /// compiletest/runtest to look at the last line of the span + /// (since `end_highlight_lines` displays an arrow to the end + /// of the span). + EndSpan(Span), + + /// A suggestion renders with both with an initial line for the + /// message, prefixed by file:linenum, followed by a summary + /// of hypothetical source code, where the `String` is spliced + /// into the lines in place of the code covered by the span. + Suggestion(Span, String), + + /// A FileLine renders with just a line for the message prefixed + /// by file:linenum. + FileLine(Span), +} + +impl RenderSpan { + fn span(&self) -> Span { + match *self { + FullSpan(s) | + Suggestion(s, _) | + EndSpan(s) | + FileLine(s) => + s + } + } +} + +/// Used as a return value to signify a fatal error occurred. (It is also +/// used as the argument to panic at the moment, but that will eventually +/// not be true.) +#[derive(Copy, Clone, Debug)] +#[must_use] +pub struct FatalError; + +impl fmt::Display for FatalError { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + write!(f, "parser fatal error") + } +} + +impl error::Error for FatalError { + fn description(&self) -> &str { + "The parser has encountered a fatal error" + } +} + +/// Signifies that the compiler died with an explicit call to `.bug` +/// or `.span_bug` rather than a failed assertion, etc. +#[derive(Copy, Clone, Debug)] +pub struct ExplicitBug; + +impl fmt::Display for ExplicitBug { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + write!(f, "parser internal bug") + } +} + +impl error::Error for ExplicitBug { + fn description(&self) -> &str { + "The parser has encountered an internal bug" + } +} + +/// A handler deals with errors; certain errors +/// (fatal, bug, unimpl) may cause immediate exit, +/// others log errors for later reporting. +pub struct Handler { + err_count: Cell, + emit: RefCell>, + pub can_emit_warnings: bool, + treat_err_as_bug: bool, + delayed_span_bug: RefCell>, +} + +impl Handler { + pub fn new(color_config: ColorConfig, + registry: Option, + can_emit_warnings: bool, + treat_err_as_bug: bool, + cm: Rc) + -> Handler { + let emitter = Box::new(EmitterWriter::stderr(color_config, registry, cm)); + Handler::with_emitter(can_emit_warnings, treat_err_as_bug, emitter) + } + + pub fn with_emitter(can_emit_warnings: bool, + treat_err_as_bug: bool, + e: Box) -> Handler { + Handler { + err_count: Cell::new(0), + emit: RefCell::new(e), + can_emit_warnings: can_emit_warnings, + treat_err_as_bug: treat_err_as_bug, + delayed_span_bug: RefCell::new(None), + } + } + + pub fn span_fatal(&self, sp: Span, msg: &str) -> FatalError { + if self.treat_err_as_bug { + self.span_bug(sp, msg); + } + self.emit(Some(sp), msg, Fatal); + return FatalError; + } + pub fn span_fatal_with_code(&self, sp: Span, msg: &str, code: &str) -> FatalError { + if self.treat_err_as_bug { + self.span_bug(sp, msg); + } + self.emit_with_code(Some(sp), msg, code, Fatal); + return FatalError; + } + pub fn span_err(&self, sp: Span, msg: &str) { + if self.treat_err_as_bug { + self.span_bug(sp, msg); + } + self.emit(Some(sp), msg, Error); + self.bump_err_count(); + } + pub fn span_err_with_code(&self, sp: Span, msg: &str, code: &str) { + if self.treat_err_as_bug { + self.span_bug(sp, msg); + } + self.emit_with_code(Some(sp), msg, code, Error); + self.bump_err_count(); + } + pub fn span_warn(&self, sp: Span, msg: &str) { + self.emit(Some(sp), msg, Warning); + } + pub fn span_warn_with_code(&self, sp: Span, msg: &str, code: &str) { + self.emit_with_code(Some(sp), msg, code, Warning); + } + pub fn span_note(&self, sp: Span, msg: &str) { + self.emit(Some(sp), msg, Note); + } + pub fn span_end_note(&self, sp: Span, msg: &str) { + self.custom_emit(EndSpan(sp), msg, Note); + } + pub fn span_help(&self, sp: Span, msg: &str) { + self.emit(Some(sp), msg, Help); + } + /// Prints out a message with a suggested edit of the code. + /// + /// See `diagnostic::RenderSpan::Suggestion` for more information. + pub fn span_suggestion(&self, sp: Span, msg: &str, suggestion: String) { + self.custom_emit(Suggestion(sp, suggestion), msg, Help); + } + pub fn fileline_note(&self, sp: Span, msg: &str) { + self.custom_emit(FileLine(sp), msg, Note); + } + pub fn fileline_help(&self, sp: Span, msg: &str) { + self.custom_emit(FileLine(sp), msg, Help); + } + pub fn span_bug(&self, sp: Span, msg: &str) -> ! { + self.emit(Some(sp), msg, Bug); + panic!(ExplicitBug); + } + pub fn delay_span_bug(&self, sp: Span, msg: &str) { + let mut delayed = self.delayed_span_bug.borrow_mut(); + *delayed = Some((sp, msg.to_string())); + } + pub fn span_bug_no_panic(&self, sp: Span, msg: &str) { + self.emit(Some(sp), msg, Bug); + self.bump_err_count(); + } + pub fn span_unimpl(&self, sp: Span, msg: &str) -> ! { + self.span_bug(sp, &format!("unimplemented {}", msg)); + } + pub fn fatal(&self, msg: &str) -> FatalError { + if self.treat_err_as_bug { + self.bug(msg); + } + self.emit.borrow_mut().emit(None, msg, None, Fatal); + FatalError + } + pub fn err(&self, msg: &str) { + if self.treat_err_as_bug { + self.bug(msg); + } + self.emit.borrow_mut().emit(None, msg, None, Error); + self.bump_err_count(); + } + pub fn warn(&self, msg: &str) { + self.emit.borrow_mut().emit(None, msg, None, Warning); + } + pub fn note(&self, msg: &str) { + self.emit.borrow_mut().emit(None, msg, None, Note); + } + pub fn help(&self, msg: &str) { + self.emit.borrow_mut().emit(None, msg, None, Help); + } + pub fn bug(&self, msg: &str) -> ! { + self.emit.borrow_mut().emit(None, msg, None, Bug); + panic!(ExplicitBug); + } + pub fn unimpl(&self, msg: &str) -> ! { + self.bug(&format!("unimplemented {}", msg)); + } + + pub fn bump_err_count(&self) { + self.err_count.set(self.err_count.get() + 1); + } + + pub fn err_count(&self) -> usize { + self.err_count.get() + } + + pub fn has_errors(&self) -> bool { + self.err_count.get() > 0 + } + + pub fn abort_if_errors(&self) { + let s; + match self.err_count.get() { + 0 => { + let delayed_bug = self.delayed_span_bug.borrow(); + match *delayed_bug { + Some((span, ref errmsg)) => { + self.span_bug(span, errmsg); + }, + _ => {} + } + + return; + } + 1 => s = "aborting due to previous error".to_string(), + _ => { + s = format!("aborting due to {} previous errors", + self.err_count.get()); + } + } + + panic!(self.fatal(&s[..])); + } + + pub fn emit(&self, + sp: Option, + msg: &str, + lvl: Level) { + if lvl == Warning && !self.can_emit_warnings { return } + self.emit.borrow_mut().emit(sp, msg, None, lvl); + } + + pub fn emit_with_code(&self, + sp: Option, + msg: &str, + code: &str, + lvl: Level) { + if lvl == Warning && !self.can_emit_warnings { return } + self.emit.borrow_mut().emit(sp, msg, Some(code), lvl); + } + + pub fn custom_emit(&self, sp: RenderSpan, msg: &str, lvl: Level) { + if lvl == Warning && !self.can_emit_warnings { return } + self.emit.borrow_mut().custom_emit(sp, msg, lvl); + } +} + + +#[derive(Copy, PartialEq, Clone, Debug)] +pub enum Level { + Bug, + Fatal, + Error, + Warning, + Note, + Help, +} + +impl fmt::Display for Level { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use std::fmt::Display; + + match *self { + Bug => "error: internal compiler error".fmt(f), + Fatal | Error => "error".fmt(f), + Warning => "warning".fmt(f), + Note => "note".fmt(f), + Help => "help".fmt(f), + } + } +} + +impl Level { + fn color(self) -> term::color::Color { + match self { + Bug | Fatal | Error => term::color::BRIGHT_RED, + Warning => term::color::BRIGHT_YELLOW, + Note => term::color::BRIGHT_GREEN, + Help => term::color::BRIGHT_CYAN, + } + } +} + +pub fn expect(diag: &Handler, opt: Option, msg: M) -> T where + M: FnOnce() -> String, +{ + match opt { + Some(t) => t, + None => diag.bug(&msg()), + } +} + +#[cfg(test)] +mod test { + use super::Level; + use emitter::EmitterWriter; + use codemap::{mk_sp, CodeMap}; + use std::sync::{Arc, Mutex}; + use std::io::{self, Write}; + use std::str::from_utf8; + + // Diagnostic doesn't align properly in span where line number increases by one digit + #[test] + fn test_hilight_suggestion_issue_11715() { + struct Sink(Arc>>); + impl Write for Sink { + fn write(&mut self, data: &[u8]) -> io::Result { + Write::write(&mut *self.0.lock().unwrap(), data) + } + fn flush(&mut self) -> io::Result<()> { Ok(()) } + } + let data = Arc::new(Mutex::new(Vec::new())); + let mut ew = EmitterWriter::new(Box::new(Sink(data.clone())), None); + let cm = CodeMap::new(); + let content = "abcdefg + koksi + line3 + line4 + cinq + line6 + line7 + line8 + line9 + line10 + e-lä-vän + tolv + dreizehn + "; + let file = cm.new_filemap_and_lines("dummy.txt", content); + let start = file.lines.borrow()[7]; + let end = file.lines.borrow()[11]; + let sp = mk_sp(start, end); + let lvl = Level::Error; + println!("span_to_lines"); + let lines = cm.span_to_lines(sp); + println!("highlight_lines"); + ew.highlight_lines(&cm, sp, lvl, lines).unwrap(); + println!("done"); + let vec = data.lock().unwrap().clone(); + let vec: &[u8] = &vec; + let str = from_utf8(vec).unwrap(); + println!("{}", str); + assert_eq!(str, "dummy.txt: 8 line8\n\ + dummy.txt: 9 line9\n\ + dummy.txt:10 line10\n\ + dummy.txt:11 e-lä-vän\n\ + dummy.txt:12 tolv\n"); + } +} -- cgit 1.4.1-3-g733a5 From e2371518c4b03e1770948d9d2429cfeb46e25a20 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 15 Dec 2015 16:42:05 +1300 Subject: A little more refactoring inside emitter.rs --- src/libsyntax/errors/emitter.rs | 80 ++++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 45 deletions(-) (limited to 'src/libsyntax/errors') diff --git a/src/libsyntax/errors/emitter.rs b/src/libsyntax/errors/emitter.rs index cbb5970bd55..e65eab58d9a 100644 --- a/src/libsyntax/errors/emitter.rs +++ b/src/libsyntax/errors/emitter.rs @@ -39,6 +39,16 @@ pub enum ColorConfig { Never, } +impl ColorConfig { + fn use_color(&self) -> bool { + match *self { + ColorConfig::Always => true, + ColorConfig::Never => false, + ColorConfig::Auto => stderr_isatty(), + } + } +} + // A basic emitter for when we don't have access to a codemap or registry. Used // for reporting very early errors, etc. pub struct BasicEmitter { @@ -64,24 +74,12 @@ impl Emitter for BasicEmitter { } impl BasicEmitter { - // TODO refactor pub fn stderr(color_config: ColorConfig) -> BasicEmitter { - let stderr = io::stderr(); - - let use_color = match color_config { - ColorConfig::Always => true, - ColorConfig::Never => false, - ColorConfig::Auto => stderr_isatty(), - }; - - if use_color { - let dst = match term::stderr() { - Some(t) => Terminal(t), - None => Raw(Box::new(stderr)), - }; + if color_config.use_color() { + let dst = Destination::from_stderr(); BasicEmitter { dst: dst } } else { - BasicEmitter { dst: Raw(Box::new(stderr)) } + BasicEmitter { dst: Raw(Box::new(io::stderr())) } } } } @@ -139,22 +137,11 @@ impl EmitterWriter { registry: Option, code_map: Rc) -> EmitterWriter { - let stderr = io::stderr(); - - let use_color = match color_config { - ColorConfig::Always => true, - ColorConfig::Never => false, - ColorConfig::Auto => stderr_isatty(), - }; - - if use_color { - let dst = match term::stderr() { - Some(t) => Terminal(t), - None => Raw(Box::new(stderr)), - }; + if color_config.use_color() { + let dst = Destination::from_stderr(); EmitterWriter { dst: dst, registry: registry, cm: code_map } } else { - EmitterWriter { dst: Raw(Box::new(stderr)), registry: registry, cm: code_map } + EmitterWriter { dst: Raw(Box::new(io::stderr())), registry: registry, cm: code_map } } } @@ -476,22 +463,18 @@ impl EmitterWriter { loop { let span_name_span = self.cm.with_expn_info(span.expn_id, |expn_info| { - match expn_info { - Some(ei) => { - let (pre, post) = match ei.callee.format { - codemap::MacroAttribute(..) => ("#[", "]"), - codemap::MacroBang(..) => ("", "!"), - }; - let macro_decl_name = format!("in this expansion of {}{}{}", - pre, - ei.callee.name(), - post); - let def_site_span = ei.callee.span; - Some((ei.call_site, macro_decl_name, def_site_span)) - } - // TODO map - None => None, - } + expn_info.map(|ei| { + let (pre, post) = match ei.callee.format { + codemap::MacroAttribute(..) => ("#[", "]"), + codemap::MacroBang(..) => ("", "!"), + }; + let macro_decl_name = format!("in this expansion of {}{}{}", + pre, + ei.callee.name(), + post); + let def_site_span = ei.callee.span; + (ei.call_site, macro_decl_name, def_site_span) + }) }); let (macro_decl_name, def_site_span) = match span_name_span { None => break, @@ -573,6 +556,13 @@ enum Destination { } impl Destination { + fn from_stderr() -> Destination { + match term::stderr() { + Some(t) => Terminal(t), + None => Raw(Box::new(io::stderr())), + } + } + fn print_maybe_styled(&mut self, args: fmt::Arguments, color: term::Attr, -- cgit 1.4.1-3-g733a5 From ff0c74f7d47f5261ebda7cb3b9a637e0cfc69104 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 15 Dec 2015 16:51:13 +1300 Subject: test errors --- src/librustc/session/config.rs | 6 +- src/librustc_driver/test.rs | 30 +++------ src/librustdoc/test.rs | 4 +- src/libsyntax/errors/emitter.rs | 61 +++++++++++++++++- src/libsyntax/errors/mod.rs | 58 ------------------ src/libsyntax/parse/lexer/mod.rs | 78 ++++++++++++++++-------- src/libsyntax_ext/lib.rs | 2 +- src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs | 2 +- src/test/run-pass-fulldeps/compiler-calls.rs | 4 +- 9 files changed, 131 insertions(+), 114 deletions(-) (limited to 'src/libsyntax/errors') diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 75761dbc15a..e33fe9570c0 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1224,7 +1224,7 @@ mod tests { let sessopts = build_session_options(&matches); let sess = build_session(sessopts, None, registry, Rc::new(DummyCrateStore)); - assert!(!sess.can_print_warnings); + assert!(!sess.diagnostic().can_emit_warnings); } { @@ -1236,7 +1236,7 @@ mod tests { let sessopts = build_session_options(&matches); let sess = build_session(sessopts, None, registry, Rc::new(DummyCrateStore)); - assert!(sess.can_print_warnings); + assert!(sess.diagnostic().can_emit_warnings); } { @@ -1247,7 +1247,7 @@ mod tests { let sessopts = build_session_options(&matches); let sess = build_session(sessopts, None, registry, Rc::new(DummyCrateStore)); - assert!(sess.can_print_warnings); + assert!(sess.diagnostic().can_emit_warnings); } } } diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 2fb23c943c7..df9294a9d5b 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -10,8 +10,6 @@ //! # Standalone Tests for the Inference Module -use diagnostic; -use diagnostic::Emitter; use driver; use rustc_lint; use rustc_resolve as resolve; @@ -34,9 +32,10 @@ use rustc::front::map as hir_map; use rustc::session::{self, config}; use std::rc::Rc; use syntax::{abi, ast}; -use syntax::codemap; use syntax::codemap::{Span, CodeMap, DUMMY_SP}; -use syntax::diagnostic::{Level, RenderSpan, Bug, Fatal, Error, Warning, Note, Help}; +use syntax::errors; +use syntax::errors::emitter::Emitter; +use syntax::errors::{Level, RenderSpan}; use syntax::parse::token; use syntax::feature_gate::UnstableFeatures; @@ -60,8 +59,8 @@ struct ExpectErrorEmitter { fn remove_message(e: &mut ExpectErrorEmitter, msg: &str, lvl: Level) { match lvl { - Bug | Fatal | Error => {} - Warning | Note | Help => { + Level::Bug | Level::Fatal | Level::Error => {} + Level::Warning | Level::Note | Level::Help => { return; } } @@ -79,14 +78,14 @@ fn remove_message(e: &mut ExpectErrorEmitter, msg: &str, lvl: Level) { impl Emitter for ExpectErrorEmitter { fn emit(&mut self, - _cmsp: Option<(&codemap::CodeMap, Span)>, + _sp: Option, msg: &str, _: Option<&str>, lvl: Level) { remove_message(self, msg, lvl); } - fn custom_emit(&mut self, _cm: &codemap::CodeMap, _sp: RenderSpan, msg: &str, lvl: Level) { + fn custom_emit(&mut self, _sp: RenderSpan, msg: &str, lvl: Level) { remove_message(self, msg, lvl); } } @@ -105,13 +104,11 @@ fn test_env(source_string: &str, let mut options = config::basic_options(); options.debugging_opts.verbose = true; options.unstable_features = UnstableFeatures::Allow; - let codemap = CodeMap::new(); - let diagnostic_handler = diagnostic::Handler::with_emitter(true, emitter); - let span_diagnostic_handler = diagnostic::SpanHandler::new(diagnostic_handler, codemap); + let diagnostic_handler = errors::Handler::with_emitter(true, false, emitter); let cstore = Rc::new(CStore::new(token::get_ident_interner())); - let sess = session::build_session_(options, None, span_diagnostic_handler, - cstore.clone()); + let sess = session::build_session_(options, None, diagnostic_handler, + Rc::new(CodeMap::new()), cstore.clone()); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); let krate_config = Vec::new(); let input = config::Input::Str(source_string.to_string()); @@ -366,13 +363,6 @@ impl<'a, 'tcx> Env<'a, 'tcx> { self.infcx.glb(true, trace) } - pub fn make_lub_ty(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> Ty<'tcx> { - match self.lub().relate(&t1, &t2) { - Ok(t) => t, - Err(ref e) => panic!("unexpected error computing LUB: {}", e), - } - } - /// Checks that `t1 <: t2` is true (this may register additional /// region checks). pub fn check_sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) { diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 4ac20ba001b..fde8299d2d2 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -225,7 +225,9 @@ fn runtest(test: &str, cratename: &str, cfgs: Vec, libs: SearchPaths, } let data = Arc::new(Mutex::new(Vec::new())); let codemap = Rc::new(CodeMap::new()); - let emitter = errors::emitter::EmitterWriter::new(box Sink(data.clone()), None, codemap.clone()); + let emitter = errors::emitter::EmitterWriter::new(box Sink(data.clone()), + None, + codemap.clone()); let old = io::set_panic(box Sink(data.clone())); let _bomb = Bomb(data, old.unwrap_or(box io::stdout())); diff --git a/src/libsyntax/errors/emitter.rs b/src/libsyntax/errors/emitter.rs index e65eab58d9a..7fef85a833e 100644 --- a/src/libsyntax/errors/emitter.rs +++ b/src/libsyntax/errors/emitter.rs @@ -45,7 +45,7 @@ impl ColorConfig { ColorConfig::Always => true, ColorConfig::Never => false, ColorConfig::Auto => stderr_isatty(), - } + } } } @@ -619,3 +619,62 @@ impl Write for Destination { } } + +#[cfg(test)] +mod test { + use errors::Level; + use super::EmitterWriter; + use codemap::{mk_sp, CodeMap}; + use std::sync::{Arc, Mutex}; + use std::io::{self, Write}; + use std::str::from_utf8; + use std::rc::Rc; + + // Diagnostic doesn't align properly in span where line number increases by one digit + #[test] + fn test_hilight_suggestion_issue_11715() { + struct Sink(Arc>>); + impl Write for Sink { + fn write(&mut self, data: &[u8]) -> io::Result { + Write::write(&mut *self.0.lock().unwrap(), data) + } + fn flush(&mut self) -> io::Result<()> { Ok(()) } + } + let data = Arc::new(Mutex::new(Vec::new())); + let cm = Rc::new(CodeMap::new()); + let mut ew = EmitterWriter::new(Box::new(Sink(data.clone())), None, cm.clone()); + let content = "abcdefg + koksi + line3 + line4 + cinq + line6 + line7 + line8 + line9 + line10 + e-lä-vän + tolv + dreizehn + "; + let file = cm.new_filemap_and_lines("dummy.txt", content); + let start = file.lines.borrow()[7]; + let end = file.lines.borrow()[11]; + let sp = mk_sp(start, end); + let lvl = Level::Error; + println!("span_to_lines"); + let lines = cm.span_to_lines(sp); + println!("highlight_lines"); + ew.highlight_lines(sp, lvl, lines).unwrap(); + println!("done"); + let vec = data.lock().unwrap().clone(); + let vec: &[u8] = &vec; + let str = from_utf8(vec).unwrap(); + println!("{}", str); + assert_eq!(str, "dummy.txt: 8 line8\n\ + dummy.txt: 9 line9\n\ + dummy.txt:10 line10\n\ + dummy.txt:11 e-lä-vän\n\ + dummy.txt:12 tolv\n"); + } +} diff --git a/src/libsyntax/errors/mod.rs b/src/libsyntax/errors/mod.rs index 920fd2fdb00..f2e61090ba2 100644 --- a/src/libsyntax/errors/mod.rs +++ b/src/libsyntax/errors/mod.rs @@ -336,61 +336,3 @@ pub fn expect(diag: &Handler, opt: Option, msg: M) -> T where None => diag.bug(&msg()), } } - -#[cfg(test)] -mod test { - use super::Level; - use emitter::EmitterWriter; - use codemap::{mk_sp, CodeMap}; - use std::sync::{Arc, Mutex}; - use std::io::{self, Write}; - use std::str::from_utf8; - - // Diagnostic doesn't align properly in span where line number increases by one digit - #[test] - fn test_hilight_suggestion_issue_11715() { - struct Sink(Arc>>); - impl Write for Sink { - fn write(&mut self, data: &[u8]) -> io::Result { - Write::write(&mut *self.0.lock().unwrap(), data) - } - fn flush(&mut self) -> io::Result<()> { Ok(()) } - } - let data = Arc::new(Mutex::new(Vec::new())); - let mut ew = EmitterWriter::new(Box::new(Sink(data.clone())), None); - let cm = CodeMap::new(); - let content = "abcdefg - koksi - line3 - line4 - cinq - line6 - line7 - line8 - line9 - line10 - e-lä-vän - tolv - dreizehn - "; - let file = cm.new_filemap_and_lines("dummy.txt", content); - let start = file.lines.borrow()[7]; - let end = file.lines.borrow()[11]; - let sp = mk_sp(start, end); - let lvl = Level::Error; - println!("span_to_lines"); - let lines = cm.span_to_lines(sp); - println!("highlight_lines"); - ew.highlight_lines(&cm, sp, lvl, lines).unwrap(); - println!("done"); - let vec = data.lock().unwrap().clone(); - let vec: &[u8] = &vec; - let str = from_utf8(vec).unwrap(); - println!("{}", str); - assert_eq!(str, "dummy.txt: 8 line8\n\ - dummy.txt: 9 line9\n\ - dummy.txt:10 line10\n\ - dummy.txt:11 e-lä-vän\n\ - dummy.txt:12 tolv\n"); - } -} diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 570e0882a85..4619410ada7 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -1422,28 +1422,30 @@ mod tests { use super::*; use codemap::{BytePos, CodeMap, Span, NO_EXPANSION}; - use diagnostic; + use errors; use parse::token; use parse::token::{str_to_ident}; use std::io; + use std::rc::Rc; - fn mk_sh() -> diagnostic::Handler { + fn mk_sh(cm: Rc) -> errors::Handler { // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. - let emitter = diagnostic::EmitterWriter::new(Box::new(io::sink()), None); - let handler = diagnostic::Handler::with_emitter(true, Box::new(emitter)); - diagnostic::Handler::new(handler, CodeMap::new()) + let emitter = errors::emitter::EmitterWriter::new(Box::new(io::sink()), None, cm); + errors::Handler::with_emitter(true, false, Box::new(emitter)) } // open a string reader for the given string - fn setup<'a>(span_handler: &'a diagnostic::Handler, + fn setup<'a>(cm: &CodeMap, + span_handler: &'a errors::Handler, teststr: String) -> StringReader<'a> { - let fm = span_handler.cm.new_filemap("zebra.rs".to_string(), teststr); + let fm = cm.new_filemap("zebra.rs".to_string(), teststr); StringReader::new(span_handler, fm) } #[test] fn t1 () { - let span_handler = mk_sh(); - let mut string_reader = setup(&span_handler, + let cm = Rc::new(CodeMap::new()); + let sh = mk_sh(cm.clone()); + let mut string_reader = setup(&cm, &sh, "/* my source file */ \ fn main() { println!(\"zebra\"); }\n".to_string()); let id = str_to_ident("fn"); @@ -1481,21 +1483,27 @@ mod tests { } #[test] fn doublecolonparsing () { - check_tokenization(setup(&mk_sh(), "a b".to_string()), + let cm = Rc::new(CodeMap::new()); + let sh = mk_sh(cm.clone()); + check_tokenization(setup(&cm, &sh, "a b".to_string()), vec![mk_ident("a", token::Plain), token::Whitespace, mk_ident("b", token::Plain)]); } #[test] fn dcparsing_2 () { - check_tokenization(setup(&mk_sh(), "a::b".to_string()), + let cm = Rc::new(CodeMap::new()); + let sh = mk_sh(cm.clone()); + check_tokenization(setup(&cm, &sh, "a::b".to_string()), vec![mk_ident("a",token::ModName), token::ModSep, mk_ident("b", token::Plain)]); } #[test] fn dcparsing_3 () { - check_tokenization(setup(&mk_sh(), "a ::b".to_string()), + let cm = Rc::new(CodeMap::new()); + let sh = mk_sh(cm.clone()); + check_tokenization(setup(&cm, &sh, "a ::b".to_string()), vec![mk_ident("a", token::Plain), token::Whitespace, token::ModSep, @@ -1503,7 +1511,9 @@ mod tests { } #[test] fn dcparsing_4 () { - check_tokenization(setup(&mk_sh(), "a:: b".to_string()), + let cm = Rc::new(CodeMap::new()); + let sh = mk_sh(cm.clone()); + check_tokenization(setup(&cm, &sh, "a:: b".to_string()), vec![mk_ident("a",token::ModName), token::ModSep, token::Whitespace, @@ -1511,40 +1521,52 @@ mod tests { } #[test] fn character_a() { - assert_eq!(setup(&mk_sh(), "'a'".to_string()).next_token().tok, + let cm = Rc::new(CodeMap::new()); + let sh = mk_sh(cm.clone()); + assert_eq!(setup(&cm, &sh, "'a'".to_string()).next_token().tok, token::Literal(token::Char(token::intern("a")), None)); } #[test] fn character_space() { - assert_eq!(setup(&mk_sh(), "' '".to_string()).next_token().tok, + let cm = Rc::new(CodeMap::new()); + let sh = mk_sh(cm.clone()); + assert_eq!(setup(&cm, &sh, "' '".to_string()).next_token().tok, token::Literal(token::Char(token::intern(" ")), None)); } #[test] fn character_escaped() { - assert_eq!(setup(&mk_sh(), "'\\n'".to_string()).next_token().tok, + let cm = Rc::new(CodeMap::new()); + let sh = mk_sh(cm.clone()); + assert_eq!(setup(&cm, &sh, "'\\n'".to_string()).next_token().tok, token::Literal(token::Char(token::intern("\\n")), None)); } #[test] fn lifetime_name() { - assert_eq!(setup(&mk_sh(), "'abc".to_string()).next_token().tok, + let cm = Rc::new(CodeMap::new()); + let sh = mk_sh(cm.clone()); + assert_eq!(setup(&cm, &sh, "'abc".to_string()).next_token().tok, token::Lifetime(token::str_to_ident("'abc"))); } #[test] fn raw_string() { - assert_eq!(setup(&mk_sh(), + let cm = Rc::new(CodeMap::new()); + let sh = mk_sh(cm.clone()); + assert_eq!(setup(&cm, &sh, "r###\"\"#a\\b\x00c\"\"###".to_string()).next_token() .tok, token::Literal(token::StrRaw(token::intern("\"#a\\b\x00c\""), 3), None)); } #[test] fn literal_suffixes() { + let cm = Rc::new(CodeMap::new()); + let sh = mk_sh(cm.clone()); macro_rules! test { ($input: expr, $tok_type: ident, $tok_contents: expr) => {{ - assert_eq!(setup(&mk_sh(), format!("{}suffix", $input)).next_token().tok, + assert_eq!(setup(&cm, &sh, format!("{}suffix", $input)).next_token().tok, token::Literal(token::$tok_type(token::intern($tok_contents)), Some(token::intern("suffix")))); // with a whitespace separator: - assert_eq!(setup(&mk_sh(), format!("{} suffix", $input)).next_token().tok, + assert_eq!(setup(&cm, &sh, format!("{} suffix", $input)).next_token().tok, token::Literal(token::$tok_type(token::intern($tok_contents)), None)); }} @@ -1560,13 +1582,13 @@ mod tests { test!("1.0", Float, "1.0"); test!("1.0e10", Float, "1.0e10"); - assert_eq!(setup(&mk_sh(), "2us".to_string()).next_token().tok, + assert_eq!(setup(&cm, &sh, "2us".to_string()).next_token().tok, token::Literal(token::Integer(token::intern("2")), Some(token::intern("us")))); - assert_eq!(setup(&mk_sh(), "r###\"raw\"###suffix".to_string()).next_token().tok, + assert_eq!(setup(&cm, &sh, "r###\"raw\"###suffix".to_string()).next_token().tok, token::Literal(token::StrRaw(token::intern("raw"), 3), Some(token::intern("suffix")))); - assert_eq!(setup(&mk_sh(), "br###\"raw\"###suffix".to_string()).next_token().tok, + assert_eq!(setup(&cm, &sh, "br###\"raw\"###suffix".to_string()).next_token().tok, token::Literal(token::ByteStrRaw(token::intern("raw"), 3), Some(token::intern("suffix")))); } @@ -1578,8 +1600,9 @@ mod tests { } #[test] fn nested_block_comments() { - let sh = mk_sh(); - let mut lexer = setup(&sh, "/* /* */ */'a'".to_string()); + let cm = Rc::new(CodeMap::new()); + let sh = mk_sh(cm.clone()); + let mut lexer = setup(&cm, &sh, "/* /* */ */'a'".to_string()); match lexer.next_token().tok { token::Comment => { }, _ => panic!("expected a comment!") @@ -1588,8 +1611,9 @@ mod tests { } #[test] fn crlf_comments() { - let sh = mk_sh(); - let mut lexer = setup(&sh, "// test\r\n/// test\r\n".to_string()); + let cm = Rc::new(CodeMap::new()); + let sh = mk_sh(cm.clone()); + let mut lexer = setup(&cm, &sh, "// test\r\n/// test\r\n".to_string()); let comment = lexer.next_token(); assert_eq!(comment.tok, token::Comment); assert_eq!(comment.sp, ::codemap::mk_sp(BytePos(0), BytePos(7))); diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index f4dd621c97e..01dc9662588 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -39,7 +39,7 @@ use syntax::parse::token::intern; macro_rules! panictry { ($e:expr) => ({ use std::result::Result::{Ok, Err}; - use syntax::diagnostic::FatalError; + use syntax::errors::FatalError; match $e { Ok(e) => e, Err(FatalError) => panic!(FatalError) diff --git a/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs b/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs index e40abe05023..7c1a45d020b 100644 --- a/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs +++ b/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs @@ -44,7 +44,7 @@ fn with_error_checking_parse(s: String, f: F) -> PResult where let mut p = string_to_parser(&ps, s); let x = f(&mut p); - if ps.span_diagnostic.handler().has_errors() || p.token != token::Eof { + if ps.span_diagnostic.has_errors() || p.token != token::Eof { return Err(p.fatal("parse error")); } diff --git a/src/test/run-pass-fulldeps/compiler-calls.rs b/src/test/run-pass-fulldeps/compiler-calls.rs index 8850f6e6d2a..e3eeeb86356 100644 --- a/src/test/run-pass-fulldeps/compiler-calls.rs +++ b/src/test/run-pass-fulldeps/compiler-calls.rs @@ -23,7 +23,7 @@ extern crate syntax; use rustc::session::Session; use rustc::session::config::{self, Input}; use rustc_driver::{driver, CompilerCalls, Compilation}; -use syntax::{diagnostics, diagnostic}; +use syntax::{diagnostics, errors}; use std::path::PathBuf; @@ -35,7 +35,7 @@ impl<'a> CompilerCalls<'a> for TestCalls { fn early_callback(&mut self, _: &getopts::Matches, _: &diagnostics::registry::Registry, - _: diagnostic::ColorConfig) + _: errors::emitter::ColorConfig) -> Compilation { self.count *= 2; Compilation::Continue -- cgit 1.4.1-3-g733a5