Skip to content

Commit 6ad1084

Browse files
authored
Auto 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 1cf592f + e4b1842 commit 6ad1084

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
@@ -97,24 +97,6 @@ impl Span {
9797
self.lo == other.lo && self.hi == other.hi
9898
}
9999

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

0 commit comments

Comments
 (0)