about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorManish Goregaokar <manishsmail@gmail.com>2015-07-16 14:13:10 +0530
committerManish Goregaokar <manishsmail@gmail.com>2015-07-16 14:13:10 +0530
commit38e875aa806f98d634bb965fa90b66484884aa2e (patch)
tree2ccf8b336d5520e4b7ebae1b57222ace3541a72b /src/libsyntax
parent828ebb805ac9425a45468b996180c6ff88470c4e (diff)
parente08c5f751578520c013d4838f0e288af937caf0d (diff)
downloadrust-38e875aa806f98d634bb965fa90b66484884aa2e.tar.gz
rust-38e875aa806f98d634bb965fa90b66484884aa2e.zip
Rollup merge of #26838 - P1start:refactor-diagnostic, r=alexcrichton
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/diagnostic.rs788
1 files changed, 392 insertions, 396 deletions
diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs
index ec93d2c5536..fbf015169f8 100644
--- a/src/libsyntax/diagnostic.rs
+++ b/src/libsyntax/diagnostic.rs
@@ -308,63 +308,6 @@ impl Level {
     }
 }
 
-fn print_maybe_styled(w: &mut EmitterWriter,
-                      msg: &str,
-                      color: term::attr::Attr) -> io::Result<()> {
-    match w.dst {
-        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.
-            if msg.ends_with("\n") {
-                try!(t.write_all(msg[..msg.len()-1].as_bytes()));
-                try!(t.reset());
-                try!(t.write_all(b"\n"));
-            } else {
-                try!(t.write_all(msg.as_bytes()));
-                try!(t.reset());
-            }
-            Ok(())
-        }
-        Raw(ref mut w) => w.write_all(msg.as_bytes()),
-    }
-}
-
-fn print_diagnostic(dst: &mut EmitterWriter, topic: &str, lvl: Level,
-                    msg: &str, code: Option<&str>) -> io::Result<()> {
-    if !topic.is_empty() {
-        try!(write!(&mut dst.dst, "{} ", topic));
-    }
-
-    try!(print_maybe_styled(dst,
-                            &format!("{}: ", lvl.to_string()),
-                            term::attr::ForegroundColor(lvl.color())));
-    try!(print_maybe_styled(dst,
-                            &format!("{}", msg),
-                            term::attr::Bold));
-
-    match code {
-        Some(code) => {
-            let style = term::attr::ForegroundColor(term::color::BRIGHT_MAGENTA);
-            try!(print_maybe_styled(dst, &format!(" [{}]", code.clone()), style));
-        }
-        None => ()
-    }
-    try!(write!(&mut dst.dst, "\n"));
-    Ok(())
-}
-
 pub struct EmitterWriter {
     dst: Destination,
     registry: Option<diagnostics::registry::Registry>
@@ -401,6 +344,392 @@ impl EmitterWriter {
                registry: Option<diagnostics::registry::Registry>) -> EmitterWriter {
         EmitterWriter { dst: Raw(dst), registry: registry }
     }
+
+    fn print_maybe_styled(&mut self,
+                          msg: &str,
+                          color: term::attr::Attr) -> io::Result<()> {
+        match self.dst {
+            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.
+                if msg.ends_with("\n") {
+                    try!(t.write_all(msg[..msg.len()-1].as_bytes()));
+                    try!(t.reset());
+                    try!(t.write_all(b"\n"));
+                } else {
+                    try!(t.write_all(msg.as_bytes()));
+                    try!(t.reset());
+                }
+                Ok(())
+            }
+            Raw(ref mut w) => w.write_all(msg.as_bytes()),
+        }
+    }
+
+    fn print_diagnostic(&mut self, topic: &str, lvl: Level,
+                        msg: &str, code: Option<&str>) -> io::Result<()> {
+        if !topic.is_empty() {
+            try!(write!(&mut self.dst, "{} ", topic));
+        }
+
+        try!(self.print_maybe_styled(&format!("{}: ", lvl.to_string()),
+                                     term::attr::ForegroundColor(lvl.color())));
+        try!(self.print_maybe_styled(&format!("{}", msg),
+                                     term::attr::Bold));
+
+        match code {
+            Some(code) => {
+                let style = term::attr::ForegroundColor(term::color::BRIGHT_MAGENTA);
+                try!(self.print_maybe_styled(&format!(" [{}]", code.clone()), style));
+            }
+            None => ()
+        }
+        try!(write!(&mut self.dst, "\n"));
+        Ok(())
+    }
+
+    fn emit_(&mut self, cm: &codemap::CodeMap, 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 {
+            "<command line option>".to_string()
+        } else if let EndSpan(_) = rsp {
+            let span_end = Span { lo: sp.hi, hi: sp.hi, expn_id: sp.expn_id};
+            cm.span_to_string(span_end)
+        } else {
+            cm.span_to_string(sp)
+        };
+
+        try!(self.print_diagnostic(&ss[..], lvl, msg, code));
+
+        match rsp {
+            FullSpan(_) => {
+                try!(self.highlight_lines(cm, sp, lvl, cm.span_to_lines(sp)));
+                try!(self.print_macro_backtrace(cm, sp));
+            }
+            EndSpan(_) => {
+                try!(self.end_highlight_lines(cm, sp, lvl, cm.span_to_lines(sp)));
+                try!(self.print_macro_backtrace(cm, sp));
+            }
+            Suggestion(_, ref suggestion) => {
+                try!(self.highlight_suggestion(cm, sp, suggestion));
+                try!(self.print_macro_backtrace(cm, 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!(self.print_diagnostic(&ss[..], Help,
+                                                   &format!("run `rustc --explain {}` to see a \
+                                                             detailed explanation", code), None));
+                    }
+                    None => ()
+                },
+            None => (),
+        }
+        Ok(())
+    }
+
+    fn highlight_suggestion(&mut self,
+                            cm: &codemap::CodeMap,
+                            sp: Span,
+                            suggestion: &str)
+                            -> io::Result<()>
+    {
+        let lines = 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,
+                       cm: &codemap::CodeMap,
+                       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<Vec<&str>> =
+            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 = 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 = 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!(self.print_maybe_styled(&format!("{}\n", s),
+                                             term::attr::ForegroundColor(lvl.color())));
+            }
+        }
+        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,
+                           cm: &codemap::CodeMap,
+                           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 = 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('^');
+        s.push('\n');
+        self.print_maybe_styled(&s[..],
+                                term::attr::ForegroundColor(lvl.color()))
+    }
+
+    fn print_macro_backtrace(&mut self,
+                             cm: &codemap::CodeMap,
+                             sp: Span)
+                             -> io::Result<()> {
+        let cs = try!(cm.with_expn_info(sp.expn_id, |expn_info| -> io::Result<_> {
+            match expn_info {
+                Some(ei) => {
+                    let ss = ei.callee.span.map_or(String::new(),
+                                                   |span| cm.span_to_string(span));
+                    let (pre, post) = match ei.callee.format {
+                        codemap::MacroAttribute => ("#[", "]"),
+                        codemap::MacroBang => ("", "!"),
+                        codemap::CompilerExpansion => ("", ""),
+                    };
+                    try!(self.print_diagnostic(&ss, Note,
+                                               &format!("in expansion of {}{}{}",
+                                                        pre,
+                                                        ei.callee.name,
+                                                        post),
+                                               None));
+                    let ss = cm.span_to_string(ei.call_site);
+                    try!(self.print_diagnostic(&ss, Note, "expansion site", None));
+                    Ok(Some(ei.call_site))
+                }
+                None => Ok(None)
+        }
+        }));
+        cs.map_or(Ok(()), |call_site| self.print_macro_backtrace(cm, call_site))
+    }
 }
 
 #[cfg(unix)]
