Skip to content

Commit d7f855c

Browse files
committed
WIP
1 parent fcfe05a commit d7f855c

File tree

63 files changed

+512
-353
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+512
-353
lines changed

compiler/rustc_ast/src/ast_traits.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ impl HasTokens for Nonterminal {
240240
Nonterminal::NtPath(path) => path.tokens(),
241241
Nonterminal::NtVis(vis) => vis.tokens(),
242242
Nonterminal::NtBlock(block) => block.tokens(),
243-
Nonterminal::NtIdent(..) | Nonterminal::NtLifetime(..) => None,
243+
Nonterminal::NtLifetime(..) => None,
244244
}
245245
}
246246
fn tokens_mut(&mut self) -> Option<&mut Option<LazyAttrTokenStream>> {
@@ -254,7 +254,7 @@ impl HasTokens for Nonterminal {
254254
Nonterminal::NtPath(path) => path.tokens_mut(),
255255
Nonterminal::NtVis(vis) => vis.tokens_mut(),
256256
Nonterminal::NtBlock(block) => block.tokens_mut(),
257-
Nonterminal::NtIdent(..) | Nonterminal::NtLifetime(..) => None,
257+
Nonterminal::NtLifetime(..) => None,
258258
}
259259
}
260260
}

compiler/rustc_ast/src/mut_visit.rs

