@@ -32,8 +32,6 @@ use serialize::{Encodable, Decodable, Encoder, Decoder};
32
32
33
33
use ast:: Name ;
34
34
35
- use errors:: emitter:: MAX_HIGHLIGHT_LINES ;
36
-
37
35
// _____________________________________________________________________________
38
36
// Pos, BytePos, CharPos
39
37
//
@@ -51,7 +49,7 @@ pub struct BytePos(pub u32);
51
49
/// A character offset. Because of multibyte utf8 characters, a byte offset
52
50
/// is not equivalent to a character offset. The CodeMap will convert BytePos
53
51
/// values to CharPos values as necessary.
54
- #[ derive( Copy , Clone , PartialEq , Eq , Hash , PartialOrd , Debug ) ]
52
+ #[ derive( Copy , Clone , PartialEq , Eq , Hash , PartialOrd , Ord , Debug ) ]
55
53
pub struct CharPos ( pub usize ) ;
56
54
57
55
// FIXME: Lots of boilerplate in these impls, but so far my attempts to fix
@@ -132,13 +130,29 @@ pub struct Span {
132
130
pub expn_id : ExpnId
133
131
}
134
132
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. Spans have two orthogonal attributes:
134
+ ///
135
+ /// - they can be *primary spans*. In this case they are the locus of
136
+ /// the error, and would be rendered with `^^^`.
137
+ /// - they can have a *label*. In this case, the label is written next
138
+ /// to the mark in the snippet when we render.
139
139
#[ derive( Clone ) ]
140
140
pub struct MultiSpan {
141
- pub spans : Vec < Span >
141
+ primary_spans : Vec < Span > ,
142
+ span_labels : Vec < ( Span , String ) > ,
143
+ }
144
+
145
+ #[ derive( Clone , Debug ) ]
146
+ pub struct SpanLabel {
147
+ /// the span we are going to include in the final snippet
148
+ pub span : Span ,
149
+
150
+ /// is this a primary span? This is the "locus" of the message,
151
+ /// and is indicated with a `^^^^` underline, versus `----`
152
+ pub is_primary : bool ,
153
+
154
+ /// what label should we attach to this span (if any)?
155
+ pub label : Option < String > ,
142
156
}
143
157
144
158
pub const DUMMY_SP : Span = Span { lo : BytePos ( 0 ) , hi : BytePos ( 0 ) , expn_id : NO_EXPANSION } ;
@@ -276,97 +290,76 @@ pub fn original_sp(cm: &CodeMap, sp: Span, enclosing_sp: Span) -> Span {
276
290
277
291
impl MultiSpan {
278
292
pub fn new ( ) -> MultiSpan {
279
- MultiSpan { spans : Vec :: new ( ) }
293
+ MultiSpan {
294
+ primary_spans : vec ! [ ] ,
295
+ span_labels : vec ! [ ]
296
+ }
280
297
}
281
298
282
- pub fn to_span_bounds ( & self ) -> Span {
283
- assert ! ( ! self . spans . is_empty ( ) ) ;
284
- let Span { lo , expn_id , .. } = * self . spans . first ( ) . unwrap ( ) ;
285
- let Span { hi , .. } = * self . spans . last ( ) . unwrap ( ) ;
286
- Span { lo : lo , hi : hi , expn_id : expn_id }
299
+ pub fn from_span ( primary_span : Span ) -> MultiSpan {
300
+ MultiSpan {
301
+ primary_spans : vec ! [ primary_span ] ,
302
+ span_labels : vec ! [ ]
303
+ }
287
304
}
288
305
289
- /// Merges or inserts the given span into itself.
290
- pub fn push_merge ( & mut self , mut sp : Span ) {
291
- let mut idx_merged = None ;
292
-
293
- for idx in 0 .. {
294
- let cur = match self . spans . get ( idx) {
295
- Some ( s) => * s,
296
- None => break ,
297
- } ;
298
- // Try to merge with a contained Span
299
- if let Some ( union) = cur. merge ( sp) {
300
- self . spans [ idx] = union;
301
- sp = union;
302
- idx_merged = Some ( idx) ;
303
- break ;
304
- }
305
- // Or insert into the first sorted position
306
- if sp. hi <= cur. lo {
307
- self . spans . insert ( idx, sp) ;
308
- idx_merged = Some ( idx) ;
309
- break ;
310
- }
311
- }
312
- if let Some ( idx) = idx_merged {
313
- // Merge with spans trailing the insertion/merging position
314
- while ( idx + 1 ) < self . spans . len ( ) {
315
- if let Some ( union) = self . spans [ idx + 1 ] . merge ( sp) {
316
- self . spans [ idx] = union;
317
- self . spans . remove ( idx + 1 ) ;
318
- } else {
319
- break ;
320
- }
321
- }
322
- } else {
323
- self . spans . push ( sp) ;
306
+ pub fn from_spans ( vec : Vec < Span > ) -> MultiSpan {
307
+ MultiSpan {
308
+ primary_spans : vec,
309
+ span_labels : vec ! [ ]
324
310
}
325
311
}
326
312
327
- /// Inserts the given span into itself, for use with `end_highlight_lines`.
328
- pub fn push_trim ( & mut self , mut sp : Span ) {
329
- let mut prev = mk_sp ( BytePos ( 0 ) , BytePos ( 0 ) ) ;
313
+ pub fn push_primary_span ( & mut self , span : Span ) {
314
+ self . primary_spans . push ( span ) ;
315
+ }
330
316
331
- if let Some ( first) = self . spans . get_mut ( 0 ) {
332
- if first. lo > sp. lo {
333
- // Prevent us here from spanning fewer lines
334
- // because of trimming the start of the span
335
- // (this should not be visible, because this method ought
336
- // to not be used in conjunction with `highlight_lines`)
337
- first. lo = sp. lo ;
338
- }
317
+ pub fn push_span_label ( & mut self , span : Span , label : String ) {
318
+ self . span_labels . push ( ( span, label) ) ;
319
+ }
320
+
321
+ /// Selects the first primary span (if any)
322
+ pub fn primary_span ( & self ) -> Option < Span > {
323
+ self . primary_spans . first ( ) . cloned ( )
324
+ }
325
+
326
+ /// Returns all primary spans.
327
+ pub fn primary_spans ( & self ) -> & [ Span ] {
328
+ & self . primary_spans
329
+ }
330
+
331
+ /// Returns the strings to highlight. If we have an explicit set,
332
+ /// return those, otherwise just give back an (unlabeled) version
333
+ /// of the primary span.
334
+ pub fn span_labels ( & self ) -> Vec < SpanLabel > {
335
+ let is_primary = |span| self . primary_spans . contains ( & span) ;
336
+ let mut span_labels = vec ! [ ] ;
337
+
338
+ for & ( span, ref label) in & self . span_labels {
339
+ span_labels. push ( SpanLabel {
340
+ span : span,
341
+ is_primary : is_primary ( span) ,
342
+ label : Some ( label. clone ( ) )
343
+ } ) ;
339
344
}
340
345
341
- for idx in 0 .. {
342
- if let Some ( sp_trim) = sp. trim_start ( prev) {
343
- // Implies `sp.hi > prev.hi`
344
- let cur = match self . spans . get ( idx) {
345
- Some ( s) => * s,
346
- None => {
347
- sp = sp_trim;
348
- break ;
349
- }
350
- } ;
351
- // `cur` may overlap with `sp_trim`
352
- if let Some ( cur_trim) = cur. trim_start ( sp_trim) {
353
- // Implies `sp.hi < cur.hi`
354
- self . spans . insert ( idx, sp_trim) ;
355
- self . spans [ idx + 1 ] = cur_trim;
356
- return ;
357
- } else if sp. hi == cur. hi {
358
- return ;
359
- }
360
- prev = cur;
346
+ for & span in & self . primary_spans {
347
+ if !span_labels. iter ( ) . any ( |sl| sl. span == span) {
348
+ span_labels. push ( SpanLabel {
349
+ span : span,
350
+ is_primary : true ,
351
+ label : None
352
+ } ) ;
361
353
}
362
354
}
363
- self . spans . push ( sp) ;
355
+
356
+ span_labels
364
357
}
365
358
}
366
359
367
360
impl From < Span > for MultiSpan {
368
361
fn from ( span : Span ) -> MultiSpan {
369
- MultiSpan { spans : vec ! [ span] }
362
+ MultiSpan :: from_span ( span)
370
363
}
371
364
}
372
365
@@ -929,6 +922,10 @@ impl CodeMap {
929
922
}
930
923
931
924
pub fn span_to_string ( & self , sp : Span ) -> String {
925
+ if sp == COMMAND_LINE_SP {
926
+ return "<command line option>" . to_string ( ) ;
927
+ }
928
+
932
929
if self . files . borrow ( ) . is_empty ( ) && sp. source_equal ( & DUMMY_SP ) {
933
930
return "no-location" . to_string ( ) ;
934
931
}
@@ -1099,12 +1096,16 @@ impl CodeMap {
1099
1096
}
1100
1097
1101
1098
pub fn span_to_lines ( & self , sp : Span ) -> FileLinesResult {
1099
+ debug ! ( "span_to_lines(sp={:?})" , sp) ;
1100
+
1102
1101
if sp. lo > sp. hi {
1103
1102
return Err ( SpanLinesError :: IllFormedSpan ( sp) ) ;
1104
1103
}
1105
1104
1106
1105
let lo = self . lookup_char_pos ( sp. lo ) ;
1106
+ debug ! ( "span_to_lines: lo={:?}" , lo) ;
1107
1107
let hi = self . lookup_char_pos ( sp. hi ) ;
1108
+ debug ! ( "span_to_lines: hi={:?}" , hi) ;
1108
1109
1109
1110
if lo. file . start_pos != hi. file . start_pos {
1110
1111
return Err ( SpanLinesError :: DistinctSources ( DistinctSources {
@@ -1184,59 +1185,6 @@ impl CodeMap {
1184
1185
}
1185
1186
}
1186
1187
1187
- /// Groups and sorts spans by lines into `MultiSpan`s, where `push` adds them to their group,
1188
- /// specifying the unification behaviour for overlapping spans.
1189
- /// Spans overflowing a line are put into their own one-element-group.
1190
- pub fn custom_group_spans < F > ( & self , mut spans : Vec < Span > , push : F ) -> Vec < MultiSpan >
1191
- where F : Fn ( & mut MultiSpan , Span )
1192
- {
1193
- spans. sort_by ( |a, b| a. lo . cmp ( & b. lo ) ) ;
1194
- let mut groups = Vec :: < MultiSpan > :: new ( ) ;
1195
- let mut overflowing = vec ! [ ] ;
1196
- let mut prev_expn = ExpnId ( !2u32 ) ;
1197
- let mut prev_file = !0usize ;
1198
- let mut prev_line = !0usize ;
1199
- let mut err_size = 0 ;
1200
-
1201
- for sp in spans {
1202
- let line = self . lookup_char_pos ( sp. lo ) . line ;
1203
- let line_hi = self . lookup_char_pos ( sp. hi ) . line ;
1204
- if line != line_hi {
1205
- overflowing. push ( sp. into ( ) ) ;
1206
- continue
1207
- }
1208
- let file = self . lookup_filemap_idx ( sp. lo ) ;
1209
-
1210
- if err_size < MAX_HIGHLIGHT_LINES && sp. expn_id == prev_expn && file == prev_file {
1211
- // `push` takes care of sorting, trimming, and merging
1212
- push ( & mut groups. last_mut ( ) . unwrap ( ) , sp) ;
1213
- if line != prev_line {
1214
- err_size += 1 ;
1215
- }
1216
- } else {
1217
- groups. push ( sp. into ( ) ) ;
1218
- err_size = 1 ;
1219
- }
1220
- prev_expn = sp. expn_id ;
1221
- prev_file = file;
1222
- prev_line = line;
1223
- }
1224
- groups. extend ( overflowing) ;
1225
- groups
1226
- }
1227
-
1228
- /// Groups and sorts spans by lines into `MultiSpan`s, merging overlapping spans.
1229
- /// Spans overflowing a line are put into their own one-element-group.
1230
- pub fn group_spans ( & self , spans : Vec < Span > ) -> Vec < MultiSpan > {
1231
- self . custom_group_spans ( spans, |msp, sp| msp. push_merge ( sp) )
1232
- }
1233
-
1234
- /// Like `group_spans`, but trims overlapping spans instead of
1235
- /// merging them (for use with `end_highlight_lines`)
1236
- pub fn end_group_spans ( & self , spans : Vec < Span > ) -> Vec < MultiSpan > {
1237
- self . custom_group_spans ( spans, |msp, sp| msp. push_trim ( sp) )
1238
- }
1239
-
1240
1188
pub fn get_filemap ( & self , filename : & str ) -> Rc < FileMap > {
1241
1189
for fm in self . files . borrow ( ) . iter ( ) {
1242
1190
if filename == fm. name {
0 commit comments