@@ -502,6 +502,9 @@ impl SpanData {
502
502
pub fn contains ( self , other : Self ) -> bool {
503
503
self . lo <= other. lo && other. hi <= self . hi
504
504
}
505
+ pub fn to_span ( & self ) -> Span {
506
+ Span :: new ( self . lo , self . hi , self . ctxt , self . parent )
507
+ }
505
508
}
506
509
507
510
// The interner is pointed to by a thread local value which is only set on the main thread
@@ -826,6 +829,39 @@ impl Span {
826
829
)
827
830
}
828
831
832
+ /// Prepare two spans to a combine operation like `to` or `between`.
833
+ /// FIXME: consider using declarative macro metavariable spans for the given spans if they are
834
+ /// better suitable for combining (#119412).
835
+ fn prepare_to_combine (
836
+ a_orig : Span ,
837
+ b_orig : Span ,
838
+ ) -> Result < ( SpanData , SpanData , Option < LocalDefId > ) , Span > {
839
+ let ( a, b) = ( a_orig. data ( ) , b_orig. data ( ) ) ;
840
+
841
+ if a. ctxt != b. ctxt {
842
+ // Context mismatches usually happen when procedural macros combine spans copied from
843
+ // the macro input with spans produced by the macro (`Span::*_site`).
844
+ // In that case we consider the combined span to be produced by the macro and return
845
+ // the original macro-produced span as the result.
846
+ // Otherwise we just fall back to returning the first span.
847
+ // Combining locations typically doesn't make sense in case of context mismatches.
848
+ // `is_root` here is a fast path optimization.
849
+ let a_is_callsite = a. ctxt . is_root ( ) || a. ctxt == b. to_span ( ) . source_callsite ( ) . ctxt ( ) ;
850
+ return Err ( if a_is_callsite { b_orig } else { a_orig } ) ;
851
+ }
852
+
853
+ let parent = if a. parent == b. parent { a. parent } else { None } ;
854
+ Ok ( ( a, b, parent) )
855
+ }
856
+
857
+ /// This span, but in a larger context, may switch to the metavariable span if suitable.
858
+ pub fn with_neighbor ( self , neighbor : Span ) -> Span {
859
+ match Span :: prepare_to_combine ( self , neighbor) {
860
+ Ok ( ( this, ..) ) => Span :: new ( this. lo , this. hi , this. ctxt , this. parent ) ,
861
+ Err ( _) => self ,
862
+ }
863
+ }
864
+
829
865
/// Returns a `Span` that would enclose both `self` and `end`.
830
866
///
831
867
/// Note that this can also be used to extend the span "backwards":
@@ -837,26 +873,12 @@ impl Span {
837
873
/// ^^^^^^^^^^^^^^^^^^^^
838
874
/// ```
839
875
pub fn to ( self , end : Span ) -> Span {
840
- let span_data = self . data ( ) ;
841
- let end_data = end. data ( ) ;
842
- // FIXME(jseyfried): `self.ctxt` should always equal `end.ctxt` here (cf. issue #23480).
843
- // Return the macro span on its own to avoid weird diagnostic output. It is preferable to
844
- // have an incomplete span than a completely nonsensical one.
845
- if span_data. ctxt != end_data. ctxt {
846
- if span_data. ctxt . is_root ( ) {
847
- return end;
848
- } else if end_data. ctxt . is_root ( ) {
849
- return self ;
876
+ match Span :: prepare_to_combine ( self , end) {
877
+ Ok ( ( from, to, parent) ) => {
878
+ Span :: new ( cmp:: min ( from. lo , to. lo ) , cmp:: max ( from. hi , to. hi ) , from. ctxt , parent)
850
879
}
851
- // Both spans fall within a macro.
852
- // FIXME(estebank): check if it is the *same* macro.
880
+ Err ( fallback) => fallback,
853
881
}
854
- Span :: new (
855
- cmp:: min ( span_data. lo , end_data. lo ) ,
856
- cmp:: max ( span_data. hi , end_data. hi ) ,
857
- if span_data. ctxt . is_root ( ) { end_data. ctxt } else { span_data. ctxt } ,
858
- if span_data. parent == end_data. parent { span_data. parent } else { None } ,
859
- )
860
882
}
861
883
862
884
/// Returns a `Span` between the end of `self` to the beginning of `end`.
@@ -867,14 +889,12 @@ impl Span {
867
889
/// ^^^^^^^^^^^^^
868
890
/// ```
869
891
pub fn between ( self , end : Span ) -> Span {
870
- let span = self . data ( ) ;
871
- let end = end. data ( ) ;
872
- Span :: new (
873
- span. hi ,
874
- end. lo ,
875
- if end. ctxt . is_root ( ) { end. ctxt } else { span. ctxt } ,
876
- if span. parent == end. parent { span. parent } else { None } ,
877
- )
892
+ match Span :: prepare_to_combine ( self , end) {
893
+ Ok ( ( from, to, parent) ) => {
894
+ Span :: new ( cmp:: min ( from. hi , to. hi ) , cmp:: max ( from. lo , to. lo ) , from. ctxt , parent)
895
+ }
896
+ Err ( fallback) => fallback,
897
+ }
878
898
}
879
899
880
900
/// Returns a `Span` from the beginning of `self` until the beginning of `end`.
@@ -885,31 +905,12 @@ impl Span {
885
905
/// ^^^^^^^^^^^^^^^^^
886
906
/// ```
887
907
pub fn until ( self , end : Span ) -> Span {
888
- // Most of this function's body is copied from `to`.
889
- // We can't just do `self.to(end.shrink_to_lo())`,
890
- // because to also does some magic where it uses min/max so
891
- // it can handle overlapping spans. Some advanced mis-use of
892
- // `until` with different ctxts makes this visible.
893
- let span_data = self . data ( ) ;
894
- let end_data = end. data ( ) ;
895
- // FIXME(jseyfried): `self.ctxt` should always equal `end.ctxt` here (cf. issue #23480).
896
- // Return the macro span on its own to avoid weird diagnostic output. It is preferable to
897
- // have an incomplete span than a completely nonsensical one.
898
- if span_data. ctxt != end_data. ctxt {
899
- if span_data. ctxt . is_root ( ) {
900
- return end;
901
- } else if end_data. ctxt . is_root ( ) {
902
- return self ;
908
+ match Span :: prepare_to_combine ( self , end) {
909
+ Ok ( ( from, to, parent) ) => {
910
+ Span :: new ( cmp:: min ( from. lo , to. lo ) , cmp:: max ( from. lo , to. lo ) , from. ctxt , parent)
903
911
}
904
- // Both spans fall within a macro.
905
- // FIXME(estebank): check if it is the *same* macro.
912
+ Err ( fallback) => fallback,
906
913
}
907
- Span :: new (
908
- span_data. lo ,
909
- end_data. lo ,
910
- if end_data. ctxt . is_root ( ) { end_data. ctxt } else { span_data. ctxt } ,
911
- if span_data. parent == end_data. parent { span_data. parent } else { None } ,
912
- )
913
914
}
914
915
915
916
pub fn from_inner ( self , inner : InnerSpan ) -> Span {
0 commit comments