-1
Original file line numberDiff line numberDiff line change
@@ -816,7 +816,6 @@ pub fn visit_nonterminal<T: MutVisitor>(nt: &mut token::Nonterminal, vis: &mut T
816816
token::NtPat(pat) => vis.visit_pat(pat),
817817
token::NtExpr(expr) => vis.visit_expr(expr),
818818
token::NtTy(ty) => vis.visit_ty(ty),
819-
token::NtIdent(ident, _is_raw) => vis.visit_ident(ident),
820819
token::NtLifetime(ident) => vis.visit_ident(ident),
821820
token::NtLiteral(expr) => vis.visit_expr(expr),
822821
token::NtMeta(item) => {

compiler/rustc_ast/src/token.rs

+1-17
Original file line numberDiff line numberDiff line change
@@ -295,9 +295,6 @@ pub enum TokenKind {
295295
Literal(Lit),
296296

297297
/// Identifier token.
298-
/// Do not forget about `NtIdent` when you want to match on identifiers.
299-
/// It's recommended to use `Token::(ident,uninterpolate,uninterpolated_span)` to
300-
/// treat regular and interpolated identifiers in the same way.
301298
Ident(Symbol, /* is_raw */ bool),
302299
/// Lifetime identifier token.
303300
/// Do not forget about `NtLifetime` when you want to match on lifetime identifiers.
@@ -590,9 +587,6 @@ impl Token {
590587
pub fn uninterpolate(&self) -> Cow<'_, Token> {
591588
match &self.kind {
592589
Interpolated(nt) => match &nt.0 {
593-
NtIdent(ident, is_raw) => {
594-
Cow::Owned(Token::new(Ident(ident.name, *is_raw), ident.span))
595-
}
596590
NtLifetime(ident) => Cow::Owned(Token::new(Lifetime(ident.name), ident.span)),
597591
_ => Cow::Borrowed(self),
598592
},
@@ -606,10 +600,6 @@ impl Token {
606600
// We avoid using `Token::uninterpolate` here because it's slow.
607601
match &self.kind {
608602
&Ident(name, is_raw) => Some((Ident::new(name, self.span), is_raw)),
609-
Interpolated(nt) => match &nt.0 {
610-
NtIdent(ident, is_raw) => Some((*ident, *is_raw)),
611-
_ => None,
612-
},
613603
_ => None,
614604
}
615605
}
@@ -836,7 +826,6 @@ pub enum Nonterminal {
836826
NtPat(P<ast::Pat>),
837827
NtExpr(P<ast::Expr>),
838828
NtTy(P<ast::Ty>),
839-
NtIdent(Ident, /* is_raw */ bool),
840829
NtLifetime(Ident),
841830
NtLiteral(P<ast::Expr>),
842831
/// Stuff inside brackets for attributes
@@ -932,7 +921,7 @@ impl Nonterminal {
932921
NtPat(pat) => pat.span,
933922
NtExpr(expr) | NtLiteral(expr) => expr.span,
934923
NtTy(ty) => ty.span,
935-
NtIdent(ident, _) | NtLifetime(ident) => ident.span,
924+
NtLifetime(ident) => ident.span,
936925
NtMeta(attr_item) => attr_item.span(),
937926
NtPath(path) => path.span,
938927
NtVis(vis) => vis.span,
@@ -948,7 +937,6 @@ impl Nonterminal {
948937
NtExpr(..) => "expression",
949938
NtLiteral(..) => "literal",
950939
NtTy(..) => "type",
951-
NtIdent(..) => "identifier",
952940
NtLifetime(..) => "lifetime",
953941
NtMeta(..) => "attribute",
954942
NtPath(..) => "path",
@@ -960,9 +948,6 @@ impl Nonterminal {
960948
impl PartialEq for Nonterminal {
961949
fn eq(&self, rhs: &Self) -> bool {
962950
match (self, rhs) {
963-
(NtIdent(ident_lhs, is_raw_lhs), NtIdent(ident_rhs, is_raw_rhs)) => {
964-
ident_lhs == ident_rhs && is_raw_lhs == is_raw_rhs
965-
}
966951
(NtLifetime(ident_lhs), NtLifetime(ident_rhs)) => ident_lhs == ident_rhs,
967952
// FIXME: Assume that all "complex" nonterminal are not equal, we can't compare them
968953
// correctly based on data from AST. This will prevent them from matching each other
@@ -982,7 +967,6 @@ impl fmt::Debug for Nonterminal {
982967
NtPat(..) => f.pad("NtPat(..)"),
983968
NtExpr(..) => f.pad("NtExpr(..)"),
984969
NtTy(..) => f.pad("NtTy(..)"),
985-
NtIdent(..) => f.pad("NtIdent(..)"),
986970
NtLiteral(..) => f.pad("NtLiteral(..)"),
987971
NtMeta(..) => f.pad("NtMeta(..)"),
988972
NtPath(..) => f.pad("NtPath(..)"),

compiler/rustc_ast/src/tokenstream.rs

+1-28
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use rustc_span::{sym, Span, Symbol, DUMMY_SP};
2626
use smallvec::{smallvec, SmallVec};
2727

2828
use std::borrow::Cow;
29-
use std::{cmp, fmt, iter, mem};
29+
use std::{cmp, fmt, iter};
3030

3131
/// When the main Rust parser encounters a syntax-extension invocation, it
3232
/// parses the arguments to the invocation as a token tree. This is a very
@@ -81,14 +81,6 @@ impl TokenTree {
8181
}
8282
}
8383

84-
/// Modify the `TokenTree`'s span in-place.
85-
pub fn set_span(&mut self, span: Span) {
86-
match self {
87-
TokenTree::Token(token, _) => token.span = span,
88-
TokenTree::Delimited(dspan, ..) => *dspan = DelimSpan::from_single(span),
89-
}
90-
}
91-
9284
/// Create a `TokenTree::Token` with alone spacing.
9385
pub fn token_alone(kind: TokenKind, span: Span) -> TokenTree {
9486
TokenTree::Token(Token::new(kind, span), Spacing::Alone)
@@ -461,19 +453,6 @@ impl TokenStream {
461453
t1.next().is_none() && t2.next().is_none()
462454
}
463455

464-
/// Applies the supplied function to each `TokenTree` and its index in `self`, returning a new `TokenStream`
465-
///
466-
/// It is equivalent to `TokenStream::new(self.trees().cloned().enumerate().map(|(i, tt)| f(i, tt)).collect())`.
467-
pub fn map_enumerated_owned(
468-
mut self,
469-
mut f: impl FnMut(usize, TokenTree) -> TokenTree,
470-
) -> TokenStream {
471-
let owned = Lrc::make_mut(&mut self.0); // clone if necessary
472-
// rely on vec's in-place optimizations to avoid another allocation
473-
*owned = mem::take(owned).into_iter().enumerate().map(|(i, tree)| f(i, tree)).collect();
474-
self
475-
}
476-
477456
/// Create a token stream containing a single token with alone spacing. The
478457
/// spacing used for the final token in a constructed stream doesn't matter
479458
/// because it's never used. In practice we arbitrarily use
@@ -499,9 +478,6 @@ impl TokenStream {
499478

500479
pub fn from_nonterminal_ast(nt: &Nonterminal) -> TokenStream {
501480
match nt {
502-
Nonterminal::NtIdent(ident, is_raw) => {
503-
TokenStream::token_alone(token::Ident(ident.name, *is_raw), ident.span)
504-
}
505481
Nonterminal::NtLifetime(ident) => {
506482
TokenStream::token_alone(token::Lifetime(ident.name), ident.span)
507483
}
@@ -523,9 +499,6 @@ impl TokenStream {
523499

524500
fn flatten_token(token: &Token, spacing: Spacing) -> TokenTree {
525501
match &token.kind {
526-
token::Interpolated(nt) if let token::NtIdent(ident, is_raw) = nt.0 => {
527-
TokenTree::Token(Token::new(token::Ident(ident.name, is_raw), ident.span), spacing)
528-
}
529502
token::Interpolated(nt) => TokenTree::Delimited(
530503
DelimSpan::from_single(token.span),
531504
DelimSpacing::new(Spacing::JointHidden, spacing),

compiler/rustc_ast_pretty/src/pprust/state.rs

-1
Original file line numberDiff line numberDiff line change
@@ -715,7 +715,6 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
715715
token::NtBlock(e) => self.block_to_string(e),
716716
token::NtStmt(e) => self.stmt_to_string(e),
717717
token::NtPat(e) => self.pat_to_string(e),
718-
token::NtIdent(e, is_raw) => IdentPrinter::for_ast_ident(*e, *is_raw).to_string(),
719718
token::NtLifetime(e) => e.to_string(),
720719
token::NtLiteral(e) => self.expr_to_string(e),
721720
token::NtVis(e) => self.vis_to_string(e),

compiler/rustc_expand/src/mbe/macro_rules.rs

+2-33
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::mbe::transcribe::transcribe;
1010

1111
use rustc_ast as ast;
1212
use rustc_ast::token::{self, Delimiter, NonterminalKind, Token, TokenKind, TokenKind::*};
13-
use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree};
13+
use rustc_ast::tokenstream::{DelimSpan, TokenStream};
1414
use rustc_ast::{NodeId, DUMMY_NODE_ID};
1515
use rustc_ast_pretty::pprust;
1616
use rustc_attr::{self as attr, TransparencyError};
@@ -213,45 +213,14 @@ fn expand_macro<'cx>(
213213
let arm_span = rhses[i].span();
214214

215215
// rhs has holes ( `$id` and `$(...)` that need filled)
216-
let mut tts = match transcribe(cx, &named_matches, rhs, rhs_span, transparency) {
216+
let tts = match transcribe(cx, &named_matches, rhs, rhs_span, transparency) {
217217
Ok(tts) => tts,
218218
Err(mut err) => {
219219
err.emit();
220220
return DummyResult::any(arm_span);
221221
}
222222
};
223223

224-
// Replace all the tokens for the corresponding positions in the macro, to maintain
225-
// proper positions in error reporting, while maintaining the macro_backtrace.
226-
if tts.len() == rhs.tts.len() {
227-
tts = tts.map_enumerated_owned(|i, mut tt| {
228-
let rhs_tt = &rhs.tts[i];
229-
let ctxt = tt.span().ctxt();
230-
match (&mut tt, rhs_tt) {
231-
// preserve the delim spans if able
232-
(
233-
TokenTree::Delimited(target_sp, ..),
234-
mbe::TokenTree::Delimited(source_sp, ..),
235-
) => {
236-
target_sp.open = source_sp.open.with_ctxt(ctxt);
237-
target_sp.close = source_sp.close.with_ctxt(ctxt);
238-
}
239-
(
240-
TokenTree::Delimited(target_sp, ..),
241-
mbe::TokenTree::MetaVar(source_sp, ..),
242-
) => {
243-
target_sp.open = source_sp.with_ctxt(ctxt);
244-
target_sp.close = source_sp.with_ctxt(ctxt).shrink_to_hi();
245-
}
246-
_ => {
247-
let sp = rhs_tt.span().with_ctxt(ctxt);
248-
tt.set_span(sp);
249-
}
250-
}
251-
tt
252-
});
253-
}
254-
255224
if cx.trace_macros() {
256225
let msg = format!("to `{}`", pprust::tts_to_string(&tts));
257226
trace_macros_note(&mut cx.expansions, sp, msg);

compiler/rustc_expand/src/mbe/transcribe.rs

+83-4
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::errors::{
44
NoSyntaxVarsExprRepeat, VarStillRepeating,
55
};
66
use crate::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, MatchedTokenTree, NamedMatch};
7-
use crate::mbe::{self, MetaVarExpr};
7+
use crate::mbe::{self, KleeneOp, MetaVarExpr};
88
use rustc_ast::mut_visit::{self, MutVisitor};
99
use rustc_ast::token::{self, Delimiter, Token, TokenKind};
1010
use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree};
@@ -13,7 +13,7 @@ use rustc_errors::DiagnosticBuilder;
1313
use rustc_errors::{pluralize, PResult};
1414
use rustc_span::hygiene::{LocalExpnId, Transparency};
1515
use rustc_span::symbol::{sym, Ident, MacroRulesNormalizedIdent};
16-
use rustc_span::Span;
16+
use rustc_span::{try_insert_metavar_span, Span};
1717

1818
use smallvec::{smallvec, SmallVec};
1919
use std::mem;
@@ -42,6 +42,7 @@ enum Frame<'a> {
4242
tts: &'a [mbe::TokenTree],
4343
idx: usize,
4444
sep: Option<Token>,
45+
kleene_op: KleeneOp,
4546
},
4647
}
4748

@@ -207,7 +208,7 @@ pub(super) fn transcribe<'a>(
207208

208209
// Is the repetition empty?
209210
if len == 0 {
210-
if seq.kleene.op == mbe::KleeneOp::OneOrMore {
211+
if seq.kleene.op == KleeneOp::OneOrMore {
211212
// FIXME: this really ought to be caught at macro definition
212213
// time... It happens when the Kleene operator in the matcher and
213214
// the body for the same meta-variable do not match.
@@ -227,6 +228,7 @@ pub(super) fn transcribe<'a>(
227228
idx: 0,
228229
sep: seq.separator.clone(),
229230
tts: &delimited.tts,
231+
kleene_op: seq.kleene.op,
230232
});
231233
}
232234
}
@@ -243,7 +245,8 @@ pub(super) fn transcribe<'a>(
243245
MatchedTokenTree(tt) => {
244246
// `tt`s are emitted into the output stream directly as "raw tokens",
245247
// without wrapping them into groups.
246-
result.push(tt.clone());
248+
marker.visit_span(&mut sp);
249+
result.push(maybe_use_metavar_location(cx, &stack, sp, tt));
247250
}
248251
MatchedNonterminal(nt) => {
249252
// Other variables are emitted into the output stream as groups with
@@ -308,6 +311,82 @@ pub(super) fn transcribe<'a>(
308311
}
309312
}
310313

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+
///
323+
/// Usually metavariables `$var` produce interpolated tokens, which have an additional place for
324+
/// keeping both the original span and the metavariable span. For `tt` metavariables that's not the
325+
/// case however, and there's no place for keeping a second span. So we try to give the single
326+
/// produced span a location that would be most useful in practice (the hygiene part of the span
327+
/// must not be changed).
328+
///
329+
/// Different locations are useful for different purposes:
330+
/// - The original location is useful when we need to report a diagnostic for the original token in
331+
/// isolation, without combining it with any surrounding tokens. This case occurs, but it is not
332+
/// very common in practice.
333+
/// - The metavariable location is useful when we need to somehow combine the token span with spans
334+
/// of its surrounding tokens. This is the most common way to use token spans.
335+
///
336+
/// So this function replaces the original location with the metavariable location in all cases
337+
/// except these two:
338+
/// - The metavariable is an element of undelimited sequence `$($tt)*`.
339+
/// These are typically used for passing larger amounts of code, and tokens in that code usually
340+
/// combine with each other and not with tokens outside of the sequence.
341+
/// - The metavariable span comes from a different crate, then we prefer the more local span.
342+
fn maybe_use_metavar_location(
343+
cx: &ExtCtxt<'_>,
344+
stack: &[Frame<'_>],
345+
metavar_span: Span,
346+
orig_tt: &TokenTree,
347+
) -> TokenTree {
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) {
368+
return orig_tt.clone();
369+
}
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.
373+
match orig_tt {
374+
TokenTree::Token(Token { kind, span }, spacing) => {
375+
let span = metavar_span.with_ctxt(span.ctxt());
376+
let _ = try_insert_metavar_span(span, metavar_span);
377+
TokenTree::Token(Token { kind: kind.clone(), span }, *spacing)
378+
}
379+
TokenTree::Delimited(dspan, dspacing, delimiter, tts) => {
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);
384+
let dspan = DelimSpan::from_pair(open, close);
385+
TokenTree::Delimited(dspan, *dspacing, *delimiter, tts.clone())
386+
}
387+
}
388+
}
389+
311390
/// Lookup the meta-var named `ident` and return the matched token tree from the invocation using
312391
/// the set of matches `interpolations`.
313392
///

compiler/rustc_expand/src/proc_macro_server.rs

-8
Original file line numberDiff line numberDiff line change
@@ -242,14 +242,6 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre
242242
}));
243243
}
244244

245-
Interpolated(ref nt) if let NtIdent(ident, is_raw) = &nt.0 => {
246-
trees.push(TokenTree::Ident(Ident {
247-
sym: ident.name,
248-
is_raw: *is_raw,
249-
span: ident.span,
250-
}))
251-
}
252-
253245
Interpolated(nt) => {
254246
let stream = TokenStream::from_nonterminal_ast(&nt.0);
255247
// A hack used to pass AST fragments to attribute and derive

compiler/rustc_parse/src/parser/attr_wrapper.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -226,8 +226,7 @@ impl<'a> Parser<'a> {
226226
let (mut ret, trailing) = ret?;
227227

228228
// When we're not in `capture-cfg` mode, then bail out early if:
229-
// 1. Our target doesn't support tokens at all (e.g we're parsing an `NtIdent`)
230-
// so there's nothing for us to do.
229+
// 1. Our target doesn't support tokens at all, so there's nothing for us to do.
231230
// 2. Our target already has tokens set (e.g. we've parsed something
232231
// like `#[my_attr] $item`. The actual parsing code takes care of prepending
233232
// any attributes to the nonterminal, so we don't need to modify the

0 commit comments

Comments
 (0)