Skip to content

Commit 0677540

Browse files
committed
extend MultiSpan to carry labels
remove the old logic that prevents them from being overlapping
1 parent a0a5f75 commit 0677540

File tree

4 files changed

+36
-208
lines changed

4 files changed

+36
-208
lines changed

src/libsyntax/codemap.rs

Lines changed: 27 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,6 @@ use serialize::{Encodable, Decodable, Encoder, Decoder};
3232

3333
use ast::Name;
3434

35-
use errors::emitter::MAX_HIGHLIGHT_LINES;
36-
3735
// _____________________________________________________________________________
3836
// Pos, BytePos, CharPos
3937
//
@@ -132,13 +130,21 @@ pub struct Span {
132130
pub expn_id: ExpnId
133131
}
134132

135-
/// Spans are converted to MultiSpans just before error reporting, either automatically,
136-
/// generated by line grouping, or manually constructed.
137-
/// In the latter case care should be taken to ensure that spans are ordered, disjoint,
138-
/// and point into the same FileMap.
133+
/// A collection of spans. Each span can optionally have an associated
134+
/// label. The spans do not have to be disjoint or have any other
135+
/// particular relationship: in fact, they can even be from distinct
136+
/// files. When the error is reported, the text referenced by the
137+
/// spans will be printed, with highlights or labels in the
138+
/// appropriate places.
139139
#[derive(Clone)]
140140
pub struct MultiSpan {
141-
pub spans: Vec<Span>
141+
pub spans: Vec<SpanString>
142+
}
143+
144+
#[derive(Clone, Debug)]
145+
pub struct SpanString {
146+
pub span: Span,
147+
pub label: Option<String>,
142148
}
143149

144150
pub const DUMMY_SP: Span = Span { lo: BytePos(0), hi: BytePos(0), expn_id: NO_EXPANSION };
@@ -284,55 +290,28 @@ impl MultiSpan {
284290
MultiSpan { spans: Vec::new() }
285291
}
286292

293+
pub fn from_labels(vec: Vec<(Span, String)>) -> MultiSpan {
294+
MultiSpan {
295+
spans: vec.into_iter()
296+
.map(|(span, string)| SpanString {
297+
span: span,
298+
label: Some(string)
299+
})
300+
.collect()
301+
}
302+
}
303+
287304
pub fn to_span_bounds(&self) -> Span {
288305
assert!(!self.spans.is_empty());
289-
let Span { lo, expn_id, .. } = *self.spans.first().unwrap();
290-
let Span { hi, .. } = *self.spans.last().unwrap();
306+
let Span { lo, expn_id, .. } = self.spans.first().unwrap().span;
307+
let Span { hi, .. } = self.spans.last().unwrap().span;
291308
Span { lo: lo, hi: hi, expn_id: expn_id }
292309
}
293-
294-
/// Merges or inserts the given span into itself.
295-
pub fn push_merge(&mut self, mut sp: Span) {
296-
let mut idx_merged = None;
297-
298-
for idx in 0.. {
299-
let cur = match self.spans.get(idx) {
300-
Some(s) => *s,
301-
None => break,
302-
};
303-
// Try to merge with a contained Span
304-
if let Some(union) = cur.merge(sp) {
305-
self.spans[idx] = union;
306-
sp = union;
307-
idx_merged = Some(idx);
308-
break;
309-
}
310-
// Or insert into the first sorted position
311-
if sp.hi <= cur.lo {
312-
self.spans.insert(idx, sp);
313-
idx_merged = Some(idx);
314-
break;
315-
}
316-
}
317-
if let Some(idx) = idx_merged {
318-
// Merge with spans trailing the insertion/merging position
319-
while (idx + 1) < self.spans.len() {
320-
if let Some(union) = self.spans[idx + 1].merge(sp) {
321-
self.spans[idx] = union;
322-
self.spans.remove(idx + 1);
323-
} else {
324-
break;
325-
}
326-
}
327-
} else {
328-
self.spans.push(sp);
329-
}
330-
}
331310
}
332311

