@@ -13,7 +13,7 @@ use rustc_errors::DiagnosticBuilder;
13
13
use rustc_errors:: { pluralize, PResult } ;
14
14
use rustc_span:: hygiene:: { LocalExpnId , Transparency } ;
15
15
use rustc_span:: symbol:: { sym, Ident , MacroRulesNormalizedIdent } ;
16
- use rustc_span:: Span ;
16
+ use rustc_span:: { try_insert_metavar_span , Span } ;
17
17
18
18
use smallvec:: { smallvec, SmallVec } ;
19
19
use std:: mem;
@@ -245,6 +245,7 @@ pub(super) fn transcribe<'a>(
245
245
MatchedTokenTree ( tt) => {
246
246
// `tt`s are emitted into the output stream directly as "raw tokens",
247
247
// without wrapping them into groups.
248
+ marker. visit_span ( & mut sp) ;
248
249
result. push ( maybe_use_metavar_location ( cx, & stack, sp, tt) ) ;
249
250
}
250
251
MatchedNonterminal ( nt) => {
@@ -310,6 +311,15 @@ pub(super) fn transcribe<'a>(
310
311
}
311
312
}
312
313
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
+ ///
313
323
/// Usually metavariables `$var` produce interpolated tokens, which have an additional place for
314
324
/// keeping both the original span and the metavariable span. For `tt` metavariables that's not the
315
325
/// 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>(
329
339
/// These are typically used for passing larger amounts of code, and tokens in that code usually
330
340
/// combine with each other and not with tokens outside of the sequence.
331
341
/// - 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.
336
342
fn maybe_use_metavar_location (
337
343
cx : & ExtCtxt < ' _ > ,
338
344
stack : & [ Frame < ' _ > ] ,
339
345
metavar_span : Span ,
340
346
orig_tt : & TokenTree ,
341
347
) -> 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) {
352
368
return orig_tt. clone ( ) ;
353
369
}
354
370
371
+ // Setting metavar spans for the heuristic spans gives better opportunities for combining them
372
+ // with neighboring spans even despite their different syntactic contexts.
355
373
match orig_tt {
356
374
TokenTree :: Token ( Token { kind, span } , spacing) => {
357
375
let span = metavar_span. with_ctxt ( span. ctxt ( ) ) ;
376
+ let _ = try_insert_metavar_span ( span, metavar_span) ;
358
377
TokenTree :: Token ( Token { kind : kind. clone ( ) , span } , * spacing)
359
378
}
360
379
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) ;
363
384
let dspan = DelimSpan :: from_pair ( open, close) ;
364
385
TokenTree :: Delimited ( dspan, * dspacing, * delimiter, tts. clone ( ) )
365
386
}
0 commit comments