]> git.lizzy.rs Git - rust.git/blob - src/libsyntax_pos/lib.rs
Use a `newtype_index!` within `Symbol`.
[rust.git] / src / libsyntax_pos / lib.rs
1 // Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! The source positions and related helper functions.
12 //!
13 //! ## Note
14 //!
15 //! This API is completely unstable and subject to change.
16
17 #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
18       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
19       html_root_url = "https://doc.rust-lang.org/nightly/")]
20
21 #![feature(const_fn)]
22 #![feature(crate_visibility_modifier)]
23 #![feature(custom_attribute)]
24 #![feature(nll)]
25 #![feature(non_exhaustive)]
26 #![feature(optin_builtin_traits)]
27 #![feature(rustc_attrs)]
28 #![feature(specialization)]
29 #![feature(step_trait)]
30 #![cfg_attr(not(stage0), feature(stdsimd))]
31
32 extern crate arena;
33 #[macro_use]
34 extern crate rustc_data_structures;
35
36 #[macro_use]
37 extern crate scoped_tls;
38
39 use serialize::{Encodable, Decodable, Encoder, Decoder};
40
41 extern crate serialize;
42 extern crate serialize as rustc_serialize; // used by deriving
43
44 #[macro_use]
45 extern crate cfg_if;
46
47 extern crate unicode_width;
48
49 pub mod edition;
50 pub mod hygiene;
51 pub use hygiene::{Mark, SyntaxContext, ExpnInfo, ExpnFormat, CompilerDesugaringKind};
52
53 mod span_encoding;
54 pub use span_encoding::{Span, DUMMY_SP};
55
56 pub mod symbol;
57
58 mod analyze_source_file;
59
60 use rustc_data_structures::stable_hasher::StableHasher;
61 use rustc_data_structures::sync::{Lrc, Lock};
62
63 use std::borrow::Cow;
64 use std::cell::Cell;
65 use std::cmp::{self, Ordering};
66 use std::fmt;
67 use std::hash::{Hasher, Hash};
68 use std::ops::{Add, Sub};
69 use std::path::PathBuf;
70
71 pub struct Globals {
72     symbol_interner: Lock<symbol::Interner>,
73     span_interner: Lock<span_encoding::SpanInterner>,
74     hygiene_data: Lock<hygiene::HygieneData>,
75 }
76
77 impl Globals {
78     pub fn new() -> Globals {
79         Globals {
80             symbol_interner: Lock::new(symbol::Interner::fresh()),
81             span_interner: Lock::new(span_encoding::SpanInterner::default()),
82             hygiene_data: Lock::new(hygiene::HygieneData::new()),
83         }
84     }
85 }
86
87 scoped_thread_local!(pub static GLOBALS: Globals);
88
89 /// Differentiates between real files and common virtual files.
90 #[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash, RustcDecodable, RustcEncodable)]
91 pub enum FileName {
92     Real(PathBuf),
93     /// A macro.  This includes the full name of the macro, so that there are no clashes.
94     Macros(String),
95     /// Call to `quote!`.
96     QuoteExpansion(u64),
97     /// Command line.
98     Anon(u64),
99     /// Hack in `src/libsyntax/parse.rs`.
100     // FIXME(jseyfried)
101     MacroExpansion(u64),
102     ProcMacroSourceCode(u64),
103     /// Strings provided as `--cfg [cfgspec]` stored in a `crate_cfg`.
104     CfgSpec(u64),
105     /// Strings provided as crate attributes in the CLI.
106     CliCrateAttr(u64),
107     /// Custom sources for explicit parser calls from plugins and drivers.
108     Custom(String),
109     DocTest(PathBuf, isize),
110 }
111
112 impl std::fmt::Display for FileName {
113     fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
114         use self::FileName::*;
115         match *self {
116             Real(ref path) => write!(fmt, "{}", path.display()),
117             Macros(ref name) => write!(fmt, "<{} macros>", name),
118             QuoteExpansion(_) => write!(fmt, "<quote expansion>"),
119             MacroExpansion(_) => write!(fmt, "<macro expansion>"),
120             Anon(_) => write!(fmt, "<anon>"),
121             ProcMacroSourceCode(_) =>
122                 write!(fmt, "<proc-macro source code>"),
123             CfgSpec(_) => write!(fmt, "<cfgspec>"),
124             CliCrateAttr(_) => write!(fmt, "<crate attribute>"),
125             Custom(ref s) => write!(fmt, "<{}>", s),
126             DocTest(ref path, _) => write!(fmt, "{}", path.display()),
127         }
128     }
129 }
130
131 impl From<PathBuf> for FileName {
132     fn from(p: PathBuf) -> Self {
133         assert!(!p.to_string_lossy().ends_with('>'));
134         FileName::Real(p)
135     }
136 }
137
138 impl FileName {
139     pub fn is_real(&self) -> bool {
140         use self::FileName::*;
141         match *self {
142             Real(_) => true,
143             Macros(_) |
144             Anon(_) |
145             MacroExpansion(_) |
146             ProcMacroSourceCode(_) |
147             CfgSpec(_) |
148             CliCrateAttr(_) |
149             Custom(_) |
150             QuoteExpansion(_) |
151             DocTest(_, _) => false,
152         }
153     }
154
155     pub fn is_macros(&self) -> bool {
156         use self::FileName::*;
157         match *self {
158             Real(_) |
159             Anon(_) |
160             MacroExpansion(_) |
161             ProcMacroSourceCode(_) |
162             CfgSpec(_) |
163             CliCrateAttr(_) |
164             Custom(_) |
165             QuoteExpansion(_) |
166             DocTest(_, _) => false,
167             Macros(_) => true,
168         }
169     }
170
171     pub fn quote_expansion_source_code(src: &str) -> FileName {
172         let mut hasher = StableHasher::new();
173         src.hash(&mut hasher);
174         FileName::QuoteExpansion(hasher.finish())
175     }
176
177     pub fn macro_expansion_source_code(src: &str) -> FileName {
178         let mut hasher = StableHasher::new();
179         src.hash(&mut hasher);
180         FileName::MacroExpansion(hasher.finish())
181     }
182
183     pub fn anon_source_code(src: &str) -> FileName {
184         let mut hasher = StableHasher::new();
185         src.hash(&mut hasher);
186         FileName::Anon(hasher.finish())
187     }
188
189     pub fn proc_macro_source_code(src: &str) -> FileName {
190         let mut hasher = StableHasher::new();
191         src.hash(&mut hasher);
192         FileName::ProcMacroSourceCode(hasher.finish())
193     }
194
195     pub fn cfg_spec_source_code(src: &str) -> FileName {
196         let mut hasher = StableHasher::new();
197         src.hash(&mut hasher);
198         FileName::QuoteExpansion(hasher.finish())
199     }
200
201     pub fn cli_crate_attr_source_code(src: &str) -> FileName {
202         let mut hasher = StableHasher::new();
203         src.hash(&mut hasher);
204         FileName::CliCrateAttr(hasher.finish())
205     }
206
207     pub fn doc_test_source_code(path: PathBuf, line: isize) -> FileName{
208         FileName::DocTest(path, line)
209     }
210 }
211
212 /// Spans represent a region of code, used for error reporting. Positions in spans
213 /// are *absolute* positions from the beginning of the source_map, not positions
214 /// relative to `SourceFile`s. Methods on the `SourceMap` can be used to relate spans back
215 /// to the original source.
216 /// You must be careful if the span crosses more than one file - you will not be
217 /// able to use many of the functions on spans in source_map and you cannot assume
218 /// that the length of the `span = hi - lo`; there may be space in the `BytePos`
219 /// range between files.
220 ///
221 /// `SpanData` is public because `Span` uses a thread-local interner and can't be
222 /// sent to other threads, but some pieces of performance infra run in a separate thread.
223 /// Using `Span` is generally preferred.
224 #[derive(Clone, Copy, Hash, PartialEq, Eq, Ord, PartialOrd)]
225 pub struct SpanData {
226     pub lo: BytePos,
227     pub hi: BytePos,
228     /// Information about where the macro came from, if this piece of
229     /// code was created by a macro expansion.
230     pub ctxt: SyntaxContext,
231 }
232
233 impl SpanData {
234     #[inline]
235     pub fn with_lo(&self, lo: BytePos) -> Span {
236         Span::new(lo, self.hi, self.ctxt)
237     }
238     #[inline]
239     pub fn with_hi(&self, hi: BytePos) -> Span {
240         Span::new(self.lo, hi, self.ctxt)
241     }
242     #[inline]
243     pub fn with_ctxt(&self, ctxt: SyntaxContext) -> Span {
244         Span::new(self.lo, self.hi, ctxt)
245     }
246 }
247
248 // The interner is pointed to by a thread local value which is only set on the main thread
249 // with parallelization is disabled. So we don't allow `Span` to transfer between threads
250 // to avoid panics and other errors, even though it would be memory safe to do so.
251 #[cfg(not(parallel_queries))]
252 impl !Send for Span {}
253 #[cfg(not(parallel_queries))]
254 impl !Sync for Span {}
255
256 impl PartialOrd for Span {
257     fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
258         PartialOrd::partial_cmp(&self.data(), &rhs.data())
259     }
260 }
261 impl Ord for Span {
262     fn cmp(&self, rhs: &Self) -> Ordering {
263         Ord::cmp(&self.data(), &rhs.data())
264     }
265 }
266
267 /// A collection of spans. Spans have two orthogonal attributes:
268 ///
269 /// - They can be *primary spans*. In this case they are the locus of
270 ///   the error, and would be rendered with `^^^`.
271 /// - They can have a *label*. In this case, the label is written next
272 ///   to the mark in the snippet when we render.
273 #[derive(Clone, Debug, Hash, PartialEq, Eq, RustcEncodable, RustcDecodable)]
274 pub struct MultiSpan {
275     primary_spans: Vec<Span>,
276     span_labels: Vec<(Span, String)>,
277 }
278
279 impl Span {
280     #[inline]
281     pub fn lo(self) -> BytePos {
282         self.data().lo
283     }
284     #[inline]
285     pub fn with_lo(self, lo: BytePos) -> Span {
286         self.data().with_lo(lo)
287     }
288     #[inline]
289     pub fn hi(self) -> BytePos {
290         self.data().hi
291     }
292     #[inline]
293     pub fn with_hi(self, hi: BytePos) -> Span {
294         self.data().with_hi(hi)
295     }
296     #[inline]
297     pub fn ctxt(self) -> SyntaxContext {
298         self.data().ctxt
299     }
300     #[inline]
301     pub fn with_ctxt(self, ctxt: SyntaxContext) -> Span {
302         self.data().with_ctxt(ctxt)
303     }
304
305     /// Returns `true` if this is a dummy span with any hygienic context.
306     #[inline]
307     pub fn is_dummy(self) -> bool {
308         let span = self.data();
309         span.lo.0 == 0 && span.hi.0 == 0
310     }
311
312     /// Returns a new span representing an empty span at the beginning of this span
313     #[inline]
314     pub fn shrink_to_lo(self) -> Span {
315         let span = self.data();
316         span.with_hi(span.lo)
317     }
318     /// Returns a new span representing an empty span at the end of this span.
319     #[inline]
320     pub fn shrink_to_hi(self) -> Span {
321         let span = self.data();
322         span.with_lo(span.hi)
323     }
324
325     /// Returns `self` if `self` is not the dummy span, and `other` otherwise.
326     pub fn substitute_dummy(self, other: Span) -> Span {
327         if self.is_dummy() { other } else { self }
328     }
329
330     /// Return `true` if `self` fully encloses `other`.
331     pub fn contains(self, other: Span) -> bool {
332         let span = self.data();
333         let other = other.data();
334         span.lo <= other.lo && other.hi <= span.hi
335     }
336
337     /// Return true if the spans are equal with regards to the source text.
338     ///
339     /// Use this instead of `==` when either span could be generated code,
340     /// and you only care that they point to the same bytes of source text.
341     pub fn source_equal(&self, other: &Span) -> bool {
342         let span = self.data();
343         let other = other.data();
344         span.lo == other.lo && span.hi == other.hi
345     }
346
347     /// Returns `Some(span)`, where the start is trimmed by the end of `other`.
348     pub fn trim_start(self, other: Span) -> Option<Span> {
349         let span = self.data();
350         let other = other.data();
351         if span.hi > other.hi {
352             Some(span.with_lo(cmp::max(span.lo, other.hi)))
353         } else {
354             None
355         }
356     }
357
358     /// Return the source span -- this is either the supplied span, or the span for
359     /// the macro callsite that expanded to it.
360     pub fn source_callsite(self) -> Span {
361         self.ctxt().outer().expn_info().map(|info| info.call_site.source_callsite()).unwrap_or(self)
362     }
363
364     /// The `Span` for the tokens in the previous macro expansion from which `self` was generated,
365     /// if any.
366     pub fn parent(self) -> Option<Span> {
367         self.ctxt().outer().expn_info().map(|i| i.call_site)
368     }
369
370     /// Edition of the crate from which this span came.
371     pub fn edition(self) -> edition::Edition {
372         self.ctxt().outer().expn_info().map_or_else(|| hygiene::default_edition(),
373                                                     |einfo| einfo.edition)
374     }
375
376     #[inline]
377     pub fn rust_2015(&self) -> bool {
378         self.edition() == edition::Edition::Edition2015
379     }
380
381     #[inline]
382     pub fn rust_2018(&self) -> bool {
383         self.edition() >= edition::Edition::Edition2018
384     }
385
386     /// Return the source callee.
387     ///
388     /// Returns `None` if the supplied span has no expansion trace,
389     /// else returns the `ExpnInfo` for the macro definition
390     /// corresponding to the source callsite.
391     pub fn source_callee(self) -> Option<ExpnInfo> {
392         fn source_callee(info: ExpnInfo) -> ExpnInfo {
393             match info.call_site.ctxt().outer().expn_info() {
394                 Some(info) => source_callee(info),
395                 None => info,
396             }
397         }
398         self.ctxt().outer().expn_info().map(source_callee)
399     }
400
401     /// Check if a span is "internal" to a macro in which `#[unstable]`
402     /// items can be used (that is, a macro marked with
403     /// `#[allow_internal_unstable]`).
404     pub fn allows_unstable(&self) -> bool {
405         match self.ctxt().outer().expn_info() {
406             Some(info) => info.allow_internal_unstable,
407             None => false,
408         }
409     }
410
411     /// Check if this span arises from a compiler desugaring of kind `kind`.
412     pub fn is_compiler_desugaring(&self, kind: CompilerDesugaringKind) -> bool {
413         match self.ctxt().outer().expn_info() {
414             Some(info) => match info.format {
415                 ExpnFormat::CompilerDesugaring(k) => k == kind,
416                 _ => false,
417             },
418             None => false,
419         }
420     }
421
422     /// Return the compiler desugaring that created this span, or `None`
423     /// if this span is not from a desugaring.
424     pub fn compiler_desugaring_kind(&self) -> Option<CompilerDesugaringKind> {
425         match self.ctxt().outer().expn_info() {
426             Some(info) => match info.format {
427                 ExpnFormat::CompilerDesugaring(k) => Some(k),
428                 _ => None
429             },
430             None => None
431         }
432     }
433
434     /// Check if a span is "internal" to a macro in which `unsafe`
435     /// can be used without triggering the `unsafe_code` lint
436     //  (that is, a macro marked with `#[allow_internal_unsafe]`).
437     pub fn allows_unsafe(&self) -> bool {
438         match self.ctxt().outer().expn_info() {
439             Some(info) => info.allow_internal_unsafe,
440             None => false,
441         }
442     }
443
444     pub fn macro_backtrace(mut self) -> Vec<MacroBacktrace> {
445         let mut prev_span = DUMMY_SP;
446         let mut result = vec![];
447         while let Some(info) = self.ctxt().outer().expn_info() {
448             // Don't print recursive invocations.
449             if !info.call_site.source_equal(&prev_span) {
450                 let (pre, post) = match info.format {
451                     ExpnFormat::MacroAttribute(..) => ("#[", "]"),
452                     ExpnFormat::MacroBang(..) => ("", "!"),
453                     ExpnFormat::CompilerDesugaring(..) => ("desugaring of `", "`"),
454                 };
455                 result.push(MacroBacktrace {
456                     call_site: info.call_site,
457                     macro_decl_name: format!("{}{}{}", pre, info.format.name(), post),
458                     def_site_span: info.def_site,
459                 });
460             }
461
462             prev_span = self;
463             self = info.call_site;
464         }
465         result
466     }
467
468     /// Return a `Span` that would enclose both `self` and `end`.
469     pub fn to(self, end: Span) -> Span {
470         let span_data = self.data();
471         let end_data = end.data();
472         // FIXME(jseyfried): `self.ctxt` should always equal `end.ctxt` here (cf. issue #23480).
473         // Return the macro span on its own to avoid weird diagnostic output. It is preferable to
474         // have an incomplete span than a completely nonsensical one.
475         if span_data.ctxt != end_data.ctxt {
476             if span_data.ctxt == SyntaxContext::empty() {
477                 return end;
478             } else if end_data.ctxt == SyntaxContext::empty() {
479                 return self;
480             }
481             // Both spans fall within a macro.
482             // FIXME(estebank): check if it is the *same* macro.
483         }
484         Span::new(
485             cmp::min(span_data.lo, end_data.lo),
486             cmp::max(span_data.hi, end_data.hi),
487             if span_data.ctxt == SyntaxContext::empty() { end_data.ctxt } else { span_data.ctxt },
488         )
489     }
490
491     /// Return a `Span` between the end of `self` to the beginning of `end`.
492     pub fn between(self, end: Span) -> Span {
493         let span = self.data();
494         let end = end.data();
495         Span::new(
496             span.hi,
497             end.lo,
498             if end.ctxt == SyntaxContext::empty() { end.ctxt } else { span.ctxt },
499         )
500     }
501
502     /// Return a `Span` between the beginning of `self` to the beginning of `end`.
503     pub fn until(self, end: Span) -> Span {
504         let span = self.data();
505         let end = end.data();
506         Span::new(
507             span.lo,
508             end.lo,
509             if end.ctxt == SyntaxContext::empty() { end.ctxt } else { span.ctxt },
510         )
511     }
512
513     pub fn from_inner_byte_pos(self, start: usize, end: usize) -> Span {
514         let span = self.data();
515         Span::new(span.lo + BytePos::from_usize(start),
516                   span.lo + BytePos::from_usize(end),
517                   span.ctxt)
518     }
519
520     #[inline]
521     pub fn apply_mark(self, mark: Mark) -> Span {
522         let span = self.data();
523         span.with_ctxt(span.ctxt.apply_mark(mark))
524     }
525
526     #[inline]
527     pub fn remove_mark(&mut self) -> Mark {
528         let mut span = self.data();
529         let mark = span.ctxt.remove_mark();
530         *self = Span::new(span.lo, span.hi, span.ctxt);
531         mark
532     }
533
534     #[inline]
535     pub fn adjust(&mut self, expansion: Mark) -> Option<Mark> {
536         let mut span = self.data();
537         let mark = span.ctxt.adjust(expansion);
538         *self = Span::new(span.lo, span.hi, span.ctxt);
539         mark
540     }
541
542     #[inline]
543     pub fn glob_adjust(&mut self, expansion: Mark, glob_ctxt: SyntaxContext)
544                        -> Option<Option<Mark>> {
545         let mut span = self.data();
546         let mark = span.ctxt.glob_adjust(expansion, glob_ctxt);
547         *self = Span::new(span.lo, span.hi, span.ctxt);
548         mark
549     }
550
551     #[inline]
552     pub fn reverse_glob_adjust(&mut self, expansion: Mark, glob_ctxt: SyntaxContext)
553                                -> Option<Option<Mark>> {
554         let mut span = self.data();
555         let mark = span.ctxt.reverse_glob_adjust(expansion, glob_ctxt);
556         *self = Span::new(span.lo, span.hi, span.ctxt);
557         mark
558     }
559
560     #[inline]
561     pub fn modern(self) -> Span {
562         let span = self.data();
563         span.with_ctxt(span.ctxt.modern())
564     }
565
566     #[inline]
567     pub fn modern_and_legacy(self) -> Span {
568         let span = self.data();
569         span.with_ctxt(span.ctxt.modern_and_legacy())
570     }
571 }
572
573 #[derive(Clone, Debug)]
574 pub struct SpanLabel {
575     /// The span we are going to include in the final snippet.
576     pub span: Span,
577
578     /// Is this a primary span? This is the "locus" of the message,
579     /// and is indicated with a `^^^^` underline, versus `----`.
580     pub is_primary: bool,
581
582     /// What label should we attach to this span (if any)?
583     pub label: Option<String>,
584 }
585
586 impl Default for Span {
587     fn default() -> Self {
588         DUMMY_SP
589     }
590 }
591
592 impl serialize::UseSpecializedEncodable for Span {
593     fn default_encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
594         let span = self.data();
595         s.emit_struct("Span", 2, |s| {
596             s.emit_struct_field("lo", 0, |s| {
597                 span.lo.encode(s)
598             })?;
599
600             s.emit_struct_field("hi", 1, |s| {
601                 span.hi.encode(s)
602             })
603         })
604     }
605 }
606
607 impl serialize::UseSpecializedDecodable for Span {
608     fn default_decode<D: Decoder>(d: &mut D) -> Result<Span, D::Error> {
609         d.read_struct("Span", 2, |d| {
610             let lo = d.read_struct_field("lo", 0, Decodable::decode)?;
611             let hi = d.read_struct_field("hi", 1, Decodable::decode)?;
612             Ok(Span::new(lo, hi, NO_EXPANSION))
613         })
614     }
615 }
616
617 pub fn default_span_debug(span: Span, f: &mut fmt::Formatter) -> fmt::Result {
618     f.debug_struct("Span")
619         .field("lo", &span.lo())
620         .field("hi", &span.hi())
621         .field("ctxt", &span.ctxt())
622         .finish()
623 }
624
625 impl fmt::Debug for Span {
626     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
627         SPAN_DEBUG.with(|span_debug| span_debug.get()(*self, f))
628     }
629 }
630
631 impl fmt::Debug for SpanData {
632     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
633         SPAN_DEBUG.with(|span_debug| span_debug.get()(Span::new(self.lo, self.hi, self.ctxt), f))
634     }
635 }
636
637 impl MultiSpan {
638     #[inline]
639     pub fn new() -> MultiSpan {
640         MultiSpan {
641             primary_spans: vec![],
642             span_labels: vec![]
643         }
644     }
645
646     pub fn from_span(primary_span: Span) -> MultiSpan {
647         MultiSpan {
648             primary_spans: vec![primary_span],
649             span_labels: vec![]
650         }
651     }
652
653     pub fn from_spans(vec: Vec<Span>) -> MultiSpan {
654         MultiSpan {
655             primary_spans: vec,
656             span_labels: vec![]
657         }
658     }
659
660     pub fn push_span_label(&mut self, span: Span, label: String) {
661         self.span_labels.push((span, label));
662     }
663
664     /// Selects the first primary span (if any).
665     pub fn primary_span(&self) -> Option<Span> {
666         self.primary_spans.first().cloned()
667     }
668
669     /// Returns all primary spans.
670     pub fn primary_spans(&self) -> &[Span] {
671         &self.primary_spans
672     }
673
674     /// Returns `true` if this contains only a dummy primary span with any hygienic context.
675     pub fn is_dummy(&self) -> bool {
676         let mut is_dummy = true;
677         for span in &self.primary_spans {
678             if !span.is_dummy() {
679                 is_dummy = false;
680             }
681         }
682         is_dummy
683     }
684
685     /// Replaces all occurrences of one Span with another. Used to move `Span`s in areas that don't
686     /// display well (like std macros). Returns true if replacements occurred.
687     pub fn replace(&mut self, before: Span, after: Span) -> bool {
688         let mut replacements_occurred = false;
689         for primary_span in &mut self.primary_spans {
690             if *primary_span == before {
691                 *primary_span = after;
692                 replacements_occurred = true;
693             }
694         }
695         for span_label in &mut self.span_labels {
696             if span_label.0 == before {
697                 span_label.0 = after;
698                 replacements_occurred = true;
699             }
700         }
701         replacements_occurred
702     }
703
704     /// Returns the strings to highlight. We always ensure that there
705     /// is an entry for each of the primary spans -- for each primary
706     /// span `P`, if there is at least one label with span `P`, we return
707     /// those labels (marked as primary). But otherwise we return
708     /// `SpanLabel` instances with empty labels.
709     pub fn span_labels(&self) -> Vec<SpanLabel> {
710         let is_primary = |span| self.primary_spans.contains(&span);
711
712         let mut span_labels = self.span_labels.iter().map(|&(span, ref label)|
713             SpanLabel {
714                 span,
715                 is_primary: is_primary(span),
716                 label: Some(label.clone())
717             }
718         ).collect::<Vec<_>>();
719
720         for &span in &self.primary_spans {
721             if !span_labels.iter().any(|sl| sl.span == span) {
722                 span_labels.push(SpanLabel {
723                     span,
724                     is_primary: true,
725                     label: None
726                 });
727             }
728         }
729
730         span_labels
731     }
732 }
733
734 impl From<Span> for MultiSpan {
735     fn from(span: Span) -> MultiSpan {
736         MultiSpan::from_span(span)
737     }
738 }
739
740 impl From<Vec<Span>> for MultiSpan {
741     fn from(spans: Vec<Span>) -> MultiSpan {
742         MultiSpan::from_spans(spans)
743     }
744 }
745
746 pub const NO_EXPANSION: SyntaxContext = SyntaxContext::empty();
747
748 /// Identifies an offset of a multi-byte character in a `SourceFile`.
749 #[derive(Copy, Clone, RustcEncodable, RustcDecodable, Eq, PartialEq, Debug)]
750 pub struct MultiByteChar {
751     /// The absolute offset of the character in the `SourceMap`.
752     pub pos: BytePos,
753     /// The number of bytes, `>= 2`.
754     pub bytes: u8,
755 }
756
757 /// Identifies an offset of a non-narrow character in a `SourceFile`.
758 #[derive(Copy, Clone, RustcEncodable, RustcDecodable, Eq, PartialEq, Debug)]
759 pub enum NonNarrowChar {
760     /// Represents a zero-width character.
761     ZeroWidth(BytePos),
762     /// Represents a wide (full-width) character.
763     Wide(BytePos),
764     /// Represents a tab character, represented visually with a width of 4 characters.
765     Tab(BytePos),
766 }
767
768 impl NonNarrowChar {
769     fn new(pos: BytePos, width: usize) -> Self {
770         match width {
771             0 => NonNarrowChar::ZeroWidth(pos),
772             2 => NonNarrowChar::Wide(pos),
773             4 => NonNarrowChar::Tab(pos),
774             _ => panic!("width {} given for non-narrow character", width),
775         }
776     }
777
778     /// Returns the absolute offset of the character in the `SourceMap`.
779     pub fn pos(&self) -> BytePos {
780         match *self {
781             NonNarrowChar::ZeroWidth(p) |
782             NonNarrowChar::Wide(p) |
783             NonNarrowChar::Tab(p) => p,
784         }
785     }
786
787     /// Returns the width of the character, 0 (zero-width) or 2 (wide).
788     pub fn width(&self) -> usize {
789         match *self {
790             NonNarrowChar::ZeroWidth(_) => 0,
791             NonNarrowChar::Wide(_) => 2,
792             NonNarrowChar::Tab(_) => 4,
793         }
794     }
795 }
796
797 impl Add<BytePos> for NonNarrowChar {
798     type Output = Self;
799
800     fn add(self, rhs: BytePos) -> Self {
801         match self {
802             NonNarrowChar::ZeroWidth(pos) => NonNarrowChar::ZeroWidth(pos + rhs),
803             NonNarrowChar::Wide(pos) => NonNarrowChar::Wide(pos + rhs),
804             NonNarrowChar::Tab(pos) => NonNarrowChar::Tab(pos + rhs),
805         }
806     }
807 }
808
809 impl Sub<BytePos> for NonNarrowChar {
810     type Output = Self;
811
812     fn sub(self, rhs: BytePos) -> Self {
813         match self {
814             NonNarrowChar::ZeroWidth(pos) => NonNarrowChar::ZeroWidth(pos - rhs),
815             NonNarrowChar::Wide(pos) => NonNarrowChar::Wide(pos - rhs),
816             NonNarrowChar::Tab(pos) => NonNarrowChar::Tab(pos - rhs),
817         }
818     }
819 }
820
821 /// The state of the lazy external source loading mechanism of a `SourceFile`.
822 #[derive(PartialEq, Eq, Clone)]
823 pub enum ExternalSource {
824     /// The external source has been loaded already.
825     Present(String),
826     /// No attempt has been made to load the external source.
827     AbsentOk,
828     /// A failed attempt has been made to load the external source.
829     AbsentErr,
830     /// No external source has to be loaded, since the `SourceFile` represents a local crate.
831     Unneeded,
832 }
833
834 impl ExternalSource {
835     pub fn is_absent(&self) -> bool {
836         match *self {
837             ExternalSource::Present(_) => false,
838             _ => true,
839         }
840     }
841
842     pub fn get_source(&self) -> Option<&str> {
843         match *self {
844             ExternalSource::Present(ref src) => Some(src),
845             _ => None,
846         }
847     }
848 }
849
850 /// A single source in the `SourceMap`.
851 #[derive(Clone)]
852 pub struct SourceFile {
853     /// The name of the file that the source came from, source that doesn't
854     /// originate from files has names between angle brackets by convention
855     /// (e.g., `<anon>`).
856     pub name: FileName,
857     /// True if the `name` field above has been modified by `--remap-path-prefix`.
858     pub name_was_remapped: bool,
859     /// The unmapped path of the file that the source came from.
860     /// Set to `None` if the `SourceFile` was imported from an external crate.
861     pub unmapped_path: Option<FileName>,
862     /// Indicates which crate this `SourceFile` was imported from.
863     pub crate_of_origin: u32,
864     /// The complete source code.
865     pub src: Option<Lrc<String>>,
866     /// The source code's hash.
867     pub src_hash: u128,
868     /// The external source code (used for external crates, which will have a `None`
869     /// value as `self.src`.
870     pub external_src: Lock<ExternalSource>,
871     /// The start position of this source in the `SourceMap`.
872     pub start_pos: BytePos,
873     /// The end position of this source in the `SourceMap`.
874     pub end_pos: BytePos,
875     /// Locations of lines beginnings in the source code.
876     pub lines: Vec<BytePos>,
877     /// Locations of multi-byte characters in the source code.
878     pub multibyte_chars: Vec<MultiByteChar>,
879     /// Width of characters that are not narrow in the source code.
880     pub non_narrow_chars: Vec<NonNarrowChar>,
881     /// A hash of the filename, used for speeding up hashing in incremental compilation.
882     pub name_hash: u128,
883 }
884
885 impl Encodable for SourceFile {
886     fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
887         s.emit_struct("SourceFile", 8, |s| {
888             s.emit_struct_field("name", 0, |s| self.name.encode(s))?;
889             s.emit_struct_field("name_was_remapped", 1, |s| self.name_was_remapped.encode(s))?;
890             s.emit_struct_field("src_hash", 2, |s| self.src_hash.encode(s))?;
891             s.emit_struct_field("start_pos", 4, |s| self.start_pos.encode(s))?;
892             s.emit_struct_field("end_pos", 5, |s| self.end_pos.encode(s))?;
893             s.emit_struct_field("lines", 6, |s| {
894                 let lines = &self.lines[..];
895                 // Store the length.
896                 s.emit_u32(lines.len() as u32)?;
897
898                 if !lines.is_empty() {
899                     // In order to preserve some space, we exploit the fact that
900                     // the lines list is sorted and individual lines are
901                     // probably not that long. Because of that we can store lines
902                     // as a difference list, using as little space as possible
903                     // for the differences.
904                     let max_line_length = if lines.len() == 1 {
905                         0
906                     } else {
907                         lines.windows(2)
908                              .map(|w| w[1] - w[0])
909                              .map(|bp| bp.to_usize())
910                              .max()
911                              .unwrap()
912                     };
913
914                     let bytes_per_diff: u8 = match max_line_length {
915                         0 ..= 0xFF => 1,
916                         0x100 ..= 0xFFFF => 2,
917                         _ => 4
918                     };
919
920                     // Encode the number of bytes used per diff.
921                     bytes_per_diff.encode(s)?;
922
923                     // Encode the first element.
924                     lines[0].encode(s)?;
925
926                     let diff_iter = (&lines[..]).windows(2)
927                                                 .map(|w| (w[1] - w[0]));
928
929                     match bytes_per_diff {
930                         1 => for diff in diff_iter { (diff.0 as u8).encode(s)? },
931                         2 => for diff in diff_iter { (diff.0 as u16).encode(s)? },
932                         4 => for diff in diff_iter { diff.0.encode(s)? },
933                         _ => unreachable!()
934                     }
935                 }
936
937                 Ok(())
938             })?;
939             s.emit_struct_field("multibyte_chars", 7, |s| {
940                 self.multibyte_chars.encode(s)
941             })?;
942             s.emit_struct_field("non_narrow_chars", 8, |s| {
943                 self.non_narrow_chars.encode(s)
944             })?;
945             s.emit_struct_field("name_hash", 9, |s| {
946                 self.name_hash.encode(s)
947             })
948         })
949     }
950 }
951
952 impl Decodable for SourceFile {
953     fn decode<D: Decoder>(d: &mut D) -> Result<SourceFile, D::Error> {
954
955         d.read_struct("SourceFile", 8, |d| {
956             let name: FileName = d.read_struct_field("name", 0, |d| Decodable::decode(d))?;
957             let name_was_remapped: bool =
958                 d.read_struct_field("name_was_remapped", 1, |d| Decodable::decode(d))?;
959             let src_hash: u128 =
960                 d.read_struct_field("src_hash", 2, |d| Decodable::decode(d))?;
961             let start_pos: BytePos =
962                 d.read_struct_field("start_pos", 4, |d| Decodable::decode(d))?;
963             let end_pos: BytePos = d.read_struct_field("end_pos", 5, |d| Decodable::decode(d))?;
964             let lines: Vec<BytePos> = d.read_struct_field("lines", 6, |d| {
965                 let num_lines: u32 = Decodable::decode(d)?;
966                 let mut lines = Vec::with_capacity(num_lines as usize);
967
968                 if num_lines > 0 {
969                     // Read the number of bytes used per diff.
970                     let bytes_per_diff: u8 = Decodable::decode(d)?;
971
972                     // Read the first element.
973                     let mut line_start: BytePos = Decodable::decode(d)?;
974                     lines.push(line_start);
975
976                     for _ in 1..num_lines {
977                         let diff = match bytes_per_diff {
978                             1 => d.read_u8()? as u32,
979                             2 => d.read_u16()? as u32,
980                             4 => d.read_u32()?,
981                             _ => unreachable!()
982                         };
983
984                         line_start = line_start + BytePos(diff);
985
986                         lines.push(line_start);
987                     }
988                 }
989
990                 Ok(lines)
991             })?;
992             let multibyte_chars: Vec<MultiByteChar> =
993                 d.read_struct_field("multibyte_chars", 7, |d| Decodable::decode(d))?;
994             let non_narrow_chars: Vec<NonNarrowChar> =
995                 d.read_struct_field("non_narrow_chars", 8, |d| Decodable::decode(d))?;
996             let name_hash: u128 =
997                 d.read_struct_field("name_hash", 9, |d| Decodable::decode(d))?;
998             Ok(SourceFile {
999                 name,
1000                 name_was_remapped,
1001                 unmapped_path: None,
1002                 // `crate_of_origin` has to be set by the importer.
1003                 // This value matches up with rustc::hir::def_id::INVALID_CRATE.
1004                 // That constant is not available here unfortunately :(
1005                 crate_of_origin: ::std::u32::MAX - 1,
1006                 start_pos,
1007                 end_pos,
1008                 src: None,
1009                 src_hash,
1010                 external_src: Lock::new(ExternalSource::AbsentOk),
1011                 lines,
1012                 multibyte_chars,
1013                 non_narrow_chars,
1014                 name_hash,
1015             })
1016         })
1017     }
1018 }
1019
1020 impl fmt::Debug for SourceFile {
1021     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1022         write!(fmt, "SourceFile({})", self.name)
1023     }
1024 }
1025
1026 impl SourceFile {
1027     pub fn new(name: FileName,
1028                name_was_remapped: bool,
1029                unmapped_path: FileName,
1030                mut src: String,
1031                start_pos: BytePos) -> SourceFile {
1032         remove_bom(&mut src);
1033
1034         let src_hash = {
1035             let mut hasher: StableHasher<u128> = StableHasher::new();
1036             hasher.write(src.as_bytes());
1037             hasher.finish()
1038         };
1039         let name_hash = {
1040             let mut hasher: StableHasher<u128> = StableHasher::new();
1041             name.hash(&mut hasher);
1042             hasher.finish()
1043         };
1044         let end_pos = start_pos.to_usize() + src.len();
1045
1046         let (lines, multibyte_chars, non_narrow_chars) =
1047             analyze_source_file::analyze_source_file(&src[..], start_pos);
1048
1049         SourceFile {
1050             name,
1051             name_was_remapped,
1052             unmapped_path: Some(unmapped_path),
1053             crate_of_origin: 0,
1054             src: Some(Lrc::new(src)),
1055             src_hash,
1056             external_src: Lock::new(ExternalSource::Unneeded),
1057             start_pos,
1058             end_pos: Pos::from_usize(end_pos),
1059             lines,
1060             multibyte_chars,
1061             non_narrow_chars,
1062             name_hash,
1063         }
1064     }
1065
1066     /// Return the `BytePos` of the beginning of the current line.
1067     pub fn line_begin_pos(&self, pos: BytePos) -> BytePos {
1068         let line_index = self.lookup_line(pos).unwrap();
1069         self.lines[line_index]
1070     }
1071
1072     /// Add externally loaded source.
1073     /// If the hash of the input doesn't match or no input is supplied via None,
1074     /// it is interpreted as an error and the corresponding enum variant is set.
1075     /// The return value signifies whether some kind of source is present.
1076     pub fn add_external_src<F>(&self, get_src: F) -> bool
1077         where F: FnOnce() -> Option<String>
1078     {
1079         if *self.external_src.borrow() == ExternalSource::AbsentOk {
1080             let src = get_src();
1081             let mut external_src = self.external_src.borrow_mut();
1082             // Check that no-one else have provided the source while we were getting it
1083             if *external_src == ExternalSource::AbsentOk {
1084                 if let Some(src) = src {
1085                     let mut hasher: StableHasher<u128> = StableHasher::new();
1086                     hasher.write(src.as_bytes());
1087
1088                     if hasher.finish() == self.src_hash {
1089                         *external_src = ExternalSource::Present(src);
1090                         return true;
1091                     }
1092                 } else {
1093                     *external_src = ExternalSource::AbsentErr;
1094                 }
1095
1096                 false
1097             } else {
1098                 self.src.is_some() || external_src.get_source().is_some()
1099             }
1100         } else {
1101             self.src.is_some() || self.external_src.borrow().get_source().is_some()
1102         }
1103     }
1104
1105     /// Get a line from the list of pre-computed line-beginnings.
1106     /// The line number here is 0-based.
1107     pub fn get_line(&self, line_number: usize) -> Option<Cow<str>> {
1108         fn get_until_newline(src: &str, begin: usize) -> &str {
1109             // We can't use `lines.get(line_number+1)` because we might
1110             // be parsing when we call this function and thus the current
1111             // line is the last one we have line info for.
1112             let slice = &src[begin..];
1113             match slice.find('\n') {
1114                 Some(e) => &slice[..e],
1115                 None => slice
1116             }
1117         }
1118
1119         let begin = {
1120             let line = if let Some(line) = self.lines.get(line_number) {
1121                 line
1122             } else {
1123                 return None;
1124             };
1125             let begin: BytePos = *line - self.start_pos;
1126             begin.to_usize()
1127         };
1128
1129         if let Some(ref src) = self.src {
1130             Some(Cow::from(get_until_newline(src, begin)))
1131         } else if let Some(src) = self.external_src.borrow().get_source() {
1132             Some(Cow::Owned(String::from(get_until_newline(src, begin))))
1133         } else {
1134             None
1135         }
1136     }
1137
1138     pub fn is_real_file(&self) -> bool {
1139         self.name.is_real()
1140     }
1141
1142     pub fn is_imported(&self) -> bool {
1143         self.src.is_none()
1144     }
1145
1146     pub fn byte_length(&self) -> u32 {
1147         self.end_pos.0 - self.start_pos.0
1148     }
1149     pub fn count_lines(&self) -> usize {
1150         self.lines.len()
1151     }
1152
1153     /// Find the line containing the given position. The return value is the
1154     /// index into the `lines` array of this `SourceFile`, not the 1-based line
1155     /// number. If the source_file is empty or the position is located before the
1156     /// first line, `None` is returned.
1157     pub fn lookup_line(&self, pos: BytePos) -> Option<usize> {
1158         if self.lines.len() == 0 {
1159             return None;
1160         }
1161
1162         let line_index = lookup_line(&self.lines[..], pos);
1163         assert!(line_index < self.lines.len() as isize);
1164         if line_index >= 0 {
1165             Some(line_index as usize)
1166         } else {
1167             None
1168         }
1169     }
1170
1171     pub fn line_bounds(&self, line_index: usize) -> (BytePos, BytePos) {
1172         if self.start_pos == self.end_pos {
1173             return (self.start_pos, self.end_pos);
1174         }
1175
1176         assert!(line_index < self.lines.len());
1177         if line_index == (self.lines.len() - 1) {
1178             (self.lines[line_index], self.end_pos)
1179         } else {
1180             (self.lines[line_index], self.lines[line_index + 1])
1181         }
1182     }
1183
1184     #[inline]
1185     pub fn contains(&self, byte_pos: BytePos) -> bool {
1186         byte_pos >= self.start_pos && byte_pos <= self.end_pos
1187     }
1188 }
1189
1190 /// Remove utf-8 BOM if any.
1191 fn remove_bom(src: &mut String) {
1192     if src.starts_with("\u{feff}") {
1193         src.drain(..3);
1194     }
1195 }
1196
1197 // _____________________________________________________________________________
1198 // Pos, BytePos, CharPos
1199 //
1200
1201 pub trait Pos {
1202     fn from_usize(n: usize) -> Self;
1203     fn to_usize(&self) -> usize;
1204     fn from_u32(n: u32) -> Self;
1205     fn to_u32(&self) -> u32;
1206 }
1207
1208 /// A byte offset. Keep this small (currently 32-bits), as AST contains
1209 /// a lot of them.
1210 #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
1211 pub struct BytePos(pub u32);
1212
1213 /// A character offset. Because of multibyte UTF-8 characters, a byte offset
1214 /// is not equivalent to a character offset. The `SourceMap` will convert `BytePos`
1215 /// values to `CharPos` values as necessary.
1216 #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
1217 pub struct CharPos(pub usize);
1218
1219 // FIXME: lots of boilerplate in these impls, but so far my attempts to fix
1220 // have been unsuccessful.
1221
1222 impl Pos for BytePos {
1223     #[inline(always)]
1224     fn from_usize(n: usize) -> BytePos { BytePos(n as u32) }
1225
1226     #[inline(always)]
1227     fn to_usize(&self) -> usize { self.0 as usize }
1228
1229     #[inline(always)]
1230     fn from_u32(n: u32) -> BytePos { BytePos(n) }
1231
1232     #[inline(always)]
1233     fn to_u32(&self) -> u32 { self.0 }
1234 }
1235
1236 impl Add for BytePos {
1237     type Output = BytePos;
1238
1239     #[inline(always)]
1240     fn add(self, rhs: BytePos) -> BytePos {
1241         BytePos((self.to_usize() + rhs.to_usize()) as u32)
1242     }
1243 }
1244
1245 impl Sub for BytePos {
1246     type Output = BytePos;
1247
1248     #[inline(always)]
1249     fn sub(self, rhs: BytePos) -> BytePos {
1250         BytePos((self.to_usize() - rhs.to_usize()) as u32)
1251     }
1252 }
1253
1254 impl Encodable for BytePos {
1255     fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
1256         s.emit_u32(self.0)
1257     }
1258 }
1259
1260 impl Decodable for BytePos {
1261     fn decode<D: Decoder>(d: &mut D) -> Result<BytePos, D::Error> {
1262         Ok(BytePos(d.read_u32()?))
1263     }
1264 }
1265
1266 impl Pos for CharPos {
1267     #[inline(always)]
1268     fn from_usize(n: usize) -> CharPos { CharPos(n) }
1269
1270     #[inline(always)]
1271     fn to_usize(&self) -> usize { self.0 }
1272
1273     #[inline(always)]
1274     fn from_u32(n: u32) -> CharPos { CharPos(n as usize) }
1275
1276     #[inline(always)]
1277     fn to_u32(&self) -> u32 { self.0 as u32}
1278 }
1279
1280 impl Add for CharPos {
1281     type Output = CharPos;
1282
1283     #[inline(always)]
1284     fn add(self, rhs: CharPos) -> CharPos {
1285         CharPos(self.to_usize() + rhs.to_usize())
1286     }
1287 }
1288
1289 impl Sub for CharPos {
1290     type Output = CharPos;
1291
1292     #[inline(always)]
1293     fn sub(self, rhs: CharPos) -> CharPos {
1294         CharPos(self.to_usize() - rhs.to_usize())
1295     }
1296 }
1297
1298 // _____________________________________________________________________________
1299 // Loc, LocWithOpt, SourceFileAndLine, SourceFileAndBytePos
1300 //
1301
1302 /// A source code location used for error reporting.
1303 #[derive(Debug, Clone)]
1304 pub struct Loc {
1305     /// Information about the original source.
1306     pub file: Lrc<SourceFile>,
1307     /// The (1-based) line number.
1308     pub line: usize,
1309     /// The (0-based) column offset.
1310     pub col: CharPos,
1311     /// The (0-based) column offset when displayed.
1312     pub col_display: usize,
1313 }
1314
1315 /// A source code location used as the result of `lookup_char_pos_adj`.
1316 // Actually, *none* of the clients use the filename *or* file field;
1317 // perhaps they should just be removed.
1318 #[derive(Debug)]
1319 pub struct LocWithOpt {
1320     pub filename: FileName,
1321     pub line: usize,
1322     pub col: CharPos,
1323     pub file: Option<Lrc<SourceFile>>,
1324 }
1325
1326 // Used to be structural records.
1327 #[derive(Debug)]
1328 pub struct SourceFileAndLine { pub sf: Lrc<SourceFile>, pub line: usize }
1329 #[derive(Debug)]
1330 pub struct SourceFileAndBytePos { pub sf: Lrc<SourceFile>, pub pos: BytePos }
1331
1332 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
1333 pub struct LineInfo {
1334     /// Index of line, starting from 0.
1335     pub line_index: usize,
1336
1337     /// Column in line where span begins, starting from 0.
1338     pub start_col: CharPos,
1339
1340     /// Column in line where span ends, starting from 0, exclusive.
1341     pub end_col: CharPos,
1342 }
1343
1344 pub struct FileLines {
1345     pub file: Lrc<SourceFile>,
1346     pub lines: Vec<LineInfo>
1347 }
1348
1349 thread_local!(pub static SPAN_DEBUG: Cell<fn(Span, &mut fmt::Formatter) -> fmt::Result> =
1350                 Cell::new(default_span_debug));
1351
1352 #[derive(Debug)]
1353 pub struct MacroBacktrace {
1354     /// span where macro was applied to generate this code
1355     pub call_site: Span,
1356
1357     /// name of macro that was applied (e.g., "foo!" or "#[derive(Eq)]")
1358     pub macro_decl_name: String,
1359
1360     /// span where macro was defined (if known)
1361     pub def_site_span: Option<Span>,
1362 }
1363
1364 // _____________________________________________________________________________
1365 // SpanLinesError, SpanSnippetError, DistinctSources, MalformedSourceMapPositions
1366 //
1367
1368 pub type FileLinesResult = Result<FileLines, SpanLinesError>;
1369
1370 #[derive(Clone, PartialEq, Eq, Debug)]
1371 pub enum SpanLinesError {
1372     IllFormedSpan(Span),
1373     DistinctSources(DistinctSources),
1374 }
1375
1376 #[derive(Clone, PartialEq, Eq, Debug)]
1377 pub enum SpanSnippetError {
1378     IllFormedSpan(Span),
1379     DistinctSources(DistinctSources),
1380     MalformedForSourcemap(MalformedSourceMapPositions),
1381     SourceNotAvailable { filename: FileName }
1382 }
1383
1384 #[derive(Clone, PartialEq, Eq, Debug)]
1385 pub struct DistinctSources {
1386     pub begin: (FileName, BytePos),
1387     pub end: (FileName, BytePos)
1388 }
1389
1390 #[derive(Clone, PartialEq, Eq, Debug)]
1391 pub struct MalformedSourceMapPositions {
1392     pub name: FileName,
1393     pub source_len: usize,
1394     pub begin_pos: BytePos,
1395     pub end_pos: BytePos
1396 }
1397
1398 // Given a slice of line start positions and a position, returns the index of
1399 // the line the position is on. Returns -1 if the position is located before
1400 // the first line.
1401 fn lookup_line(lines: &[BytePos], pos: BytePos) -> isize {
1402     match lines.binary_search(&pos) {
1403         Ok(line) => line as isize,
1404         Err(line) => line as isize - 1
1405     }
1406 }
1407
1408 #[cfg(test)]
1409 mod tests {
1410     use super::{lookup_line, BytePos};
1411
1412     #[test]
1413     fn test_lookup_line() {
1414
1415         let lines = &[BytePos(3), BytePos(17), BytePos(28)];
1416
1417         assert_eq!(lookup_line(lines, BytePos(0)), -1);
1418         assert_eq!(lookup_line(lines, BytePos(3)),  0);
1419         assert_eq!(lookup_line(lines, BytePos(4)),  0);
1420
1421         assert_eq!(lookup_line(lines, BytePos(16)), 0);
1422         assert_eq!(lookup_line(lines, BytePos(17)), 1);
1423         assert_eq!(lookup_line(lines, BytePos(18)), 1);
1424
1425         assert_eq!(lookup_line(lines, BytePos(28)), 2);
1426         assert_eq!(lookup_line(lines, BytePos(29)), 2);
1427     }
1428 }