Skip to content

Commit e904292

Browse files
author
Jonathan Turner
authored
Rollup merge of #36585 - jonathandturner:misc_error_touchups, r=nrc
Add the ability to merge spans to codemap This PR adds the ability to merge Spans. To do so, it builds on the Codemap's ability to verify the locations of spans, namely that following can be verified: * the expn_id of both spans much match * the lhs span needs to end on the same line the rhs span begins * the lhs span must start at or before the rhs span If all of these are met, a new span is returned that is min(lo), max(hi) of the two spans. This PR also removes an older Span merge, as this new functionality subsumes it. r? @nrc
2 parents 5e7fbc4 + e4b1842 commit e904292

File tree

3 files changed

+78
-18
lines changed

3 files changed

+78
-18
lines changed

src/librustc_errors/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ pub trait CodeMapper {
8181
fn span_to_string(&self, sp: Span) -> String;
8282
fn span_to_filename(&self, sp: Span) -> FileName;
8383
fn macro_backtrace(&self, span: Span) -> Vec<MacroBacktrace>;
84+
fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option<Span>;
8485
}
8586

8687
impl CodeSuggestion {

src/libsyntax/codemap.rs

+77
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,46 @@ impl CodeMap {
364364
}
365365
}
366366

367+
/// Returns `Some(span)`, a union of the lhs and rhs span. The lhs must precede the rhs. If
368+
/// there are gaps between lhs and rhs, the resulting union will cross these gaps.
369+
/// For this to work, the spans have to be:
370+
/// * the expn_id of both spans much match
371+
/// * the lhs span needs to end on the same line the rhs span begins
372+
/// * the lhs span must start at or before the rhs span
373+
pub fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option<Span> {
374+
use std::cmp;
375+
376+
// make sure we're at the same expansion id
377+
if sp_lhs.expn_id != sp_rhs.expn_id {
378+
return None;
379+
}
380+
381+
let lhs_end = match self.lookup_line(sp_lhs.hi) {
382+
Ok(x) => x,
383+
Err(_) => return None
384+
};
385+
let rhs_begin = match self.lookup_line(sp_rhs.lo) {
386+
Ok(x) => x,
387+
Err(_) => return None
388+
};
389+
390+
// if we must cross lines to merge, don't merge
391+
if lhs_end.line != rhs_begin.line {
392+
return None;
393+
}
394+
395+
// ensure these follow the expected order and we don't overlap
396+
if (sp_lhs.lo <= sp_rhs.lo) && (sp_lhs.hi <= sp_rhs.lo) {
397+
Some(Span {
398+
lo: cmp::min(sp_lhs.lo, sp_rhs.lo),
399+
hi: cmp::max(sp_lhs.hi, sp_rhs.hi),
400+
expn_id: sp_lhs.expn_id,
401+
})
402+
} else {
403+
None
404+
}
405+
}
406+
367407
pub fn span_to_string(&self, sp: Span) -> String {
368408
if sp == COMMAND_LINE_SP {
369409
return "<command line option>".to_string();
@@ -819,6 +859,9 @@ impl CodeMapper for CodeMap {
819859
fn macro_backtrace(&self, span: Span) -> Vec<MacroBacktrace> {
820860
self.macro_backtrace(span)
821861
}
862+
fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option<Span> {
863+
self.merge_spans(sp_lhs, sp_rhs)
864+
}
822865
}
823866

824867
// _____________________________________________________________________________
@@ -1072,6 +1115,40 @@ mod tests {
10721115
blork.rs:1:1: 1:12\n `first line.`\n");
10731116
}
10741117

1118+
/// Test merging two spans on the same line
1119+
#[test]
1120+
fn span_merging() {
1121+
let cm = CodeMap::new();
1122+
let inputtext = "bbbb BB bb CCC\n";
1123+
let selection1 = " ~~ \n";
1124+
let selection2 = " ~~~\n";
1125+
cm.new_filemap_and_lines("blork.rs", None, inputtext);
1126+
let span1 = span_from_selection(inputtext, selection1);
1127+
let span2 = span_from_selection(inputtext, selection2);
1128+
1129+
if let Some(sp) = cm.merge_spans(span1, span2) {
1130+
let sstr = cm.span_to_expanded_string(sp);
1131+
assert_eq!(sstr, "blork.rs:1:6: 1:15\n`BB bb CCC`\n");
1132+
}
1133+
else {
1134+
assert!(false);
1135+
}
1136+
}
1137+
1138+
/// Test failing to merge two spans on different lines
1139+
#[test]
1140+
fn span_merging_fail() {
1141+
let cm = CodeMap::new();
1142+
let inputtext = "bbbb BB\ncc CCC\n";
1143+
let selection1 = " ~~\n \n";
1144+
let selection2 = " \n ~~~\n";
1145+
cm.new_filemap_and_lines("blork.rs", None, inputtext);
1146+
let span1 = span_from_selection(inputtext, selection1);
1147+
let span2 = span_from_selection(inputtext, selection2);
1148+
1149+
assert!(cm.merge_spans(span1, span2).is_none());
1150+
}
1151+
10751152
/// Returns the span corresponding to the `n`th occurrence of
10761153
/// `substring` in `source_text`.
10771154
trait CodeMapExtension {

src/libsyntax_pos/lib.rs

-18
Original file line numberDiff line numberDiff line change
@@ -96,24 +96,6 @@ impl Span {
9696
self.lo == other.lo && self.hi == other.hi
9797
}
9898

99-
/// Returns `Some(span)`, a union of `self` and `other`, on overlap.
100-
pub fn merge(self, other: Span) -> Option<Span> {
101-
if self.expn_id != other.expn_id {
102-
return None;
103-
}
104-
105-
if (self.lo <= other.lo && self.hi > other.lo) ||
106-
(self.lo >= other.lo && self.lo < other.hi) {
107-
Some(Span {
108-
lo: cmp::min(self.lo, other.lo),
109-
hi: cmp::max(self.hi, other.hi),
110-
expn_id: self.expn_id,
111-
})
112-
} else {
113-
None
114-
}
115-
}
116-
11799
/// Returns `Some(span)`, where the start is trimmed by the end of `other`
118100
pub fn trim_start(self, other: Span) -> Option<Span> {
119101
if self.hi > other.hi {

0 commit comments

Comments
 (0)