Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Store NtLiteral without generalizing to Expr #92392

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions compiler/rustc_ast/src/ast_like.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ impl AstLike for crate::token::Nonterminal {
match self {
Nonterminal::NtItem(item) => item.attrs(),
Nonterminal::NtStmt(stmt) => stmt.attrs(),
Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.attrs(),
Nonterminal::NtExpr(expr) => expr.attrs(),
Nonterminal::NtPat(_)
| Nonterminal::NtTy(_)
| Nonterminal::NtMeta(_)
Expand All @@ -53,14 +53,15 @@ impl AstLike for crate::token::Nonterminal {
| Nonterminal::NtTT(_)
| Nonterminal::NtBlock(_)
| Nonterminal::NtIdent(..)
| Nonterminal::NtLifetime(_) => &[],
| Nonterminal::NtLifetime(_)
| Nonterminal::NtLiteral(_) => &[],
}
}
fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
match self {
Nonterminal::NtItem(item) => item.visit_attrs(f),
Nonterminal::NtStmt(stmt) => stmt.visit_attrs(f),
Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.visit_attrs(f),
Nonterminal::NtExpr(expr) => expr.visit_attrs(f),
Nonterminal::NtPat(_)
| Nonterminal::NtTy(_)
| Nonterminal::NtMeta(_)
Expand All @@ -69,21 +70,25 @@ impl AstLike for crate::token::Nonterminal {
| Nonterminal::NtTT(_)
| Nonterminal::NtBlock(_)
| Nonterminal::NtIdent(..)
| Nonterminal::NtLifetime(_) => {}
| Nonterminal::NtLifetime(_)
| Nonterminal::NtLiteral(_) => {}
}
}
fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
match self {
Nonterminal::NtItem(item) => item.tokens_mut(),
Nonterminal::NtStmt(stmt) => stmt.tokens_mut(),
Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens_mut(),
Nonterminal::NtExpr(expr) => expr.tokens_mut(),
Nonterminal::NtPat(pat) => pat.tokens_mut(),
Nonterminal::NtTy(ty) => ty.tokens_mut(),
Nonterminal::NtMeta(attr_item) => attr_item.tokens_mut(),
Nonterminal::NtPath(path) => path.tokens_mut(),
Nonterminal::NtVis(vis) => vis.tokens_mut(),
Nonterminal::NtBlock(block) => block.tokens_mut(),
Nonterminal::NtIdent(..) | Nonterminal::NtLifetime(..) | Nonterminal::NtTT(..) => None,
Nonterminal::NtIdent(..)
| Nonterminal::NtLifetime(..)
| Nonterminal::NtLiteral(_)
| Nonterminal::NtTT(..) => None,
}
}
}
Expand Down
8 changes: 7 additions & 1 deletion compiler/rustc_ast/src/mut_visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -781,7 +781,13 @@ pub fn visit_interpolated<T: MutVisitor>(nt: &mut token::Nonterminal, vis: &mut
token::NtTy(ty) => vis.visit_ty(ty),
token::NtIdent(ident, _is_raw) => vis.visit_ident(ident),
token::NtLifetime(ident) => vis.visit_ident(ident),
token::NtLiteral(expr) => vis.visit_expr(expr),
token::NtLiteral(signed) => {
if let Some(neg_span) = &mut signed.neg {
vis.visit_span(neg_span);
}
vis.visit_span(&mut signed.lit.span);
vis.visit_span(&mut signed.span);
}
token::NtMeta(item) => {
let AttrItem { path, args, tokens } = item.deref_mut();
vis.visit_path(path);
Expand Down
14 changes: 12 additions & 2 deletions compiler/rustc_ast/src/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -679,14 +679,23 @@ pub enum Nonterminal {
NtTy(P<ast::Ty>),
NtIdent(Ident, /* is_raw */ bool),
NtLifetime(Ident),
NtLiteral(P<ast::Expr>),
NtLiteral(SignedLiteral),
/// Stuff inside brackets for attributes
NtMeta(P<ast::AttrItem>),
NtPath(ast::Path),
NtVis(ast::Visibility),
NtTT(TokenTree),
}

#[derive(Clone, Encodable, Decodable)]
pub struct SignedLiteral {
pub neg: Option<Span>,
pub lit: P<ast::Lit>,
// If neg is None, then identical to lit.span.
// If neg is Some, then neg.to(lit.span).
pub span: Span,
}

// `Nonterminal` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
rustc_data_structures::static_assert_size!(Nonterminal, 48);
Expand Down Expand Up @@ -776,9 +785,10 @@ impl Nonterminal {
NtBlock(block) => block.span,
NtStmt(stmt) => stmt.span,
NtPat(pat) => pat.span,
NtExpr(expr) | NtLiteral(expr) => expr.span,
NtExpr(expr) => expr.span,
NtTy(ty) => ty.span,
NtIdent(ident, _) | NtLifetime(ident) => ident.span,
NtLiteral(lit) => lit.span,
NtMeta(attr_item) => attr_item.span(),
NtPath(path) => path.span,
NtVis(vis) => vis.span,
Expand Down
6 changes: 5 additions & 1 deletion compiler/rustc_ast/src/util/literal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,10 +217,14 @@ impl Lit {
}
token::Literal(lit) => lit,
token::Interpolated(ref nt) => {
if let token::NtExpr(expr) | token::NtLiteral(expr) = &**nt {
if let token::NtExpr(expr) = &**nt {
if let ast::ExprKind::Lit(lit) = &expr.kind {
return Ok(lit.clone());
}
} else if let token::NtLiteral(signed) = &**nt {
if signed.neg.is_none() {
return Ok((*signed.lit).clone());
}
}
return Err(LitError::NotLiteral);
}
Expand Down
8 changes: 7 additions & 1 deletion compiler/rustc_ast_pretty/src/pprust/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -706,7 +706,13 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
token::NtPat(ref e) => self.pat_to_string(e),
token::NtIdent(e, is_raw) => IdentPrinter::for_ast_ident(e, is_raw).to_string(),
token::NtLifetime(e) => e.to_string(),
token::NtLiteral(ref e) => self.expr_to_string(e),
token::NtLiteral(ref e) => {
let mut string = literal_to_string(e.lit.token);
if e.neg.is_some() {
string.insert(0, '-');
}
string
}
token::NtTT(ref tree) => self.tt_to_string(tree),
token::NtVis(ref e) => self.vis_to_string(e),
}
Expand Down
13 changes: 10 additions & 3 deletions compiler/rustc_parse/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
extern crate tracing;

use rustc_ast as ast;
use rustc_ast::token::{self, Nonterminal, Token, TokenKind};
use rustc_ast::token::{self, BinOpToken, Nonterminal, Token, TokenKind};
use rustc_ast::tokenstream::{self, AttributesData, CanSynthesizeMissingTokens, LazyTokenStream};
use rustc_ast::tokenstream::{AttrAnnotatedTokenStream, AttrAnnotatedTokenTree};
use rustc_ast::tokenstream::{Spacing, TokenStream};
Expand Down Expand Up @@ -288,8 +288,15 @@ pub fn nt_to_tokenstream(
Nonterminal::NtPath(ref path) => convert_tokens(path.tokens.as_ref()),
Nonterminal::NtVis(ref vis) => convert_tokens(vis.tokens.as_ref()),
Nonterminal::NtTT(ref tt) => Some(tt.clone().into()),
Nonterminal::NtExpr(ref expr) | Nonterminal::NtLiteral(ref expr) => {
prepend_attrs(&expr.attrs, expr.tokens.as_ref())
Nonterminal::NtExpr(ref expr) => prepend_attrs(&expr.attrs, expr.tokens.as_ref()),
Nonterminal::NtLiteral(ref signed) => {
let literal_tt = tokenstream::TokenTree::token(token::Literal(signed.lit.token), signed.lit.span);
if let Some(neg_span) = signed.neg {
let neg_tt = tokenstream::TokenTree::token(token::BinOp(BinOpToken::Minus), neg_span);
Some(TokenStream::new(vec![(neg_tt, Spacing::Alone), (literal_tt, Spacing::Alone)]))
} else {
Some(literal_tt.into())
}
}
};

Expand Down
50 changes: 32 additions & 18 deletions compiler/rustc_parse/src/parser/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::maybe_recover_from_interpolated_ty_qpath;

use ast::token::DelimToken;
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Token, TokenKind};
use rustc_ast::token::{self, SignedLiteral, Token, TokenKind};
use rustc_ast::tokenstream::Spacing;
use rustc_ast::util::classify;
use rustc_ast::util::literal::LitError;
Expand All @@ -35,11 +35,16 @@ macro_rules! maybe_whole_expr {
($p:expr) => {
if let token::Interpolated(nt) = &$p.token.kind {
match &**nt {
token::NtExpr(e) | token::NtLiteral(e) => {
token::NtExpr(e) => {
let e = e.clone();
$p.bump();
return Ok(e);
}
token::NtLiteral(lit) => {
let e = signed_lit_to_expr(lit.clone());
$p.bump();
return Ok(e);
}
token::NtPath(path) => {
let path = path.clone();
$p.bump();
Expand Down Expand Up @@ -1609,12 +1614,7 @@ impl<'a> Parser<'a> {
pub(super) fn parse_lit(&mut self) -> PResult<'a, Lit> {
self.parse_opt_lit().ok_or_else(|| {
if let token::Interpolated(inner) = &self.token.kind {
let expr = match inner.as_ref() {
token::NtExpr(expr) => Some(expr),
token::NtLiteral(expr) => Some(expr),
_ => None,
};
if let Some(expr) = expr {
if let token::NtExpr(expr) = inner.as_ref() {
if matches!(expr.kind, ExprKind::Err) {
self.diagnostic()
.delay_span_bug(self.token.span, &"invalid interpolated expression");
Expand Down Expand Up @@ -1800,17 +1800,10 @@ impl<'a> Parser<'a> {
let lo = self.token.span;
let minus_present = self.eat(&token::BinOp(token::Minus));
let lit = self.parse_lit()?;
let expr = self.mk_expr(lit.span, ExprKind::Lit(lit), AttrVec::new());
let (neg, span) =
if minus_present { (Some(lo), lo.to(self.prev_token.span)) } else { (None, lit.span) };

if minus_present {
Ok(self.mk_expr(
lo.to(self.prev_token.span),
self.mk_unary(UnOp::Neg, expr),
AttrVec::new(),
))
} else {
Ok(expr)
}
Ok(signed_lit_to_expr(SignedLiteral { neg, lit: P(lit), span }))
}

fn is_array_like_block(&mut self) -> bool {
Expand Down Expand Up @@ -2916,3 +2909,24 @@ impl<'a> Parser<'a> {
})
}
}

fn signed_lit_to_expr(signed: SignedLiteral) -> P<Expr> {
let expr = P(Expr {
kind: ExprKind::Lit((*signed.lit).clone()),
span: signed.lit.span,
attrs: AttrVec::new(),
id: DUMMY_NODE_ID,
tokens: None,
});
if let Some(neg_span) = signed.neg {
P(Expr {
kind: ExprKind::Unary(UnOp::Neg, expr),
span: neg_span.to(signed.lit.span),
attrs: AttrVec::new(),
id: DUMMY_NODE_ID,
tokens: None,
})
} else {
expr
}
}
28 changes: 22 additions & 6 deletions compiler/rustc_parse/src/parser/nonterminal.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Nonterminal, NonterminalKind, Token};
use rustc_ast::AstLike;
use rustc_ast::token::{self, Nonterminal, NonterminalKind, SignedLiteral, Token};
use rustc_ast::{AstLike, ExprKind, UnOp};
use rustc_ast_pretty::pprust;
use rustc_errors::PResult;
use rustc_span::symbol::{kw, Ident};
use rustc_span::BytePos;

use crate::parser::pat::{RecoverColon, RecoverComma};
use crate::parser::{FollowedByType, ForceCollect, Parser, PathStyle};
Expand Down Expand Up @@ -133,10 +134,25 @@ impl<'a> Parser<'a> {

NonterminalKind::Expr => token::NtExpr(self.parse_expr_force_collect()?),
NonterminalKind::Literal => {
// The `:literal` matcher does not support attributes
token::NtLiteral(
self.collect_tokens_no_attrs(|this| this.parse_literal_maybe_minus())?,
)
let mut expr = self.parse_literal_maybe_minus()?.into_inner();
let span = expr.span;

let mut neg = None;
if let ExprKind::Unary(UnOp::Neg, inner) = expr.kind {
// ast::Expr does not store an individual Span of the minus sign,
// only the Span of the whole expr, but we can reconstruct it.
let span_data = expr.span.data();
neg = Some(span_data.with_hi(BytePos(span_data.lo.0 + 1)));
expr = inner.into_inner();
}

let lit = if let ExprKind::Lit(lit) = expr.kind {
P(lit)
} else {
return Err(self.struct_span_err(expr.span, "expected a literal"));
};

token::NtLiteral(SignedLiteral { neg, lit, span })
}

NonterminalKind::Ty => {
Expand Down