333312
impl From<Span> for MultiSpan {
334313
fn from(span: Span) -> MultiSpan {
335-
MultiSpan { spans: vec![span] }
314+
MultiSpan { spans: vec![SpanString { span: span, label: None }] }
336315
}
337316
}
338317

@@ -1156,53 +1135,6 @@ impl CodeMap {
11561135
}
11571136
}
11581137

1159-
/// Groups and sorts spans by lines into `MultiSpan`s, where `push` adds them to their group,
1160-
/// specifying the unification behaviour for overlapping spans.
1161-
/// Spans overflowing a line are put into their own one-element-group.
1162-
pub fn custom_group_spans<F>(&self, mut spans: Vec<Span>, push: F) -> Vec<MultiSpan>
1163-
where F: Fn(&mut MultiSpan, Span)
1164-
{
1165-
spans.sort_by(|a, b| a.lo.cmp(&b.lo));
1166-
let mut groups = Vec::<MultiSpan>::new();
1167-
let mut overflowing = vec![];
1168-
let mut prev_expn = ExpnId(!2u32);
1169-
let mut prev_file = !0usize;
1170-
let mut prev_line = !0usize;
1171-
let mut err_size = 0;
1172-
1173-
for sp in spans {
1174-
let line = self.lookup_char_pos(sp.lo).line;
1175-
let line_hi = self.lookup_char_pos(sp.hi).line;
1176-
if line != line_hi {
1177-
overflowing.push(sp.into());
1178-
continue
1179-
}
1180-
let file = self.lookup_filemap_idx(sp.lo);
1181-
1182-
if err_size < MAX_HIGHLIGHT_LINES && sp.expn_id == prev_expn && file == prev_file {
1183-
// `push` takes care of sorting, trimming, and merging
1184-
push(&mut groups.last_mut().unwrap(), sp);
1185-
if line != prev_line {
1186-
err_size += 1;
1187-
}
1188-
} else {
1189-
groups.push(sp.into());
1190-
err_size = 1;
1191-
}
1192-
prev_expn = sp.expn_id;
1193-
prev_file = file;
1194-
prev_line = line;
1195-
}
1196-
groups.extend(overflowing);
1197-
groups
1198-
}
1199-
1200-
/// Groups and sorts spans by lines into `MultiSpan`s, merging overlapping spans.
1201-
/// Spans overflowing a line are put into their own one-element-group.
1202-
pub fn group_spans(&self, spans: Vec<Span>) -> Vec<MultiSpan> {
1203-
self.custom_group_spans(spans, |msp, sp| msp.push_merge(sp))
1204-
}
1205-
12061138
pub fn get_filemap(&self, filename: &str) -> Rc<FileMap> {
12071139
for fm in self.files.borrow().iter() {
12081140
if filename == fm.name {
@@ -1719,62 +1651,4 @@ r"blork2.rs:2:1: 2:12
17191651
";
17201652
assert_eq!(sstr, res_str);
17211653
}
1722-
1723-
#[test]
1724-
fn t13() {
1725-
// Test that collecting multiple spans into line-groups works correctly
1726-
let cm = CodeMap::new();
1727-
let inp = "_aaaaa__bbb\nvv\nw\nx\ny\nz\ncccccc__ddddee__";
1728-
let sp1 = " ~~~~~ \n \n \n \n \n \n ";
1729-
let sp2 = " \n \n \n \n \n~\n ";
1730-
let sp3 = " ~~~\n~~\n \n \n \n \n ";
1731-
let sp4 = " \n \n \n \n \n \n~~~~~~ ";
1732-
let sp5 = " \n \n \n \n \n \n ~~~~ ";
1733-
let sp6 = " \n \n \n \n \n \n ~~~~ ";
1734-
let sp_merge = " \n \n \n \n \n \n ~~~~~~ ";
1735-
let sp7 = " \n ~\n \n \n \n \n ";
1736-
let sp8 = " \n \n~\n \n \n \n ";
1737-
let sp9 = " \n \n \n~\n \n \n ";
1738-
let sp10 = " \n \n \n \n~\n \n ";
1739-
1740-
let span = |sp, expected| {
1741-
let sp = span_from_selection(inp, sp);
1742-
assert_eq!(&cm.span_to_snippet(sp).unwrap(), expected);
1743-
sp
1744-
};
1745-
1746-
cm.new_filemap_and_lines("blork.rs", inp);
1747-
let sp1 = span(sp1, "aaaaa");
1748-
let sp2 = span(sp2, "z");
1749-
let sp3 = span(sp3, "bbb\nvv");
1750-
let sp4 = span(sp4, "cccccc");
1751-
let sp5 = span(sp5, "dddd");
1752-
let sp6 = span(sp6, "ddee");
1753-
let sp7 = span(sp7, "v");
1754-
let sp8 = span(sp8, "w");
1755-
let sp9 = span(sp9, "x");
1756-
let sp10 = span(sp10, "y");
1757-
let sp_merge = span(sp_merge, "ddddee");
1758-
1759-
let spans = vec![sp5, sp2, sp4, sp9, sp10, sp7, sp3, sp8, sp1, sp6];
1760-
1761-
macro_rules! check_next {
1762-
($groups: expr, $expected: expr) => ({
1763-
let actual = $groups.next().map(|g|&g.spans[..]);
1764-
let expected = $expected;
1765-
println!("actual:\n{:?}\n", actual);
1766-
println!("expected:\n{:?}\n", expected);
1767-
assert_eq!(actual, expected.as_ref().map(|x|&x[..]));
1768-
});
1769-
}
1770-
1771-
let _groups = cm.group_spans(spans.clone());
1772-
let it = &mut _groups.iter();
1773-
1774-
check_next!(it, Some([sp1, sp7, sp8, sp9, sp10, sp2]));
1775-
// New group because we're exceeding MAX_HIGHLIGHT_LINES
1776-
check_next!(it, Some([sp4, sp_merge]));
1777-
check_next!(it, Some([sp3]));
1778-
check_next!(it, None::<[Span; 0]>);
1779-
}
17801654
}

src/libsyntax/errors/emitter.rs

Lines changed: 3 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -243,8 +243,8 @@ impl EmitterWriter {
243243
-> io::Result<()>
244244
{
245245
let mut snippet_data = SnippetData::new(self.cm.clone());
246-
for &span in &msp.spans {
247-
snippet_data.push(span, None);
246+
for span_str in &msp.spans {
247+
snippet_data.push(span_str.span, span_str.label.clone());
248248
}
249249
let rendered_lines = snippet_data.render_lines();
250250
for rendered_line in &rendered_lines {
@@ -380,6 +380,7 @@ impl Destination {
380380
-> io::Result<()> {
381381
match style {
382382
Style::FileNameLine => {
383+
self.start_attr(term::Attr::Bold)?;
383384
self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_BLUE))?;
384385
}
385386
Style::Quotation => {
@@ -562,54 +563,6 @@ dummy.txt:12 tolv
562563
assert_eq!(suggest.splice_lines(&cm), expected);
563564
}
564565

565-
#[test]
566-
fn test_multiple_span_splice() {
567-
// Test that a `MultiSpan` containing multiple spans splices substitions on
568-
// several lines correctly
569-
let cm = CodeMap::new();
570-
let inp = "aaaaabbbbBB\nZZ\nZZ\nCCCDDDDDdddddeee";
571-
let sp1 = " ~~~~~~\n \n \n ";
572-
let sp2 = " \n \n \n~~~~~~ ";
573-
let sp3 = " \n \n \n ~~~ ";
574-
let sp4 = " \n \n \n ~~~~ ";
575-
576-
let span_eq = |sp, eq| assert_eq!(&cm.span_to_snippet(sp).unwrap(), eq);
577-
578-
cm.new_filemap_and_lines("blork.rs", inp);
579-
let sp1 = span_from_selection(inp, sp1);
580-
let sp2 = span_from_selection(inp, sp2);
581-
let sp3 = span_from_selection(inp, sp3);
582-
let sp4 = span_from_selection(inp, sp4);
583-
span_eq(sp1, "bbbbBB");
584-
span_eq(sp2, "CCCDDD");
585-
span_eq(sp3, "ddd");
586-
span_eq(sp4, "ddee");
587-
588-
let substitutes: Vec<String> = ["1", "2", "3", "4"].iter().map(|x|x.to_string()).collect();
589-
let expected = "aaaaa1\nZZ\nZZ\n2DD34e";
590-
591-
let test = |msp| {
592-
let suggest = CodeSuggestion {
593-
msp: msp,
594-
substitutes: substitutes.clone(),
595-
};
596-
let actual = suggest.splice_lines(&cm);
597-
assert_eq!(actual, expected);
598-
};
599-
test(MultiSpan { spans: vec![sp1, sp2, sp3, sp4] });
600-
601-
// Test ordering and merging by `MultiSpan::push`
602-
let mut msp = MultiSpan::new();
603-
msp.push_merge(sp2);
604-
msp.push_merge(sp1);
605-
assert_eq!(&msp.spans, &[sp1, sp2]);
606-
msp.push_merge(sp4);
607-
assert_eq!(&msp.spans, &[sp1, sp2, sp4]);
608-
msp.push_merge(sp3);
609-
assert_eq!(&msp.spans, &[sp1, sp2, sp3, sp4]);
610-
test(msp);
611-
}
612-
613566
#[test]
614567
fn test_multispan_highlight() {
615568
let data = Arc::new(Mutex::new(Vec::new()));

src/libsyntax/errors/json.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
// FIXME spec the JSON output properly.
2121

2222

23-
use codemap::{Span, MultiSpan, CodeMap};
23+
use codemap::{Span, SpanString, MultiSpan, CodeMap};
2424
use diagnostics::registry::Registry;
2525
use errors::{Level, DiagnosticBuilder, SubDiagnostic, RenderSpan, CodeSuggestion};
2626
use errors::emitter::Emitter;
@@ -179,7 +179,7 @@ impl<'a> Diagnostic<'a> {
179179

180180
impl DiagnosticSpan {
181181
fn from_multispan(msp: &MultiSpan, je: &JsonEmitter) -> Vec<DiagnosticSpan> {
182-
msp.spans.iter().map(|span| {
182+
msp.spans.iter().map(|&SpanString { span, .. }| {
183183
let start = je.cm.lookup_char_pos(span.lo);
184184
let end = je.cm.lookup_char_pos(span.hi);
185185
DiagnosticSpan {
@@ -190,7 +190,7 @@ impl DiagnosticSpan {
190190
line_end: end.line,
191191
column_start: start.col.0 + 1,
192192
column_end: end.col.0 + 1,
193-
text: DiagnosticSpanLine::from_span(span, je),
193+
text: DiagnosticSpanLine::from_span(&span, je),
194194
}
195195
}).collect()
196196
}
@@ -203,7 +203,7 @@ impl DiagnosticSpan {
203203
DiagnosticSpan::from_multispan(msp, je)
204204
}
205205
RenderSpan::FileLine(ref msp) => {
206-
msp.spans.iter().map(|span| {
206+
msp.spans.iter().map(|&SpanString { span, .. }| {
207207
let start = je.cm.lookup_char_pos(span.lo);
208208
let end = je.cm.lookup_char_pos(span.hi);
209209
DiagnosticSpan {
@@ -214,7 +214,7 @@ impl DiagnosticSpan {
214214
line_end: end.line,
215215
column_start: 0,
216216
column_end: 0,
217-
text: DiagnosticSpanLine::from_span(span, je),
217+
text: DiagnosticSpanLine::from_span(&span, je),
218218
}
219219
}).collect()
220220
}

src/libsyntax/errors/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ impl CodeSuggestion {
106106
let mut buf = String::new();
107107

108108
for (sp, substitute) in self.msp.spans.iter().zip(self.substitutes.iter()) {
109+
let sp = sp.span;
109110
let cur_lo = cm.lookup_char_pos(sp.lo);
110111
if prev_hi.line == cur_lo.line {
111112
push_trailing(&mut buf, prev_line, &prev_hi, Some(&cur_lo));

0 commit comments

Comments
 (0)