@@ -442,11 +771,11 @@ impl Emitter for EmitterWriter {
             cmsp: Option<(&codemap::CodeMap, Span)>,
             msg: &str, code: Option<&str>, lvl: Level) {
         let error = match cmsp {
-            Some((cm, COMMAND_LINE_SP)) => emit(self, cm,
+            Some((cm, COMMAND_LINE_SP)) => self.emit_(cm,
                                                 FileLine(COMMAND_LINE_SP),
                                                 msg, code, lvl),
-            Some((cm, sp)) => emit(self, cm, FullSpan(sp), msg, code, lvl),
-            None => print_diagnostic(self, "", lvl, msg, code),
+            Some((cm, sp)) => self.emit_(cm, FullSpan(sp), msg, code, lvl),
+            None => self.print_diagnostic("", lvl, msg, code),
         };
 
         match error {
@@ -457,346 +786,13 @@ impl Emitter for EmitterWriter {
 
     fn custom_emit(&mut self, cm: &codemap::CodeMap,
                    sp: RenderSpan, msg: &str, lvl: Level) {
-        match emit(self, cm, sp, msg, None, lvl) {
+        match self.emit_(cm, sp, msg, None, lvl) {
             Ok(()) => {}
             Err(e) => panic!("failed to print diagnostics: {:?}", e),
         }
     }
 }
 
-fn emit(dst: &mut EmitterWriter, cm: &codemap::CodeMap, 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 {
-        "<command line option>".to_string()
-    } else if let EndSpan(_) = rsp {
-        let span_end = Span { lo: sp.hi, hi: sp.hi, expn_id: sp.expn_id};
-        cm.span_to_string(span_end)
-    } else {
-        cm.span_to_string(sp)
-    };
-
-    try!(print_diagnostic(dst, &ss[..], lvl, msg, code));
-
-    match rsp {
-        FullSpan(_) => {
-            try!(highlight_lines(dst, cm, sp, lvl, cm.span_to_lines(sp)));
-            try!(print_macro_backtrace(dst, cm, sp));
-        }
-        EndSpan(_) => {
-            try!(end_highlight_lines(dst, cm, sp, lvl, cm.span_to_lines(sp)));
-            try!(print_macro_backtrace(dst, cm, sp));
-        }
-        Suggestion(_, ref suggestion) => {
-            try!(highlight_suggestion(dst, cm, sp, suggestion));
-            try!(print_macro_backtrace(dst, cm, sp));
-        }
-        FileLine(..) => {
-            // no source text in this case!
-        }
-    }
-
-    match code {
-        Some(code) =>
-            match dst.registry.as_ref().and_then(|registry| registry.find_description(code)) {
-                Some(_) => {
-                    try!(print_diagnostic(dst, &ss[..], Help,
-                                          &format!("run `rustc --explain {}` to see a detailed \
-                                                   explanation", code), None));
-                }
-                None => ()
-            },
-        None => (),
-    }
-    Ok(())
-}
-
-fn highlight_suggestion(err: &mut EmitterWriter,
-                        cm: &codemap::CodeMap,
-                        sp: Span,
-                        suggestion: &str)
-                        -> io::Result<()>
-{
-    let lines = 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 err.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 err.dst, "{0:1$} {0:2$} ...\n",
-                    "", fm.name.len(), elided_line_num.len()));
-    }
-
-    Ok(())
-}
-
-fn highlight_lines(err: &mut EmitterWriter,
-                   cm: &codemap::CodeMap,
-                   sp: Span,
-                   lvl: Level,
-                   lines: codemap::FileLinesResult)
-                   -> io::Result<()>
-{
-    let lines = match lines {
-        Ok(lines) => lines,
-        Err(_) => {
-            try!(write!(&mut err.dst, "(internal compiler error: unprintable span)\n"));
-            return Ok(());
-        }
-    };
-
-    let fm = &*lines.file;
-
-    let line_strings: Option<Vec<&str>> =
-        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 err.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 err.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 = 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 err.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 = 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!(print_maybe_styled(err,
-                                    &format!("{}\n", s),
-                                    term::attr::ForegroundColor(lvl.color())));
-        }
-    }
-    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(w: &mut EmitterWriter,
-                          cm: &codemap::CodeMap,
-                          sp: Span,
-                          lvl: Level,
-                          lines: codemap::FileLinesResult)
-                          -> io::Result<()> {
-    let lines = match lines {
-        Ok(lines) => lines,
-        Err(_) => {
-            try!(write!(&mut w.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 w.dst, "{}:{} {}\n", fm.name,
-                        lines[0].line_index + 1, line));
-        }
-        try!(write!(&mut w.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 w.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 w.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 = 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('^');
-    s.push('\n');
-    print_maybe_styled(w,
-                       &s[..],
-                       term::attr::ForegroundColor(lvl.color()))
-}
-
-fn print_macro_backtrace(w: &mut EmitterWriter,
-                         cm: &codemap::CodeMap,
-                         sp: Span)
-                         -> io::Result<()> {
-    let cs = try!(cm.with_expn_info(sp.expn_id, |expn_info| -> io::Result<_> {
-        match expn_info {
-            Some(ei) => {
-                let ss = ei.callee.span.map_or(String::new(),
-                                               |span| cm.span_to_string(span));
-                let (pre, post) = match ei.callee.format {
-                    codemap::MacroAttribute => ("#[", "]"),
-                    codemap::MacroBang => ("", "!"),
-                    codemap::CompilerExpansion => ("", ""),
-                };
-                try!(print_diagnostic(w, &ss, Note,
-                                      &format!("in expansion of {}{}{}",
-                                               pre,
-                                               ei.callee.name,
-                                               post),
-                                      None));
-                let ss = cm.span_to_string(ei.call_site);
-                try!(print_diagnostic(w, &ss, Note, "expansion site", None));
-                Ok(Some(ei.call_site))
-            }
-            None => Ok(None)
-    }
-    }));
-    cs.map_or(Ok(()), |call_site| print_macro_backtrace(w, cm, call_site))
-}
-
 pub fn expect<T, M>(diag: &SpanHandler, opt: Option<T>, msg: M) -> T where
     M: FnOnce() -> String,
 {
@@ -808,7 +804,7 @@ pub fn expect<T, M>(diag: &SpanHandler, opt: Option<T>, msg: M) -> T where
 
 #[cfg(test)]
 mod test {
-    use super::{EmitterWriter, highlight_lines, Level};
+    use super::{EmitterWriter, Level};
     use codemap::{mk_sp, CodeMap, BytePos};
     use std::sync::{Arc, Mutex};
     use std::io::{self, Write};
@@ -854,7 +850,7 @@ mod test {
         println!("span_to_lines");
         let lines = cm.span_to_lines(sp);
         println!("highlight_lines");
-        highlight_lines(&mut ew, &cm, sp, lvl, lines).unwrap();
+        ew.highlight_lines(&cm, sp, lvl, lines).unwrap();
         println!("done");
         let vec = data.lock().unwrap().clone();
         let vec: &[u8] = &vec;