PageRenderTime 63ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 1ms

/src/libsyntax/diagnostic.rs

http://github.com/eholk/rust
Rust | 675 lines | 556 code | 52 blank | 67 comment | 56 complexity | 2d0946a74ca40452cf31b56ebfd7f296 MD5 | raw file
Possible License(s): AGPL-1.0, BSD-2-Clause, 0BSD, Apache-2.0, MIT, LGPL-2.0
  1. // Copyright 2012 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. pub use self::Level::*;
  11. pub use self::RenderSpan::*;
  12. pub use self::ColorConfig::*;
  13. use self::Destination::*;
  14. use codemap::{COMMAND_LINE_SP, COMMAND_LINE_EXPN, Pos, Span};
  15. use codemap;
  16. use diagnostics;
  17. use std::cell::{RefCell, Cell};
  18. use std::fmt;
  19. use std::io::prelude::*;
  20. use std::io;
  21. use term::WriterWrapper;
  22. use term;
  23. use libc;
  24. /// maximum number of lines we will print for each error; arbitrary.
  25. const MAX_LINES: usize = 6;
  26. #[derive(Clone, Copy)]
  27. pub enum RenderSpan {
  28. /// A FullSpan renders with both with an initial line for the
  29. /// message, prefixed by file:linenum, followed by a summary of
  30. /// the source code covered by the span.
  31. FullSpan(Span),
  32. /// A FileLine renders with just a line for the message prefixed
  33. /// by file:linenum.
  34. FileLine(Span),
  35. }
  36. impl RenderSpan {
  37. fn span(self) -> Span {
  38. match self {
  39. FullSpan(s) | FileLine(s) => s
  40. }
  41. }
  42. fn is_full_span(&self) -> bool {
  43. match self {
  44. &FullSpan(..) => true,
  45. &FileLine(..) => false,
  46. }
  47. }
  48. }
  49. #[derive(Clone, Copy)]
  50. pub enum ColorConfig {
  51. Auto,
  52. Always,
  53. Never
  54. }
  55. pub trait Emitter {
  56. fn emit(&mut self, cmsp: Option<(&codemap::CodeMap, Span)>,
  57. msg: &str, code: Option<&str>, lvl: Level);
  58. fn custom_emit(&mut self, cm: &codemap::CodeMap,
  59. sp: RenderSpan, msg: &str, lvl: Level);
  60. }
  61. /// This structure is used to signify that a task has panicked with a fatal error
  62. /// from the diagnostics. You can use this with the `Any` trait to figure out
  63. /// how a rustc task died (if so desired).
  64. #[derive(Copy)]
  65. pub struct FatalError;
  66. /// Signifies that the compiler died with an explicit call to `.bug`
  67. /// or `.span_bug` rather than a failed assertion, etc.
  68. #[derive(Copy)]
  69. pub struct ExplicitBug;
  70. /// A span-handler is like a handler but also
  71. /// accepts span information for source-location
  72. /// reporting.
  73. pub struct SpanHandler {
  74. pub handler: Handler,
  75. pub cm: codemap::CodeMap,
  76. }
  77. impl SpanHandler {
  78. pub fn span_fatal(&self, sp: Span, msg: &str) -> ! {
  79. self.handler.emit(Some((&self.cm, sp)), msg, Fatal);
  80. panic!(FatalError);
  81. }
  82. pub fn span_fatal_with_code(&self, sp: Span, msg: &str, code: &str) -> ! {
  83. self.handler.emit_with_code(Some((&self.cm, sp)), msg, code, Fatal);
  84. panic!(FatalError);
  85. }
  86. pub fn span_err(&self, sp: Span, msg: &str) {
  87. self.handler.emit(Some((&self.cm, sp)), msg, Error);
  88. self.handler.bump_err_count();
  89. }
  90. pub fn span_err_with_code(&self, sp: Span, msg: &str, code: &str) {
  91. self.handler.emit_with_code(Some((&self.cm, sp)), msg, code, Error);
  92. self.handler.bump_err_count();
  93. }
  94. pub fn span_warn(&self, sp: Span, msg: &str) {
  95. self.handler.emit(Some((&self.cm, sp)), msg, Warning);
  96. }
  97. pub fn span_warn_with_code(&self, sp: Span, msg: &str, code: &str) {
  98. self.handler.emit_with_code(Some((&self.cm, sp)), msg, code, Warning);
  99. }
  100. pub fn span_note(&self, sp: Span, msg: &str) {
  101. self.handler.emit(Some((&self.cm, sp)), msg, Note);
  102. }
  103. pub fn span_end_note(&self, sp: Span, msg: &str) {
  104. self.handler.custom_emit(&self.cm, FullSpan(sp), msg, Note);
  105. }
  106. pub fn span_help(&self, sp: Span, msg: &str) {
  107. self.handler.emit(Some((&self.cm, sp)), msg, Help);
  108. }
  109. pub fn fileline_note(&self, sp: Span, msg: &str) {
  110. self.handler.custom_emit(&self.cm, FileLine(sp), msg, Note);
  111. }
  112. pub fn fileline_help(&self, sp: Span, msg: &str) {
  113. self.handler.custom_emit(&self.cm, FileLine(sp), msg, Help);
  114. }
  115. pub fn span_bug(&self, sp: Span, msg: &str) -> ! {
  116. self.handler.emit(Some((&self.cm, sp)), msg, Bug);
  117. panic!(ExplicitBug);
  118. }
  119. pub fn span_unimpl(&self, sp: Span, msg: &str) -> ! {
  120. self.span_bug(sp, &format!("unimplemented {}", msg));
  121. }
  122. pub fn handler<'a>(&'a self) -> &'a Handler {
  123. &self.handler
  124. }
  125. }
  126. /// A handler deals with errors; certain errors
  127. /// (fatal, bug, unimpl) may cause immediate exit,
  128. /// others log errors for later reporting.
  129. pub struct Handler {
  130. err_count: Cell<usize>,
  131. emit: RefCell<Box<Emitter + Send>>,
  132. pub can_emit_warnings: bool
  133. }
  134. impl Handler {
  135. pub fn fatal(&self, msg: &str) -> ! {
  136. self.emit.borrow_mut().emit(None, msg, None, Fatal);
  137. panic!(FatalError);
  138. }
  139. pub fn err(&self, msg: &str) {
  140. self.emit.borrow_mut().emit(None, msg, None, Error);
  141. self.bump_err_count();
  142. }
  143. pub fn bump_err_count(&self) {
  144. self.err_count.set(self.err_count.get() + 1);
  145. }
  146. pub fn err_count(&self) -> usize {
  147. self.err_count.get()
  148. }
  149. pub fn has_errors(&self) -> bool {
  150. self.err_count.get() > 0
  151. }
  152. pub fn abort_if_errors(&self) {
  153. let s;
  154. match self.err_count.get() {
  155. 0 => return,
  156. 1 => s = "aborting due to previous error".to_string(),
  157. _ => {
  158. s = format!("aborting due to {} previous errors",
  159. self.err_count.get());
  160. }
  161. }
  162. self.fatal(&s[..]);
  163. }
  164. pub fn warn(&self, msg: &str) {
  165. self.emit.borrow_mut().emit(None, msg, None, Warning);
  166. }
  167. pub fn note(&self, msg: &str) {
  168. self.emit.borrow_mut().emit(None, msg, None, Note);
  169. }
  170. pub fn help(&self, msg: &str) {
  171. self.emit.borrow_mut().emit(None, msg, None, Help);
  172. }
  173. pub fn bug(&self, msg: &str) -> ! {
  174. self.emit.borrow_mut().emit(None, msg, None, Bug);
  175. panic!(ExplicitBug);
  176. }
  177. pub fn unimpl(&self, msg: &str) -> ! {
  178. self.bug(&format!("unimplemented {}", msg));
  179. }
  180. pub fn emit(&self,
  181. cmsp: Option<(&codemap::CodeMap, Span)>,
  182. msg: &str,
  183. lvl: Level) {
  184. if lvl == Warning && !self.can_emit_warnings { return }
  185. self.emit.borrow_mut().emit(cmsp, msg, None, lvl);
  186. }
  187. pub fn emit_with_code(&self,
  188. cmsp: Option<(&codemap::CodeMap, Span)>,
  189. msg: &str,
  190. code: &str,
  191. lvl: Level) {
  192. if lvl == Warning && !self.can_emit_warnings { return }
  193. self.emit.borrow_mut().emit(cmsp, msg, Some(code), lvl);
  194. }
  195. pub fn custom_emit(&self, cm: &codemap::CodeMap,
  196. sp: RenderSpan, msg: &str, lvl: Level) {
  197. if lvl == Warning && !self.can_emit_warnings { return }
  198. self.emit.borrow_mut().custom_emit(cm, sp, msg, lvl);
  199. }
  200. }
  201. pub fn mk_span_handler(handler: Handler, cm: codemap::CodeMap) -> SpanHandler {
  202. SpanHandler {
  203. handler: handler,
  204. cm: cm,
  205. }
  206. }
  207. pub fn default_handler(color_config: ColorConfig,
  208. registry: Option<diagnostics::registry::Registry>,
  209. can_emit_warnings: bool) -> Handler {
  210. mk_handler(can_emit_warnings, Box::new(EmitterWriter::stderr(color_config, registry)))
  211. }
  212. pub fn mk_handler(can_emit_warnings: bool, e: Box<Emitter + Send>) -> Handler {
  213. Handler {
  214. err_count: Cell::new(0),
  215. emit: RefCell::new(e),
  216. can_emit_warnings: can_emit_warnings
  217. }
  218. }
  219. #[derive(Copy, PartialEq, Clone, Debug)]
  220. pub enum Level {
  221. Bug,
  222. Fatal,
  223. Error,
  224. Warning,
  225. Note,
  226. Help,
  227. }
  228. impl fmt::Display for Level {
  229. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  230. use std::fmt::Display;
  231. match *self {
  232. Bug => "error: internal compiler error".fmt(f),
  233. Fatal | Error => "error".fmt(f),
  234. Warning => "warning".fmt(f),
  235. Note => "note".fmt(f),
  236. Help => "help".fmt(f),
  237. }
  238. }
  239. }
  240. impl Level {
  241. fn color(self) -> term::color::Color {
  242. match self {
  243. Bug | Fatal | Error => term::color::BRIGHT_RED,
  244. Warning => term::color::BRIGHT_YELLOW,
  245. Note => term::color::BRIGHT_GREEN,
  246. Help => term::color::BRIGHT_CYAN,
  247. }
  248. }
  249. }
  250. fn print_maybe_styled(w: &mut EmitterWriter,
  251. msg: &str,
  252. color: term::attr::Attr) -> io::Result<()> {
  253. match w.dst {
  254. Terminal(ref mut t) => {
  255. try!(t.attr(color));
  256. // If `msg` ends in a newline, we need to reset the color before
  257. // the newline. We're making the assumption that we end up writing
  258. // to a `LineBufferedWriter`, which means that emitting the reset
  259. // after the newline ends up buffering the reset until we print
  260. // another line or exit. Buffering the reset is a problem if we're
  261. // sharing the terminal with any other programs (e.g. other rustc
  262. // instances via `make -jN`).
  263. //
  264. // Note that if `msg` contains any internal newlines, this will
  265. // result in the `LineBufferedWriter` flushing twice instead of
  266. // once, which still leaves the opportunity for interleaved output
  267. // to be miscolored. We assume this is rare enough that we don't
  268. // have to worry about it.
  269. if msg.ends_with("\n") {
  270. try!(t.write_all(msg[..msg.len()-1].as_bytes()));
  271. try!(t.reset());
  272. try!(t.write_all(b"\n"));
  273. } else {
  274. try!(t.write_all(msg.as_bytes()));
  275. try!(t.reset());
  276. }
  277. Ok(())
  278. }
  279. Raw(ref mut w) => w.write_all(msg.as_bytes()),
  280. }
  281. }
  282. fn print_diagnostic(dst: &mut EmitterWriter, topic: &str, lvl: Level,
  283. msg: &str, code: Option<&str>) -> io::Result<()> {
  284. if !topic.is_empty() {
  285. try!(write!(&mut dst.dst, "{} ", topic));
  286. }
  287. try!(print_maybe_styled(dst,
  288. &format!("{}: ", lvl.to_string()),
  289. term::attr::ForegroundColor(lvl.color())));
  290. try!(print_maybe_styled(dst,
  291. &format!("{}", msg),
  292. term::attr::Bold));
  293. match code {
  294. Some(code) => {
  295. let style = term::attr::ForegroundColor(term::color::BRIGHT_MAGENTA);
  296. try!(print_maybe_styled(dst, &format!(" [{}]", code.clone()), style));
  297. }
  298. None => ()
  299. }
  300. try!(write!(&mut dst.dst, "\n"));
  301. Ok(())
  302. }
  303. pub struct EmitterWriter {
  304. dst: Destination,
  305. registry: Option<diagnostics::registry::Registry>
  306. }
  307. enum Destination {
  308. Terminal(Box<term::Terminal<WriterWrapper> + Send>),
  309. Raw(Box<Write + Send>),
  310. }
  311. impl EmitterWriter {
  312. pub fn stderr(color_config: ColorConfig,
  313. registry: Option<diagnostics::registry::Registry>) -> EmitterWriter {
  314. let stderr = io::stderr();
  315. let use_color = match color_config {
  316. Always => true,
  317. Never => false,
  318. Auto => stderr_isatty(),
  319. };
  320. if use_color {
  321. let dst = match term::stderr() {
  322. Some(t) => Terminal(t),
  323. None => Raw(Box::new(stderr)),
  324. };
  325. EmitterWriter { dst: dst, registry: registry }
  326. } else {
  327. EmitterWriter { dst: Raw(Box::new(stderr)), registry: registry }
  328. }
  329. }
  330. pub fn new(dst: Box<Write + Send>,
  331. registry: Option<diagnostics::registry::Registry>) -> EmitterWriter {
  332. EmitterWriter { dst: Raw(dst), registry: registry }
  333. }
  334. }
  335. #[cfg(unix)]
  336. fn stderr_isatty() -> bool {
  337. unsafe { libc::isatty(libc::STDERR_FILENO) != 0 }
  338. }
  339. #[cfg(windows)]
  340. fn stderr_isatty() -> bool {
  341. const STD_ERROR_HANDLE: libc::DWORD = -12;
  342. extern "system" {
  343. fn GetStdHandle(which: libc::DWORD) -> libc::HANDLE;
  344. fn GetConsoleMode(hConsoleHandle: libc::HANDLE,
  345. lpMode: libc::LPDWORD) -> libc::BOOL;
  346. }
  347. unsafe {
  348. let handle = GetStdHandle(STD_ERROR_HANDLE);
  349. let mut out = 0;
  350. GetConsoleMode(handle, &mut out) != 0
  351. }
  352. }
  353. impl Write for Destination {
  354. fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
  355. match *self {
  356. Terminal(ref mut t) => t.write(bytes),
  357. Raw(ref mut w) => w.write(bytes),
  358. }
  359. }
  360. fn flush(&mut self) -> io::Result<()> {
  361. match *self {
  362. Terminal(ref mut t) => t.flush(),
  363. Raw(ref mut w) => w.flush(),
  364. }
  365. }
  366. }
  367. impl Emitter for EmitterWriter {
  368. fn emit(&mut self,
  369. cmsp: Option<(&codemap::CodeMap, Span)>,
  370. msg: &str, code: Option<&str>, lvl: Level) {
  371. let error = match cmsp {
  372. Some((cm, COMMAND_LINE_SP)) => emit(self, cm,
  373. FileLine(COMMAND_LINE_SP),
  374. msg, code, lvl, false),
  375. Some((cm, sp)) => emit(self, cm, FullSpan(sp), msg, code, lvl, false),
  376. None => print_diagnostic(self, "", lvl, msg, code),
  377. };
  378. match error {
  379. Ok(()) => {}
  380. Err(e) => panic!("failed to print diagnostics: {:?}", e),
  381. }
  382. }
  383. fn custom_emit(&mut self, cm: &codemap::CodeMap,
  384. sp: RenderSpan, msg: &str, lvl: Level) {
  385. match emit(self, cm, sp, msg, None, lvl, true) {
  386. Ok(()) => {}
  387. Err(e) => panic!("failed to print diagnostics: {:?}", e),
  388. }
  389. }
  390. }
  391. fn emit(dst: &mut EmitterWriter, cm: &codemap::CodeMap, rsp: RenderSpan,
  392. msg: &str, code: Option<&str>, lvl: Level, custom: bool) -> io::Result<()> {
  393. let sp = rsp.span();
  394. // We cannot check equality directly with COMMAND_LINE_SP
  395. // since PartialEq is manually implemented to ignore the ExpnId
  396. let ss = if sp.expn_id == COMMAND_LINE_EXPN {
  397. "<command line option>".to_string()
  398. } else {
  399. cm.span_to_string(sp)
  400. };
  401. if custom {
  402. // we want to tell compiletest/runtest to look at the last line of the
  403. // span (since `custom_highlight_lines` displays an arrow to the end of
  404. // the span)
  405. let span_end = Span { lo: sp.hi, hi: sp.hi, expn_id: sp.expn_id};
  406. let ses = cm.span_to_string(span_end);
  407. try!(print_diagnostic(dst, &ses[..], lvl, msg, code));
  408. if rsp.is_full_span() {
  409. try!(custom_highlight_lines(dst, cm, sp, lvl, cm.span_to_lines(sp)));
  410. }
  411. } else {
  412. try!(print_diagnostic(dst, &ss[..], lvl, msg, code));
  413. if rsp.is_full_span() {
  414. try!(highlight_lines(dst, cm, sp, lvl, cm.span_to_lines(sp)));
  415. }
  416. }
  417. if sp != COMMAND_LINE_SP {
  418. try!(print_macro_backtrace(dst, cm, sp));
  419. }
  420. match code {
  421. Some(code) =>
  422. match dst.registry.as_ref().and_then(|registry| registry.find_description(code)) {
  423. Some(_) => {
  424. try!(print_diagnostic(dst, &ss[..], Help,
  425. &format!("pass `--explain {}` to see a detailed \
  426. explanation", code), None));
  427. }
  428. None => ()
  429. },
  430. None => (),
  431. }
  432. Ok(())
  433. }
  434. fn highlight_lines(err: &mut EmitterWriter,
  435. cm: &codemap::CodeMap,
  436. sp: Span,
  437. lvl: Level,
  438. lines: codemap::FileLines) -> io::Result<()> {
  439. let fm = &*lines.file;
  440. let mut elided = false;
  441. let mut display_lines = &lines.lines[..];
  442. if display_lines.len() > MAX_LINES {
  443. display_lines = &display_lines[0..MAX_LINES];
  444. elided = true;
  445. }
  446. // Print the offending lines
  447. for &line_number in display_lines {
  448. if let Some(line) = fm.get_line(line_number) {
  449. try!(write!(&mut err.dst, "{}:{} {}\n", fm.name,
  450. line_number + 1, line));
  451. }
  452. }
  453. if elided {
  454. let last_line = display_lines[display_lines.len() - 1];
  455. let s = format!("{}:{} ", fm.name, last_line + 1);
  456. try!(write!(&mut err.dst, "{0:1$}...\n", "", s.len()));
  457. }
  458. // FIXME (#3260)
  459. // If there's one line at fault we can easily point to the problem
  460. if lines.lines.len() == 1 {
  461. let lo = cm.lookup_char_pos(sp.lo);
  462. let mut digits = 0;
  463. let mut num = (lines.lines[0] + 1) / 10;
  464. // how many digits must be indent past?
  465. while num > 0 { num /= 10; digits += 1; }
  466. let mut s = String::new();
  467. // Skip is the number of characters we need to skip because they are
  468. // part of the 'filename:line ' part of the previous line.
  469. let skip = fm.name.width(false) + digits + 3;
  470. for _ in 0..skip {
  471. s.push(' ');
  472. }
  473. if let Some(orig) = fm.get_line(lines.lines[0]) {
  474. let mut col = skip;
  475. let mut lastc = ' ';
  476. let mut iter = orig.chars().enumerate();
  477. for (pos, ch) in iter.by_ref() {
  478. lastc = ch;
  479. if pos >= lo.col.to_usize() { break; }
  480. // Whenever a tab occurs on the previous line, we insert one on
  481. // the error-point-squiggly-line as well (instead of a space).
  482. // That way the squiggly line will usually appear in the correct
  483. // position.
  484. match ch {
  485. '\t' => {
  486. col += 8 - col%8;
  487. s.push('\t');
  488. },
  489. c => for _ in 0..c.width(false).unwrap_or(0) {
  490. col += 1;
  491. s.push(' ');
  492. },
  493. }
  494. }
  495. try!(write!(&mut err.dst, "{}", s));
  496. let mut s = String::from_str("^");
  497. let count = match lastc {
  498. // Most terminals have a tab stop every eight columns by default
  499. '\t' => 8 - col%8,
  500. _ => lastc.width(false).unwrap_or(0),
  501. };
  502. col += count;
  503. s.extend(::std::iter::repeat('~').take(count));
  504. let hi = cm.lookup_char_pos(sp.hi);
  505. if hi.col != lo.col {
  506. for (pos, ch) in iter {
  507. if pos >= hi.col.to_usize() { break; }
  508. let count = match ch {
  509. '\t' => 8 - col%8,
  510. _ => ch.width(false).unwrap_or(0),
  511. };
  512. col += count;
  513. s.extend(::std::iter::repeat('~').take(count));
  514. }
  515. }
  516. if s.len() > 1 {
  517. // One extra squiggly is replaced by a "^"
  518. s.pop();
  519. }
  520. try!(print_maybe_styled(err,
  521. &format!("{}\n", s),
  522. term::attr::ForegroundColor(lvl.color())));
  523. }
  524. }
  525. Ok(())
  526. }
  527. /// Here are the differences between this and the normal `highlight_lines`:
  528. /// `custom_highlight_lines` will always put arrow on the last byte of the
  529. /// span (instead of the first byte). Also, when the span is too long (more
  530. /// than 6 lines), `custom_highlight_lines` will print the first line, then
  531. /// dot dot dot, then last line, whereas `highlight_lines` prints the first
  532. /// six lines.
  533. fn custom_highlight_lines(w: &mut EmitterWriter,
  534. cm: &codemap::CodeMap,
  535. sp: Span,
  536. lvl: Level,
  537. lines: codemap::FileLines)
  538. -> io::Result<()> {
  539. let fm = &*lines.file;
  540. let lines = &lines.lines[..];
  541. if lines.len() > MAX_LINES {
  542. if let Some(line) = fm.get_line(lines[0]) {
  543. try!(write!(&mut w.dst, "{}:{} {}\n", fm.name,
  544. lines[0] + 1, line));
  545. }
  546. try!(write!(&mut w.dst, "...\n"));
  547. let last_line_number = lines[lines.len() - 1];
  548. if let Some(last_line) = fm.get_line(last_line_number) {
  549. try!(write!(&mut w.dst, "{}:{} {}\n", fm.name,
  550. last_line_number + 1, last_line));
  551. }
  552. } else {
  553. for &line_number in lines {
  554. if let Some(line) = fm.get_line(line_number) {
  555. try!(write!(&mut w.dst, "{}:{} {}\n", fm.name,
  556. line_number + 1, line));
  557. }
  558. }
  559. }
  560. let last_line_start = format!("{}:{} ", fm.name, lines[lines.len()-1]+1);
  561. let hi = cm.lookup_char_pos(sp.hi);
  562. let skip = last_line_start.width(false);
  563. let mut s = String::new();
  564. for _ in 0..skip {
  565. s.push(' ');
  566. }
  567. if let Some(orig) = fm.get_line(lines[0]) {
  568. let iter = orig.chars().enumerate();
  569. for (pos, ch) in iter {
  570. // Span seems to use half-opened interval, so subtract 1
  571. if pos >= hi.col.to_usize() - 1 { break; }
  572. // Whenever a tab occurs on the previous line, we insert one on
  573. // the error-point-squiggly-line as well (instead of a space).
  574. // That way the squiggly line will usually appear in the correct
  575. // position.
  576. match ch {
  577. '\t' => s.push('\t'),
  578. c => for _ in 0..c.width(false).unwrap_or(0) {
  579. s.push(' ');
  580. },
  581. }
  582. }
  583. }
  584. s.push('^');
  585. s.push('\n');
  586. print_maybe_styled(w,
  587. &s[..],
  588. term::attr::ForegroundColor(lvl.color()))
  589. }
  590. fn print_macro_backtrace(w: &mut EmitterWriter,
  591. cm: &codemap::CodeMap,
  592. sp: Span)
  593. -> io::Result<()> {
  594. let cs = try!(cm.with_expn_info(sp.expn_id, |expn_info| -> io::Result<_> {
  595. match expn_info {
  596. Some(ei) => {
  597. let ss = ei.callee.span.map_or(String::new(),
  598. |span| cm.span_to_string(span));
  599. let (pre, post) = match ei.callee.format {
  600. codemap::MacroAttribute => ("#[", "]"),
  601. codemap::MacroBang => ("", "!")
  602. };
  603. try!(print_diagnostic(w, &ss, Note,
  604. &format!("in expansion of {}{}{}", pre,
  605. ei.callee.name,
  606. post), None));
  607. let ss = cm.span_to_string(ei.call_site);
  608. try!(print_diagnostic(w, &ss, Note, "expansion site", None));
  609. Ok(Some(ei.call_site))
  610. }
  611. None => Ok(None)
  612. }
  613. }));
  614. cs.map_or(Ok(()), |call_site| print_macro_backtrace(w, cm, call_site))
  615. }
  616. pub fn expect<T, M>(diag: &SpanHandler, opt: Option<T>, msg: M) -> T where
  617. M: FnOnce() -> String,
  618. {
  619. match opt {
  620. Some(t) => t,
  621. None => diag.handler().bug(&msg()),
  622. }
  623. }