diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index f6ae748560750..ac7c959302562 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -1173,17 +1173,7 @@ impl Span { } } - /// Returns a `Span` that would enclose both `self` and `end`. - /// - /// Note that this can also be used to extend the span "backwards": - /// `start.to(end)` and `end.to(start)` return the same `Span`. - /// - /// ```text - /// ____ ___ - /// self lorem ipsum end - /// ^^^^^^^^^^^^^^^^^^^^ - /// ``` - pub fn to(self, end: Span) -> Span { + fn to_general(self, end: Span) -> Span { match Span::prepare_to_combine(self, end) { Ok((from, to, parent)) => { Span::new(cmp::min(from.lo, to.lo), cmp::max(from.hi, to.hi), from.ctxt, parent) diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs index 64280d5ce4b5e..d6a7653d1c5f7 100644 --- a/compiler/rustc_span/src/span_encoding.rs +++ b/compiler/rustc_span/src/span_encoding.rs @@ -281,6 +281,36 @@ impl Span { } } + /// Returns a `Span` that would enclose both `self` and `end`. + /// + /// Note that this can also be used to extend the span "backwards": + /// `start.to(end)` and `end.to(start)` return the same `Span`. + /// + /// ```text + /// ____ ___ + /// self lorem ipsum end + /// ^^^^^^^^^^^^^^^^^^^^ + /// ``` + #[inline] + pub fn to(self, end: Span) -> Span { + // Inline-context spans have no parent dependency to record. + if u32::from(self.len_with_tag_or_marker) <= MAX_LEN + && u32::from(end.len_with_tag_or_marker) <= MAX_LEN + && self.ctxt_or_parent_or_marker == end.ctxt_or_parent_or_marker + { + let lo = self.lo_or_index.min(end.lo_or_index); + let hi = self + .lo_or_index + .debug_strict_add(u32::from(self.len_with_tag_or_marker)) + .max(end.lo_or_index.debug_strict_add(u32::from(end.len_with_tag_or_marker))); + let len = hi - lo; + if len <= MAX_LEN { + return InlineCtxt::span(lo, len as u16, self.ctxt_or_parent_or_marker); + } + } + self.to_general(end) + } + #[inline] pub fn data(self) -> SpanData { let data = self.data_untracked(); diff --git a/compiler/rustc_span/src/tests.rs b/compiler/rustc_span/src/tests.rs index 64c40e6116250..1ca87b6a88700 100644 --- a/compiler/rustc_span/src/tests.rs +++ b/compiler/rustc_span/src/tests.rs @@ -1,5 +1,40 @@ use super::*; +#[test] +fn test_span_union_encoding_boundaries() { + create_default_session_globals_then(|| { + let ranges = [ + (0, 0), + (3, 10), + (8, 14), + (40_000, 40_001), + (1, 32_766), + (1, 32_767), + (1, 32_768), + (u32::MAX - 10, u32::MAX), + ]; + for ctxt in [0, 7, 65_534, 65_535, 70_000] { + let ctxt = SyntaxContext::from_u32(ctxt); + for parent in [None, Some(crate::def_id::CRATE_DEF_ID)] { + for (lo_a, hi_a) in ranges { + for (lo_b, hi_b) in ranges { + let a = Span::new(BytePos(lo_a), BytePos(hi_a), ctxt, parent); + let b = Span::new(BytePos(lo_b), BytePos(hi_b), ctxt, parent); + let expected = Span::new( + BytePos(lo_a.min(lo_b)), + BytePos(hi_a.max(hi_b)), + ctxt, + parent, + ); + assert_eq!(a.to(b), expected); + assert_eq!(b.to(a), expected); + } + } + } + } + }); +} + #[test] fn test_lookup_line() { let source = "abcdefghijklm\nabcdefghij\n...".to_owned();