@@ -13,7 +13,7 @@ use rustc_errors::DiagnosticBuilder;
1313use rustc_errors:: { pluralize, PResult } ;
1414use rustc_span:: hygiene:: { LocalExpnId , Transparency } ;
1515use rustc_span:: symbol:: { sym, Ident , MacroRulesNormalizedIdent } ;
16- use rustc_span:: Span ;
16+ use rustc_span:: { try_insert_metavar_span , Span } ;
1717
1818use smallvec:: { smallvec, SmallVec } ;
1919use std:: mem;
@@ -245,6 +245,7 @@ pub(super) fn transcribe<'a>(
245245 MatchedTokenTree ( tt) => {
246246 // `tt`s are emitted into the output stream directly as "raw tokens",
247247 // without wrapping them into groups.
248+ marker. visit_span ( & mut sp) ;
248249 result. push ( maybe_use_metavar_location ( cx, & stack, sp, tt) ) ;
249250 }
250251 MatchedNonterminal ( nt) => {
@@ -310,6 +311,15 @@ pub(super) fn transcribe<'a>(
310311 }
311312}
312313
314+ /// Store the metavariable span for this original span into a side table.
315+ /// FIXME: Try to put the metavariable span into `SpanData` instead of a side table (#118517).
316+ /// An optimal encoding for inlined spans will need to be selected to minimize regressions.
317+ /// The side table approach is relatively good, but not perfect due to collisions.
318+ /// The old heuristic below is used to improve spans in case of collisions, but diagnostics are
319+ /// still degraded sometimes in those cases.
320+ ///
321+ /// The old heuristic:
322+ ///
313323/// Usually metavariables `$var` produce interpolated tokens, which have an additional place for
314324/// keeping both the original span and the metavariable span. For `tt` metavariables that's not the
315325/// case however, and there's no place for keeping a second span. So we try to give the single
@@ -329,37 +339,48 @@ pub(super) fn transcribe<'a>(
329339/// These are typically used for passing larger amounts of code, and tokens in that code usually
330340/// combine with each other and not with tokens outside of the sequence.
331341/// - The metavariable span comes from a different crate, then we prefer the more local span.
332- ///
333- /// FIXME: Find a way to keep both original and metavariable spans for all tokens without
334- /// regressing compilation time too much. Several experiments for adding such spans were made in
335- /// the past (PR #95580, #118517, #118671) and all showed some regressions.
336342fn maybe_use_metavar_location (
337343 cx : & ExtCtxt < ' _ > ,
338344 stack : & [ Frame < ' _ > ] ,
339345 metavar_span : Span ,
340346 orig_tt : & TokenTree ,
341347) -> TokenTree {
342- let undelimited_seq = matches ! (
343- stack. last( ) ,
344- Some ( Frame :: Sequence {
345- tts: [ _] ,
346- sep: None ,
347- kleene_op: KleeneOp :: ZeroOrMore | KleeneOp :: OneOrMore ,
348- ..
349- } )
350- ) ;
351- if undelimited_seq || cx. source_map ( ) . is_imported ( metavar_span) {
348+ let no_collision = match orig_tt {
349+ TokenTree :: Token ( token, ..) => try_insert_metavar_span ( token. span , metavar_span) ,
350+ TokenTree :: Delimited ( dspan, ..) => {
351+ try_insert_metavar_span ( dspan. open , metavar_span)
352+ && try_insert_metavar_span ( dspan. close , metavar_span)
353+ && try_insert_metavar_span ( dspan. entire ( ) , metavar_span)
354+ }
355+ } ;
356+ let undelimited_seq = || {
357+ matches ! (
358+ stack. last( ) ,
359+ Some ( Frame :: Sequence {
360+ tts: [ _] ,
361+ sep: None ,
362+ kleene_op: KleeneOp :: ZeroOrMore | KleeneOp :: OneOrMore ,
363+ ..
364+ } )
365+ )
366+ } ;
367+ if no_collision || undelimited_seq ( ) || cx. source_map ( ) . is_imported ( metavar_span) {
352368 return orig_tt. clone ( ) ;
353369 }
354370
371+ // Setting metavar spans for the heuristic spans gives better opportunities for combining them
372+ // with neighboring spans even despite their different syntactic contexts.
355373 match orig_tt {
356374 TokenTree :: Token ( Token { kind, span } , spacing) => {
357375 let span = metavar_span. with_ctxt ( span. ctxt ( ) ) ;
376+ let _ = try_insert_metavar_span ( span, metavar_span) ;
358377 TokenTree :: Token ( Token { kind : kind. clone ( ) , span } , * spacing)
359378 }
360379 TokenTree :: Delimited ( dspan, dspacing, delimiter, tts) => {
361- let open = metavar_span. shrink_to_lo ( ) . with_ctxt ( dspan. open . ctxt ( ) ) ;
362- let close = metavar_span. shrink_to_hi ( ) . with_ctxt ( dspan. close . ctxt ( ) ) ;
380+ let open = metavar_span. with_ctxt ( dspan. open . ctxt ( ) ) ;
381+ let close = metavar_span. with_ctxt ( dspan. close . ctxt ( ) ) ;
382+ let _ = try_insert_metavar_span ( open, metavar_span) ;
383+ let _ = try_insert_metavar_span ( close, metavar_span) ;
363384 let dspan = DelimSpan :: from_pair ( open, close) ;
364385 TokenTree :: Delimited ( dspan, * dspacing, * delimiter, tts. clone ( ) )
365386 }
0 commit comments