@@ -826,6 +826,39 @@ impl Span {
826826 )
827827 }
828828
829+ /// Prepare two spans to a combine operation like `to` or `between`.
830+ /// FIXME: consider using declarative macro metavariable spans for the given spans if they are
831+ /// better suitable for combining (#119412).
832+ fn prepare_to_combine (
833+ a_orig : Span ,
834+ b_orig : Span ,
835+ ) -> Result < ( SpanData , SpanData , Option < LocalDefId > ) , Span > {
836+ let ( a, b) = ( a_orig. data ( ) , b_orig. data ( ) ) ;
837+
838+ if a. ctxt != b. ctxt {
839+ // Context mismatches usually happen when procedural macros combine spans copied from
840+ // the macro input with spans produced by the macro (`Span::*_site`).
841+ // In that case we consider the combined span to be produced by the macro and return
842+ // the original macro-produced span as the result.
843+ // Otherwise we just fall back to returning the first span.
844+ // Combining locations typically doesn't make sense in case of context mismatches.
845+ // `is_root` here is a fast path optimization.
846+ let a_is_callsite = a. ctxt . is_root ( ) || a. ctxt == b. span ( ) . source_callsite ( ) . ctxt ( ) ;
847+ return Err ( if a_is_callsite { b_orig } else { a_orig } ) ;
848+ }
849+
850+ let parent = if a. parent == b. parent { a. parent } else { None } ;
851+ Ok ( ( a, b, parent) )
852+ }
853+
854+ /// This span, but in a larger context, may switch to the metavariable span if suitable.
855+ pub fn with_neighbor ( self , neighbor : Span ) -> Span {
856+ match Span :: prepare_to_combine ( self , neighbor) {
857+ Ok ( ( this, ..) ) => Span :: new ( this. lo , this. hi , this. ctxt , this. parent ) ,
858+ Err ( _) => self ,
859+ }
860+ }
861+
829862 /// Returns a `Span` that would enclose both `self` and `end`.
830863 ///
831864 /// Note that this can also be used to extend the span "backwards":
@@ -837,26 +870,12 @@ impl Span {
837870 /// ^^^^^^^^^^^^^^^^^^^^
838871 /// ```
839872 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 ;
873+ match Span :: prepare_to_combine ( self , end) {
874+ Ok ( ( from, to, parent) ) => {
875+ Span :: new ( cmp:: min ( from. lo , to. lo ) , cmp:: max ( from. hi , to. hi ) , from. ctxt , parent)
850876 }
851- // Both spans fall within a macro.
852- // FIXME(estebank): check if it is the *same* macro.
877+ Err ( fallback) => fallback,
853878 }
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- )
860879 }
861880
862881 /// Returns a `Span` between the end of `self` to the beginning of `end`.
@@ -867,14 +886,12 @@ impl Span {
867886 /// ^^^^^^^^^^^^^
868887 /// ```
869888 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- )
889+ match Span :: prepare_to_combine ( self , end) {
890+ Ok ( ( from, to, parent) ) => {
891+ Span :: new ( cmp:: min ( from. hi , to. hi ) , cmp:: max ( from. lo , to. lo ) , from. ctxt , parent)
892+ }
893+ Err ( fallback) => fallback,
894+ }
878895 }
879896
880897 /// Returns a `Span` from the beginning of `self` until the beginning of `end`.
@@ -885,31 +902,12 @@ impl Span {
885902 /// ^^^^^^^^^^^^^^^^^
886903 /// ```
887904 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 ;
905+ match Span :: prepare_to_combine ( self , end) {
906+ Ok ( ( from, to, parent) ) => {
907+ Span :: new ( cmp:: min ( from. lo , to. lo ) , cmp:: max ( from. lo , to. lo ) , from. ctxt , parent)
903908 }
904- // Both spans fall within a macro.
905- // FIXME(estebank): check if it is the *same* macro.
909+ Err ( fallback) => fallback,
906910 }
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- )
913911 }
914912
915913 pub fn from_inner ( self , inner : InnerSpan ) -> Span {
0 commit comments