@@ -32,8 +32,6 @@ use serialize::{Encodable, Decodable, Encoder, Decoder};
3232
3333use ast:: Name ;
3434
35- use errors:: emitter:: MAX_HIGHLIGHT_LINES ;
36-
3735// _____________________________________________________________________________
3836// Pos, BytePos, CharPos
3937//
@@ -51,7 +49,7 @@ pub struct BytePos(pub u32);
5149/// A character offset. Because of multibyte utf8 characters, a byte offset
5250/// is not equivalent to a character offset. The CodeMap will convert BytePos
5351/// 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 ) ]
5553pub struct CharPos ( pub usize ) ;
5654
5755// FIXME: Lots of boilerplate in these impls, but so far my attempts to fix
@@ -132,13 +130,29 @@ 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. 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.
139139#[ derive( Clone ) ]
140140pub 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 > ,
142156}
143157
144158pub 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 {
276290
277291impl MultiSpan {
278292 pub fn new ( ) -> MultiSpan {
279- MultiSpan { spans : Vec :: new ( ) }
293+ MultiSpan {
294+ primary_spans : vec ! [ ] ,
295+ span_labels : vec ! [ ]
296+ }
280297 }
281298
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+ }
287304 }
288305
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 ! [ ]
324310 }
325311 }
326312
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+ }
330316
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+ } ) ;
339344 }
340345
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+ } ) ;
361353 }
362354 }
363- self . spans . push ( sp) ;
355+
356+ span_labels
364357 }
365358}
366359
367360impl From < Span > for MultiSpan {
368361 fn from ( span : Span ) -> MultiSpan {
369- MultiSpan { spans : vec ! [ span] }
362+ MultiSpan :: from_span ( span)
370363 }
371364}
372365
@@ -929,6 +922,10 @@ impl CodeMap {
929922 }
930923
931924 pub fn span_to_string ( & self , sp : Span ) -> String {
925+ if sp == COMMAND_LINE_SP {
926+ return "<command line option>" . to_string ( ) ;
927+ }
928+
932929 if self . files . borrow ( ) . is_empty ( ) && sp. source_equal ( & DUMMY_SP ) {
933930 return "no-location" . to_string ( ) ;
934931 }
@@ -1099,12 +1096,16 @@ impl CodeMap {
10991096 }
11001097
11011098 pub fn span_to_lines ( & self , sp : Span ) -> FileLinesResult {
1099+ debug ! ( "span_to_lines(sp={:?})" , sp) ;
1100+
11021101 if sp. lo > sp. hi {
11031102 return Err ( SpanLinesError :: IllFormedSpan ( sp) ) ;
11041103 }
11051104
11061105 let lo = self . lookup_char_pos ( sp. lo ) ;
1106+ debug ! ( "span_to_lines: lo={:?}" , lo) ;
11071107 let hi = self . lookup_char_pos ( sp. hi ) ;
1108+ debug ! ( "span_to_lines: hi={:?}" , hi) ;
11081109
11091110 if lo. file . start_pos != hi. file . start_pos {
11101111 return Err ( SpanLinesError :: DistinctSources ( DistinctSources {
@@ -1184,59 +1185,6 @@ impl CodeMap {
11841185 }
11851186 }
11861187
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-
12401188 pub fn get_filemap ( & self , filename : & str ) -> Rc < FileMap > {
12411189 for fm in self . files . borrow ( ) . iter ( ) {
12421190 if filename == fm. name {
0 commit comments