1
Fork 0

syntax: Make _ an identifier

This commit is contained in:
Vadim Petrochenkov 2018-03-08 14:27:23 +03:00
parent 61b6bf54fd
commit 5d06c890fe
20 changed files with 109 additions and 119 deletions

View file

@ -680,7 +680,6 @@ impl TokenTree {
Pound => op!('#'), Pound => op!('#'),
Dollar => op!('$'), Dollar => op!('$'),
Question => op!('?'), Question => op!('?'),
Underscore => op!('_'),
Ident(ident) | Lifetime(ident) => TokenNode::Term(Term(ident.name)), Ident(ident) | Lifetime(ident) => TokenNode::Term(Term(ident.name)),
Literal(..) | DocComment(..) => TokenNode::Literal(self::Literal(token)), Literal(..) | DocComment(..) => TokenNode::Literal(self::Literal(token)),
@ -743,7 +742,6 @@ impl TokenTree {
'#' => Pound, '#' => Pound,
'$' => Dollar, '$' => Dollar,
'?' => Question, '?' => Question,
'_' => Underscore,
_ => panic!("unsupported character {}", op), _ => panic!("unsupported character {}", op),
}; };

View file

@ -214,7 +214,7 @@ impl LifetimeName {
use self::LifetimeName::*; use self::LifetimeName::*;
match *self { match *self {
Implicit => keywords::Invalid.name(), Implicit => keywords::Invalid.name(),
Underscore => Symbol::intern("'_"), Underscore => keywords::UnderscoreLifetime.name(),
Static => keywords::StaticLifetime.name(), Static => keywords::StaticLifetime.name(),
Name(name) => name, Name(name) => name,
} }

View file

@ -287,7 +287,6 @@ fn hash_token<'a, 'gcx, W: StableHasherResult>(
token::Token::Pound | token::Token::Pound |
token::Token::Dollar | token::Token::Dollar |
token::Token::Question | token::Token::Question |
token::Token::Underscore |
token::Token::Whitespace | token::Token::Whitespace |
token::Token::Comment | token::Token::Comment |
token::Token::Eof => {} token::Token::Eof => {}

View file

@ -37,7 +37,9 @@ impl<'a> AstValidator<'a> {
} }
fn check_lifetime(&self, lifetime: &Lifetime) { fn check_lifetime(&self, lifetime: &Lifetime) {
let valid_names = [keywords::StaticLifetime.name(), keywords::Invalid.name()]; let valid_names = [keywords::UnderscoreLifetime.name(),
keywords::StaticLifetime.name(),
keywords::Invalid.name()];
if !valid_names.contains(&lifetime.ident.name) && if !valid_names.contains(&lifetime.ident.name) &&
token::Ident(lifetime.ident.without_first_quote()).is_reserved_ident() { token::Ident(lifetime.ident.without_first_quote()).is_reserved_ident() {
self.err_handler().span_err(lifetime.span, "lifetimes cannot use keyword names"); self.err_handler().span_err(lifetime.span, "lifetimes cannot use keyword names");
@ -45,7 +47,7 @@ impl<'a> AstValidator<'a> {
} }
fn check_label(&self, label: Ident, span: Span) { fn check_label(&self, label: Ident, span: Span) {
if token::Ident(label.without_first_quote()).is_reserved_ident() || label.name == "'_" { if token::Ident(label.without_first_quote()).is_reserved_ident() {
self.err_handler().span_err(span, &format!("invalid label name `{}`", label.name)); self.err_handler().span_err(span, &format!("invalid label name `{}`", label.name));
} }
} }

View file

@ -352,7 +352,7 @@ impl<'a> Classifier<'a> {
token::Lifetime(..) => Class::Lifetime, token::Lifetime(..) => Class::Lifetime,
token::Underscore | token::Eof | token::Interpolated(..) | token::Eof | token::Interpolated(..) |
token::Tilde | token::At | token::DotEq => Class::None, token::Tilde | token::At | token::DotEq => Class::None,
}; };

View file

@ -19,7 +19,7 @@ use ext::base::{ExtCtxt, MacEager, MacResult};
use ext::build::AstBuilder; use ext::build::AstBuilder;
use parse::token; use parse::token;
use ptr::P; use ptr::P;
use symbol::Symbol; use symbol::{keywords, Symbol};
use tokenstream::{TokenTree}; use tokenstream::{TokenTree};
use util::small_vector::SmallVector; use util::small_vector::SmallVector;
@ -192,7 +192,7 @@ pub fn expand_build_diagnostic_array<'cx>(ecx: &'cx mut ExtCtxt,
(descriptions.len(), ecx.expr_vec(span, descriptions)) (descriptions.len(), ecx.expr_vec(span, descriptions))
}); });
let static_ = ecx.lifetime(span, Ident::from_str("'static")); let static_ = ecx.lifetime(span, keywords::StaticLifetime.ident());
let ty_str = ecx.ty_rptr( let ty_str = ecx.ty_rptr(
span, span,
ecx.ty_ident(span, ecx.ident_of("str")), ecx.ty_ident(span, ecx.ident_of("str")),

View file

@ -709,7 +709,6 @@ fn expr_mk_token(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> P<ast::Expr> {
token::Pound => "Pound", token::Pound => "Pound",
token::Dollar => "Dollar", token::Dollar => "Dollar",
token::Question => "Question", token::Question => "Question",
token::Underscore => "Underscore",
token::Eof => "Eof", token::Eof => "Eof",
token::Whitespace | token::Comment | token::Shebang(_) => { token::Whitespace | token::Comment | token::Shebang(_) => {

View file

@ -765,8 +765,7 @@ fn may_begin_with(name: &str, token: &Token) -> bool {
Token::DotDotDot | // range pattern (future compat) Token::DotDotDot | // range pattern (future compat)
Token::ModSep | // path Token::ModSep | // path
Token::Lt | // path (UFCS constant) Token::Lt | // path (UFCS constant)
Token::BinOp(token::Shl) | // path (double UFCS) Token::BinOp(token::Shl) => true, // path (double UFCS)
Token::Underscore => true, // placeholder
Token::Interpolated(ref nt) => may_be_ident(&nt.0), Token::Interpolated(ref nt) => may_be_ident(&nt.0),
_ => false, _ => false,
}, },

View file

@ -1790,7 +1790,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
} }
fn visit_lifetime(&mut self, lt: &'a ast::Lifetime) { fn visit_lifetime(&mut self, lt: &'a ast::Lifetime) {
if lt.ident.name == "'_" { if lt.ident.name == keywords::UnderscoreLifetime.name() {
gate_feature_post!(&self, underscore_lifetimes, lt.span, gate_feature_post!(&self, underscore_lifetimes, lt.span,
"underscore lifetimes are unstable"); "underscore lifetimes are unstable");
} }

View file

@ -34,7 +34,7 @@ pub struct TokenAndSpan {
impl Default for TokenAndSpan { impl Default for TokenAndSpan {
fn default() -> Self { fn default() -> Self {
TokenAndSpan { tok: token::Underscore, sp: syntax_pos::DUMMY_SP } TokenAndSpan { tok: token::Whitespace, sp: syntax_pos::DUMMY_SP }
} }
} }
@ -126,7 +126,7 @@ impl<'a> StringReader<'a> {
pub fn try_next_token(&mut self) -> Result<TokenAndSpan, ()> { pub fn try_next_token(&mut self) -> Result<TokenAndSpan, ()> {
assert!(self.fatal_errs.is_empty()); assert!(self.fatal_errs.is_empty());
let ret_val = TokenAndSpan { let ret_val = TokenAndSpan {
tok: replace(&mut self.peek_tok, token::Underscore), tok: replace(&mut self.peek_tok, token::Whitespace),
sp: self.peek_span, sp: self.peek_span,
}; };
self.advance_token()?; self.advance_token()?;
@ -1133,14 +1133,8 @@ impl<'a> StringReader<'a> {
self.bump(); self.bump();
} }
return Ok(self.with_str_from(start, |string| {
if string == "_" {
token::Underscore
} else {
// FIXME: perform NFKC normalization here. (Issue #2253) // FIXME: perform NFKC normalization here. (Issue #2253)
token::Ident(self.mk_ident(string)) return Ok(self.with_str_from(start, |string| token::Ident(self.mk_ident(string))));
}
}));
} }
if is_dec_digit(c) { if is_dec_digit(c) {

View file

@ -549,7 +549,7 @@ impl<'a> Parser<'a> {
-> Self { -> Self {
let mut parser = Parser { let mut parser = Parser {
sess, sess,
token: token::Underscore, token: token::Whitespace,
span: syntax_pos::DUMMY_SP, span: syntax_pos::DUMMY_SP,
prev_span: syntax_pos::DUMMY_SP, prev_span: syntax_pos::DUMMY_SP,
meta_var_span: None, meta_var_span: None,
@ -800,11 +800,7 @@ impl<'a> Parser<'a> {
Err(if self.prev_token_kind == PrevTokenKind::DocComment { Err(if self.prev_token_kind == PrevTokenKind::DocComment {
self.span_fatal_err(self.prev_span, Error::UselessDocComment) self.span_fatal_err(self.prev_span, Error::UselessDocComment)
} else { } else {
let mut err = self.expected_ident_found(); self.expected_ident_found()
if self.token == token::Underscore {
err.note("`_` is a wildcard pattern, not an identifier");
}
err
}) })
} }
} }
@ -1602,7 +1598,7 @@ impl<'a> Parser<'a> {
let e = self.parse_expr()?; let e = self.parse_expr()?;
self.expect(&token::CloseDelim(token::Paren))?; self.expect(&token::CloseDelim(token::Paren))?;
TyKind::Typeof(e) TyKind::Typeof(e)
} else if self.eat(&token::Underscore) { } else if self.eat_keyword(keywords::Underscore) {
// A type to be inferred `_` // A type to be inferred `_`
TyKind::Infer TyKind::Infer
} else if self.token_is_bare_fn_keyword() { } else if self.token_is_bare_fn_keyword() {
@ -1796,7 +1792,7 @@ impl<'a> Parser<'a> {
_ => 0, _ => 0,
}; };
self.look_ahead(offset, |t| t.is_ident() || t == &token::Underscore) && self.look_ahead(offset, |t| t.is_ident()) &&
self.look_ahead(offset + 1, |t| t == &token::Colon) self.look_ahead(offset + 1, |t| t == &token::Colon)
} }
@ -2782,7 +2778,7 @@ impl<'a> Parser<'a> {
}, },
token::CloseDelim(_) | token::Eof => unreachable!(), token::CloseDelim(_) | token::Eof => unreachable!(),
_ => { _ => {
let (token, span) = (mem::replace(&mut self.token, token::Underscore), self.span); let (token, span) = (mem::replace(&mut self.token, token::Whitespace), self.span);
self.bump(); self.bump();
TokenTree::Token(span, token) TokenTree::Token(span, token)
} }
@ -3815,11 +3811,6 @@ impl<'a> Parser<'a> {
let lo = self.span; let lo = self.span;
let pat; let pat;
match self.token { match self.token {
token::Underscore => {
// Parse _
self.bump();
pat = PatKind::Wild;
}
token::BinOp(token::And) | token::AndAnd => { token::BinOp(token::And) | token::AndAnd => {
// Parse &pat / &mut pat // Parse &pat / &mut pat
self.expect_and()?; self.expect_and()?;
@ -3849,8 +3840,11 @@ impl<'a> Parser<'a> {
self.expect(&token::CloseDelim(token::Bracket))?; self.expect(&token::CloseDelim(token::Bracket))?;
pat = PatKind::Slice(before, slice, after); pat = PatKind::Slice(before, slice, after);
} }
// At this point, token != _, &, &&, (, [ // At this point, token != &, &&, (, [
_ => if self.eat_keyword(keywords::Mut) { _ => if self.eat_keyword(keywords::Underscore) {
// Parse _
pat = PatKind::Wild;
} else if self.eat_keyword(keywords::Mut) {
// Parse mut ident @ pat / mut ref ident @ pat // Parse mut ident @ pat / mut ref ident @ pat
let mutref_span = self.prev_span.to(self.span); let mutref_span = self.prev_span.to(self.span);
let binding_mode = if self.eat_keyword(keywords::Ref) { let binding_mode = if self.eat_keyword(keywords::Ref) {
@ -7065,10 +7059,12 @@ impl<'a> Parser<'a> {
fn parse_rename(&mut self) -> PResult<'a, Option<Ident>> { fn parse_rename(&mut self) -> PResult<'a, Option<Ident>> {
if self.eat_keyword(keywords::As) { if self.eat_keyword(keywords::As) {
if self.eat(&token::Underscore) { match self.token {
Ok(Some(Ident::with_empty_ctxt(Symbol::gensym("_")))) token::Ident(ident) if ident.name == keywords::Underscore.name() => {
} else { self.bump(); // `_`
self.parse_ident().map(Some) Ok(Some(Ident { name: ident.name.gensymed(), ..ident }))
}
_ => self.parse_ident().map(Some),
} }
} else { } else {
Ok(None) Ok(None)

View file

@ -122,6 +122,7 @@ fn ident_can_begin_type(ident: ast::Ident) -> bool {
!ident_token.is_reserved_ident() || !ident_token.is_reserved_ident() ||
ident_token.is_path_segment_keyword() || ident_token.is_path_segment_keyword() ||
[ [
keywords::Underscore.name(),
keywords::For.name(), keywords::For.name(),
keywords::Impl.name(), keywords::Impl.name(),
keywords::Fn.name(), keywords::Fn.name(),
@ -175,7 +176,6 @@ pub enum Token {
/* Name components */ /* Name components */
Ident(ast::Ident), Ident(ast::Ident),
Underscore,
Lifetime(ast::Ident), Lifetime(ast::Ident),
// The `LazyTokenStream` is a pure function of the `Nonterminal`, // The `LazyTokenStream` is a pure function of the `Nonterminal`,
@ -242,7 +242,6 @@ impl Token {
Ident(ident) => ident_can_begin_type(ident), // type name or keyword Ident(ident) => ident_can_begin_type(ident), // type name or keyword
OpenDelim(Paren) | // tuple OpenDelim(Paren) | // tuple
OpenDelim(Bracket) | // array OpenDelim(Bracket) | // array
Underscore | // placeholder
Not | // never Not | // never
BinOp(Star) | // raw pointer BinOp(Star) | // raw pointer
BinOp(And) | // reference BinOp(And) | // reference
@ -371,7 +370,7 @@ impl Token {
// unnamed method parameters, crate root module, error recovery etc. // unnamed method parameters, crate root module, error recovery etc.
pub fn is_special_ident(&self) -> bool { pub fn is_special_ident(&self) -> bool {
match self.ident() { match self.ident() {
Some(id) => id.name <= keywords::DollarCrate.name(), Some(id) => id.name <= keywords::Underscore.name(),
_ => false, _ => false,
} }
} }
@ -441,7 +440,7 @@ impl Token {
Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | BinOpEq(..) | At | DotDotDot | DotEq | Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | BinOpEq(..) | At | DotDotDot | DotEq |
DotDotEq | Comma | Semi | ModSep | RArrow | LArrow | FatArrow | Pound | Dollar | DotDotEq | Comma | Semi | ModSep | RArrow | LArrow | FatArrow | Pound | Dollar |
Question | OpenDelim(..) | CloseDelim(..) | Underscore => return None, Question | OpenDelim(..) | CloseDelim(..) => return None,
Literal(..) | Ident(..) | Lifetime(..) | Interpolated(..) | DocComment(..) | Literal(..) | Ident(..) | Lifetime(..) | Interpolated(..) | DocComment(..) |
Whitespace | Comment | Shebang(..) | Eof => return None, Whitespace | Comment | Shebang(..) | Eof => return None,
@ -573,7 +572,7 @@ impl fmt::Debug for Nonterminal {
pub fn is_op(tok: &Token) -> bool { pub fn is_op(tok: &Token) -> bool {
match *tok { match *tok {
OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) |
Ident(..) | Underscore | Lifetime(..) | Interpolated(..) | Ident(..) | Lifetime(..) | Interpolated(..) |
Whitespace | Comment | Shebang(..) | Eof => false, Whitespace | Comment | Shebang(..) | Eof => false,
_ => true, _ => true,
} }

View file

@ -252,7 +252,6 @@ pub fn token_to_string(tok: &Token) -> String {
/* Name components */ /* Name components */
token::Ident(s) => s.to_string(), token::Ident(s) => s.to_string(),
token::Lifetime(s) => s.to_string(), token::Lifetime(s) => s.to_string(),
token::Underscore => "_".to_string(),
/* Other */ /* Other */
token::DocComment(s) => s.to_string(), token::DocComment(s) => s.to_string(),

View file

@ -17,7 +17,7 @@ use syntax::ast::{self, Ident};
use syntax::ext::base::*; use syntax::ext::base::*;
use syntax::ext::base; use syntax::ext::base;
use syntax::ext::build::AstBuilder; use syntax::ext::build::AstBuilder;
use syntax::symbol::Symbol; use syntax::symbol::{keywords, Symbol};
use syntax_pos::Span; use syntax_pos::Span;
use syntax::tokenstream; use syntax::tokenstream;
@ -35,14 +35,14 @@ pub fn expand_option_env<'cx>(cx: &'cx mut ExtCtxt,
let sp = sp.with_ctxt(sp.ctxt().apply_mark(cx.current_expansion.mark)); let sp = sp.with_ctxt(sp.ctxt().apply_mark(cx.current_expansion.mark));
let e = match env::var(&*var.as_str()) { let e = match env::var(&*var.as_str()) {
Err(..) => { Err(..) => {
let lt = cx.lifetime(sp, keywords::StaticLifetime.ident());
cx.expr_path(cx.path_all(sp, cx.expr_path(cx.path_all(sp,
true, true,
cx.std_path(&["option", "Option", "None"]), cx.std_path(&["option", "Option", "None"]),
Vec::new(), Vec::new(),
vec![cx.ty_rptr(sp, vec![cx.ty_rptr(sp,
cx.ty_ident(sp, Ident::from_str("str")), cx.ty_ident(sp, Ident::from_str("str")),
Some(cx.lifetime(sp, Some(lt),
Ident::from_str("'static"))),
ast::Mutability::Immutable)], ast::Mutability::Immutable)],
Vec::new())) Vec::new()))
} }

View file

@ -264,70 +264,74 @@ declare_keywords! {
(0, Invalid, "") (0, Invalid, "")
(1, CrateRoot, "{{root}}") (1, CrateRoot, "{{root}}")
(2, DollarCrate, "$crate") (2, DollarCrate, "$crate")
(3, Underscore, "_")
// Keywords used in the language. // Keywords used in the language.
(3, As, "as") (4, As, "as")
(4, Box, "box") (5, Box, "box")
(5, Break, "break") (6, Break, "break")
(6, Const, "const") (7, Const, "const")
(7, Continue, "continue") (8, Continue, "continue")
(8, Crate, "crate") (9, Crate, "crate")
(9, Else, "else") (10, Else, "else")
(10, Enum, "enum") (11, Enum, "enum")
(11, Extern, "extern") (12, Extern, "extern")
(12, False, "false") (13, False, "false")
(13, Fn, "fn") (14, Fn, "fn")
(14, For, "for") (15, For, "for")
(15, If, "if") (16, If, "if")
(16, Impl, "impl") (17, Impl, "impl")
(17, In, "in") (18, In, "in")
(18, Let, "let") (19, Let, "let")
(19, Loop, "loop") (20, Loop, "loop")
(20, Match, "match") (21, Match, "match")
(21, Mod, "mod") (22, Mod, "mod")
(22, Move, "move") (23, Move, "move")
(23, Mut, "mut") (24, Mut, "mut")
(24, Pub, "pub") (25, Pub, "pub")
(25, Ref, "ref") (26, Ref, "ref")
(26, Return, "return") (27, Return, "return")
(27, SelfValue, "self") (28, SelfValue, "self")
(28, SelfType, "Self") (29, SelfType, "Self")
(29, Static, "static") (30, Static, "static")
(30, Struct, "struct") (31, Struct, "struct")
(31, Super, "super") (32, Super, "super")
(32, Trait, "trait") (33, Trait, "trait")
(33, True, "true") (34, True, "true")
(34, Type, "type") (35, Type, "type")
(35, Unsafe, "unsafe") (36, Unsafe, "unsafe")
(36, Use, "use") (37, Use, "use")
(37, Where, "where") (38, Where, "where")
(38, While, "while") (39, While, "while")
// Keywords reserved for future use. // Keywords reserved for future use.
(39, Abstract, "abstract") (40, Abstract, "abstract")
(40, Alignof, "alignof") (41, Alignof, "alignof")
(41, Become, "become") (42, Become, "become")
(42, Do, "do") (43, Do, "do")
(43, Final, "final") (44, Final, "final")
(44, Macro, "macro") (45, Macro, "macro")
(45, Offsetof, "offsetof") (46, Offsetof, "offsetof")
(46, Override, "override") (47, Override, "override")
(47, Priv, "priv") (48, Priv, "priv")
(48, Proc, "proc") (49, Proc, "proc")
(49, Pure, "pure") (50, Pure, "pure")
(50, Sizeof, "sizeof") (51, Sizeof, "sizeof")
(51, Typeof, "typeof") (52, Typeof, "typeof")
(52, Unsized, "unsized") (53, Unsized, "unsized")
(53, Virtual, "virtual") (54, Virtual, "virtual")
(54, Yield, "yield") (55, Yield, "yield")
// Special lifetime names
(56, UnderscoreLifetime, "'_")
(57, StaticLifetime, "'static")
// Weak keywords, have special meaning only in specific contexts. // Weak keywords, have special meaning only in specific contexts.
(55, Auto, "auto") (58, Auto, "auto")
(56, Catch, "catch") (59, Catch, "catch")
(57, Default, "default") (60, Default, "default")
(58, Dyn, "dyn") (61, Dyn, "dyn")
(59, StaticLifetime, "'static") (62, Union, "union")
(60, Union, "union")
} }
// If an interner exists, return it. Otherwise, prepare a fresh one. // If an interner exists, return it. Otherwise, prepare a fresh one.

View file

@ -16,7 +16,5 @@ fn main() {
let _ = 0; let _ = 0;
let mut b = 0; let mut b = 0;
let mut _b = 0; let mut _b = 0;
let mut _ = 0; //~ ERROR expected identifier, found `_` let mut _ = 0; //~ ERROR expected identifier, found reserved identifier `_`
//~^ NOTE `_` is a wildcard pattern, not an identifier
//~| NOTE expected identifier
} }

View file

@ -39,5 +39,5 @@ fn main() {
} }
} }
// still recover later // still recover later
let bad_syntax = _; //~ ERROR: found `_` let bad_syntax = _; //~ ERROR: expected expression, found reserved identifier `_`
} }

View file

@ -9,5 +9,6 @@
// except according to those terms. // except according to those terms.
fn main() { fn main() {
let a = 42._; //~ ERROR unexpected token: `_` let a = 42._; //~ ERROR expected identifier, found reserved identifier `_`
//~^ ERROR `{integer}` is a primitive type and therefore doesn't have fields
} }

View file

@ -71,4 +71,6 @@ pub fn main() {
let ident_pat!(x) = 2; let ident_pat!(x) = 2;
x+1 x+1
}); });
let ident_pat!(_) = 2; // OK
} }

View file

@ -1,4 +1,4 @@
error: expected expression, found `_` error: expected expression, found reserved identifier `_`
--> $DIR/underscore.rs:18:9 --> $DIR/underscore.rs:18:9
| |
LL | _ LL | _