@@ -829,6 +829,39 @@ impl Span {
829829 )
830830 }
831831
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. 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+
832865 /// Returns a `Span` that would enclose both `self` and `end`.
833866 ///
834867 /// Note that this can also be used to extend the span "backwards":
@@ -840,26 +873,12 @@ impl Span {
840873 /// ^^^^^^^^^^^^^^^^^^^^
841874 /// ```
842875 pub fn to ( self , end : Span ) -> Span {
843- let span_data = self . data ( ) ;
844- let end_data = end. data ( ) ;
845- // FIXME(jseyfried): `self.ctxt` should always equal `end.ctxt` here (cf. issue #23480).
846- // Return the macro span on its own to avoid weird diagnostic output. It is preferable to
847- // have an incomplete span than a completely nonsensical one.
848- if span_data. ctxt != end_data. ctxt {
849- if span_data. ctxt . is_root ( ) {
850- return end;
851- } else if end_data. ctxt . is_root ( ) {
852- 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)
853879 }
854- // Both spans fall within a macro.
855- // FIXME(estebank): check if it is the *same* macro.
880+ Err ( fallback) => fallback,
856881 }
857- Span :: new (
858- cmp:: min ( span_data. lo , end_data. lo ) ,
859- cmp:: max ( span_data. hi , end_data. hi ) ,
860- if span_data. ctxt . is_root ( ) { end_data. ctxt } else { span_data. ctxt } ,
861- if span_data. parent == end_data. parent { span_data. parent } else { None } ,
862- )
863882 }
864883
865884 /// Returns a `Span` between the end of `self` to the beginning of `end`.
@@ -870,14 +889,12 @@ impl Span {
870889 /// ^^^^^^^^^^^^^
871890 /// ```
872891 pub fn between ( self , end : Span ) -> Span {
873- let span = self . data ( ) ;
874- let end = end. data ( ) ;
875- Span :: new (
876- span. hi ,
877- end. lo ,
878- if end. ctxt . is_root ( ) { end. ctxt } else { span. ctxt } ,
879- if span. parent == end. parent { span. parent } else { None } ,
880- )
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+ }
881898 }
882899
883900 /// Returns a `Span` from the beginning of `self` until the beginning of `end`.
@@ -888,31 +905,12 @@ impl Span {
888905 /// ^^^^^^^^^^^^^^^^^
889906 /// ```
890907 pub fn until ( self , end : Span ) -> Span {
891- // Most of this function's body is copied from `to`.
892- // We can't just do `self.to(end.shrink_to_lo())`,
893- // because to also does some magic where it uses min/max so
894- // it can handle overlapping spans. Some advanced mis-use of
895- // `until` with different ctxts makes this visible.
896- let span_data = self . data ( ) ;
897- let end_data = end. data ( ) ;
898- // FIXME(jseyfried): `self.ctxt` should always equal `end.ctxt` here (cf. issue #23480).
899- // Return the macro span on its own to avoid weird diagnostic output. It is preferable to
900- // have an incomplete span than a completely nonsensical one.
901- if span_data. ctxt != end_data. ctxt {
902- if span_data. ctxt . is_root ( ) {
903- return end;
904- } else if end_data. ctxt . is_root ( ) {
905- 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)
906911 }
907- // Both spans fall within a macro.
908- // FIXME(estebank): check if it is the *same* macro.
912+ Err ( fallback) => fallback,
909913 }
910- Span :: new (
911- span_data. lo ,
912- end_data. lo ,
913- if end_data. ctxt . is_root ( ) { end_data. ctxt } else { span_data. ctxt } ,
914- if span_data. parent == end_data. parent { span_data. parent } else { None } ,
915- )
916914 }
917915
918916 pub fn from_inner ( self , inner : InnerSpan ) -> Span {
0 commit comments