about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2018-05-23 18:31:54 -0700
committerEsteban Küber <esteban@kuber.com.ar>2018-05-24 04:16:54 -0700
commit50eefc0d777a70ff8d11cfd358eb0ed36f6e0651 (patch)
tree7fb047b4ce91491150638e4fc2407d7b127db80c
parent2daa013290e054151424849e51c0b1f24db7e7f9 (diff)
downloadrust-50eefc0d777a70ff8d11cfd358eb0ed36f6e0651.tar.gz
rust-50eefc0d777a70ff8d11cfd358eb0ed36f6e0651.zip
Account for negative offsets in suggestions
When suggesting code that has a shorter span than the current code,
account for this by keeping the offset as a signed value.
-rw-r--r--src/librustc_errors/emitter.rs35
-rw-r--r--src/test/ui/impl-trait/impl-generic-mismatch.stderr2
2 files changed, 21 insertions, 16 deletions
diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs
index 123b6abab50..4d1d33e1325 100644
--- a/src/librustc_errors/emitter.rs
+++ b/src/librustc_errors/emitter.rs
@@ -1242,29 +1242,32 @@ impl EmitterWriter {
                     line_pos += 1;
                     row_num += 1;
                 }
-                let mut extra = 0;
+
+                // This offset and the ones below need to be signed to account for replacement code
+                // that is shorter than the original code.
+                let mut offset: isize = 0;
                 // Only show an underline in the suggestions if the suggestion is not the
                 // entirety of the code being shown and the displayed code is not multiline.
                 if show_underline {
                     draw_col_separator(&mut buffer, row_num, max_line_num_len + 1);
                     for part in parts {
-                        let span_start_pos = cm.lookup_char_pos(part.span.lo());
-                        let span_end_pos = cm.lookup_char_pos(part.span.hi());
-                        // length of the code to be substituted
-                        let snippet_len = span_end_pos.col_display - span_start_pos.col_display;
-
-                        // Do not underline the leading or trailing spaces.
-                        let start = part.snippet.len() - part.snippet.trim_left().len();
-                        // account for substitutions containing unicode characters
+                        let span_start_pos = cm.lookup_char_pos(part.span.lo()).col_display;
+                        let span_end_pos = cm.lookup_char_pos(part.span.hi()).col_display;
+
+                        // Do not underline the leading...
+                        let start = part.snippet.len()
+                            .saturating_sub(part.snippet.trim_left().len());
+                        // ...or trailing spaces. Account for substitutions containing unicode
+                        // characters.
                         let sub_len = part.snippet.trim().chars().fold(0, |acc, ch| {
                             acc + unicode_width::UnicodeWidthChar::width(ch).unwrap_or(0)
                         });
 
-                        let underline_start = span_start_pos.col_display + start + extra;
-                        let underline_end = span_start_pos.col_display + start + sub_len + extra;
+                        let underline_start = (span_start_pos + start) as isize + offset;
+                        let underline_end = (span_start_pos + start + sub_len) as isize + offset;
                         for p in underline_start..underline_end {
                             buffer.putc(row_num,
-                                        max_line_num_len + 3 + p,
+                                        max_line_num_len + 3 + p as usize,
                                         '^',
                                         Style::UnderlinePrimary);
                         }
@@ -1272,7 +1275,7 @@ impl EmitterWriter {
                         if underline_start == underline_end {
                             for p in underline_start-1..underline_start+1 {
                                 buffer.putc(row_num,
-                                            max_line_num_len + 3 + p,
+                                            max_line_num_len + 3 + p as usize,
                                             '-',
                                             Style::UnderlineSecondary);
                             }
@@ -1280,12 +1283,14 @@ impl EmitterWriter {
 
                         // length of the code after substitution
                         let full_sub_len = part.snippet.chars().fold(0, |acc, ch| {
-                            acc + unicode_width::UnicodeWidthChar::width(ch).unwrap_or(0)
+                            acc + unicode_width::UnicodeWidthChar::width(ch).unwrap_or(0) as isize
                         });
 
+                        // length of the code to be substituted
+                        let snippet_len = (span_end_pos - span_start_pos) as isize;
                         // For multiple substitutions, use the position *after* the previous
                         // substitutions have happened.
-                        extra += full_sub_len - snippet_len;
+                        offset += full_sub_len - snippet_len;
                     }
                     row_num += 1;
                 }
diff --git a/src/test/ui/impl-trait/impl-generic-mismatch.stderr b/src/test/ui/impl-trait/impl-generic-mismatch.stderr
index e133d825ba0..d47adee424c 100644
--- a/src/test/ui/impl-trait/impl-generic-mismatch.stderr
+++ b/src/test/ui/impl-trait/impl-generic-mismatch.stderr
@@ -9,7 +9,7 @@ LL |     fn foo<U: Debug>(&self, _: &U) { }
 help: try removing the generic parameter and using `impl Trait` instead
    |
 LL |     fn foo(&self, _: &impl Debug) { }
-   |
+   |          --           ^^^^^^^^^^
 
 error[E0643]: method `bar` has incompatible signature for trait
   --> $DIR/impl-generic-mismatch.rs:27:23