26
26
#![ feature( core_io_borrowed_buf) ]
27
27
#![ feature( if_let_guard) ]
28
28
#![ feature( let_chains) ]
29
+ #![ feature( map_try_insert) ]
29
30
#![ feature( min_specialization) ]
30
31
#![ feature( negative_impls) ]
31
32
#![ feature( new_uninit) ]
@@ -74,6 +75,7 @@ pub mod fatal_error;
74
75
75
76
pub mod profiling;
76
77
78
+ use rustc_data_structures:: fx:: FxHashMap ;
77
79
use rustc_data_structures:: stable_hasher:: { Hash128 , Hash64 , HashStable , StableHasher } ;
78
80
use rustc_data_structures:: sync:: { FreezeLock , FreezeWriteGuard , Lock , Lrc } ;
79
81
@@ -100,6 +102,7 @@ mod tests;
100
102
pub struct SessionGlobals {
101
103
symbol_interner : symbol:: Interner ,
102
104
span_interner : Lock < span_encoding:: SpanInterner > ,
105
+ metavar_spans : Lock < FxHashMap < Span , Span > > ,
103
106
hygiene_data : Lock < hygiene:: HygieneData > ,
104
107
105
108
/// A reference to the source map in the `Session`. It's an `Option`
@@ -117,6 +120,7 @@ impl SessionGlobals {
117
120
SessionGlobals {
118
121
symbol_interner : symbol:: Interner :: fresh ( ) ,
119
122
span_interner : Lock :: new ( span_encoding:: SpanInterner :: default ( ) ) ,
123
+ metavar_spans : Default :: default ( ) ,
120
124
hygiene_data : Lock :: new ( hygiene:: HygieneData :: new ( edition) ) ,
121
125
source_map : Lock :: new ( None ) ,
122
126
}
@@ -170,6 +174,11 @@ pub fn create_default_session_globals_then<R>(f: impl FnOnce() -> R) -> R {
170
174
// deserialization.
171
175
scoped_tls:: scoped_thread_local!( static SESSION_GLOBALS : SessionGlobals ) ;
172
176
177
+ #[ inline]
178
+ pub fn with_metavar_spans < R > ( f : impl FnOnce ( & mut FxHashMap < Span , Span > ) -> R ) -> R {
179
+ with_session_globals ( |session_globals| f ( & mut session_globals. metavar_spans . lock ( ) ) )
180
+ }
181
+
173
182
// FIXME: We should use this enum or something like it to get rid of the
174
183
// use of magic `/rust/1.x/...` paths across the board.
175
184
#[ derive( Debug , Eq , PartialEq , Clone , Ord , PartialOrd , Decodable ) ]
@@ -825,29 +834,64 @@ impl Span {
825
834
)
826
835
}
827
836
837
+ /// Check if you can select metavar spans for the given spans to get matching contexts.
838
+ fn try_metavars ( a : SpanData , b : SpanData , a_orig : Span , b_orig : Span ) -> ( SpanData , SpanData ) {
839
+ let get = |mspans : & FxHashMap < _ , _ > , s| mspans. get ( & s) . copied ( ) ;
840
+ match with_metavar_spans ( |mspans| ( get ( mspans, a_orig) , get ( mspans, b_orig) ) ) {
841
+ ( None , None ) => { }
842
+ ( Some ( meta_a) , None ) => {
843
+ let meta_a = meta_a. data ( ) ;
844
+ if meta_a. ctxt == b. ctxt {
845
+ return ( meta_a, b) ;
846
+ }
847
+ }
848
+ ( None , Some ( meta_b) ) => {
849
+ let meta_b = meta_b. data ( ) ;
850
+ if a. ctxt == meta_b. ctxt {
851
+ return ( a, meta_b) ;
852
+ }
853
+ }
854
+ ( Some ( meta_a) , Some ( meta_b) ) => {
855
+ let meta_b = meta_b. data ( ) ;
856
+ if a. ctxt == meta_b. ctxt {
857
+ return ( a, meta_b) ;
858
+ }
859
+ let meta_a = meta_a. data ( ) ;
860
+ if meta_a. ctxt == b. ctxt {
861
+ return ( meta_a, b) ;
862
+ } else if meta_a. ctxt == meta_b. ctxt {
863
+ return ( meta_a, meta_b) ;
864
+ }
865
+ }
866
+ }
867
+
868
+ ( a, b)
869
+ }
870
+
828
871
/// Prepare two spans to a combine operation like `to` or `between`.
829
- /// FIXME: consider using declarative macro metavariable spans for the given spans if they are
830
- /// better suitable for combining (#119412).
831
872
fn prepare_to_combine (
832
873
a_orig : Span ,
833
874
b_orig : Span ,
834
875
) -> Result < ( SpanData , SpanData , Option < LocalDefId > ) , Span > {
835
876
let ( a, b) = ( a_orig. data ( ) , b_orig. data ( ) ) ;
877
+ if a. ctxt == b. ctxt {
878
+ return Ok ( ( a, b, if a. parent == b. parent { a. parent } else { None } ) ) ;
879
+ }
836
880
837
- if a. ctxt != b. ctxt {
838
- // Context mismatches usually happen when procedural macros combine spans copied from
839
- // the macro input with spans produced by the macro (`Span::*_site`).
840
- // In that case we consider the combined span to be produced by the macro and return
841
- // the original macro-produced span as the result.
842
- // Otherwise we just fall back to returning the first span.
843
- // Combining locations typically doesn't make sense in case of context mismatches.
844
- // `is_root` here is a fast path optimization.
845
- let a_is_callsite = a. ctxt . is_root ( ) || a. ctxt == b. span ( ) . source_callsite ( ) . ctxt ( ) ;
846
- return Err ( if a_is_callsite { b_orig } else { a_orig } ) ;
881
+ let ( a, b) = Span :: try_metavars ( a, b, a_orig, b_orig) ;
882
+ if a. ctxt == b. ctxt {
883
+ return Ok ( ( a, b, if a. parent == b. parent { a. parent } else { None } ) ) ;
847
884
}
848
885
849
- let parent = if a. parent == b. parent { a. parent } else { None } ;
850
- Ok ( ( a, b, parent) )
886
+ // Context mismatches usually happen when procedural macros combine spans copied from
887
+ // the macro input with spans produced by the macro (`Span::*_site`).
888
+ // In that case we consider the combined span to be produced by the macro and return
889
+ // the original macro-produced span as the result.
890
+ // Otherwise we just fall back to returning the first span.
891
+ // Combining locations typically doesn't make sense in case of context mismatches.
892
+ // `is_root` here is a fast path optimization.
893
+ let a_is_callsite = a. ctxt . is_root ( ) || a. ctxt == b. span ( ) . source_callsite ( ) . ctxt ( ) ;
894
+ Err ( if a_is_callsite { b_orig } else { a_orig } )
851
895
}
852
896
853
897
/// This span, but in a larger context, may switch to the metavariable span if suitable.
0 commit comments