-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
Edition-gated keywords #49611
Edition-gated keywords #49611
Changes from all commits
4607cc6
d55832f
0eabb1b
0407348
a4945c6
658840f
79a654d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -278,8 +278,8 @@ macro_rules! declare_keywords {( | |
// NB: leaving holes in the ident table is bad! a different ident will get | ||
// interned with the id from the hole, but it will be between the min and max | ||
// of the reserved words, and thus tagged as "reserved". | ||
// After modifying this list adjust `is_special_ident`, `is_used_keyword`/`is_unused_keyword`, | ||
// this should be rarely necessary though if the keywords are kept in alphabetic order. | ||
// After modifying this list adjust `is_special`, `is_used_keyword`/`is_unused_keyword` | ||
// velow | ||
declare_keywords! { | ||
// Special reserved identifiers used internally for elided lifetimes, | ||
// unnamed method parameters, crate root module, error recovery etc. | ||
|
@@ -325,6 +325,9 @@ declare_keywords! { | |
(37, Use, "use") | ||
(38, Where, "where") | ||
(39, While, "while") | ||
// edition-gated used keywords go here | ||
// be sure to update is_used_keyword and | ||
// is_future_edition_keyword_* below | ||
|
||
// Keywords reserved for future use. | ||
(40, Abstract, "abstract") | ||
|
@@ -343,17 +346,66 @@ declare_keywords! { | |
(53, Unsized, "unsized") | ||
(54, Virtual, "virtual") | ||
(55, Yield, "yield") | ||
// edition-gated reserved keywords | ||
// be sure to update is_unused_keyword and | ||
// is_future_edition_keyword_* below | ||
(56, Async, "async") // Rust 2018+ only | ||
|
||
// Special lifetime names | ||
(56, UnderscoreLifetime, "'_") | ||
(57, StaticLifetime, "'static") | ||
(57, UnderscoreLifetime, "'_") | ||
(58, StaticLifetime, "'static") | ||
|
||
// Weak keywords, have special meaning only in specific contexts. | ||
(58, Auto, "auto") | ||
(59, Catch, "catch") | ||
(60, Default, "default") | ||
(61, Dyn, "dyn") | ||
(62, Union, "union") | ||
(59, Auto, "auto") | ||
(60, Catch, "catch") | ||
(61, Default, "default") | ||
(62, Dyn, "dyn") | ||
(63, Union, "union") | ||
} | ||
|
||
impl Ident { | ||
// Returns true for reserved identifiers used internally for elided lifetimes, | ||
// unnamed method parameters, crate root module, error recovery etc. | ||
#[inline] | ||
pub fn is_special(self) -> bool { | ||
self.name <= self::keywords::Underscore.name() | ||
} | ||
|
||
/// Returns `true` if the token is a keyword used in the language, for | ||
/// at least one edition. | ||
/// | ||
/// Keywords from future editions will be lexed as if they were raw identifiers | ||
/// so they will not reach this step. | ||
#[inline] | ||
pub fn is_used_keyword(self) -> bool { | ||
self.name >= self::keywords::As.name() && self.name <= self::keywords::While.name() | ||
} | ||
|
||
/// Returns `true` if the token is a keyword reserved for possible future use, for | ||
/// at least one edition. | ||
#[inline] | ||
pub fn is_unused_keyword(self) -> bool { | ||
self.name >= self::keywords::Abstract.name() && self.name <= self::keywords::Async.name() | ||
} | ||
|
||
|
||
/// Returns `true` if the token is either a special identifier or a keyword. | ||
#[inline] | ||
pub fn is_reserved(self) -> bool { | ||
self.is_special() || self.is_used_keyword() || self.is_unused_keyword() | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If these functions are moved to methods, then they should rather become methods of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we let that be a mentored followup? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok. |
||
} | ||
|
||
impl Symbol { | ||
#[inline] | ||
pub fn is_future_edition_keyword_2015(self) -> bool { | ||
self == self::keywords::Async.name() | ||
} | ||
|
||
#[inline] | ||
pub fn is_future_edition_keyword_2018(self) -> bool { | ||
false | ||
} | ||
} | ||
|
||
// If an interner exists, return it. Otherwise, prepare a fresh one. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT | ||
// file at the top-level directory of this distribution and at | ||
// http://rust-lang.org/COPYRIGHT. | ||
// | ||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | ||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | ||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | ||
// option. This file may not be copied, modified, or distributed | ||
// except according to those terms. | ||
|
||
// compile-flags: -Zedition=2015 -Zunstable-options | ||
|
||
#[macro_export] | ||
macro_rules! consumes_async { | ||
(async) => (1) | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT | ||
// file at the top-level directory of this distribution and at | ||
// http://rust-lang.org/COPYRIGHT. | ||
// | ||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | ||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | ||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | ||
// option. This file may not be copied, modified, or distributed | ||
// except according to those terms. | ||
|
||
// compile-flags: -Zedition=2018 -Zunstable-options | ||
// aux-build:edition-kw-macro-2015.rs | ||
|
||
#![feature(raw_identifiers)] | ||
|
||
#[macro_use] | ||
extern crate edition_kw_macro_2015; | ||
|
||
pub fn main() { | ||
let _ = consumes_async!(async); | ||
//~^ ERROR no rules expected the token `async` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think this is correct behavior, macros' left hand sides don't care about keywordy-ness status of tokens they match. They can equally well match tokens from code snippets written in any Rust editions or even in C++, Java or mix of both. (See #49520) The correct solution requires a bit more effort, but not significantly more, thankfully:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I disagree; we're going to ask macro consumers to rustfix usages of I find it would be inconsistent if some macros stopped working in the 2018 epoch when fed thoughts, @nikomatsakis ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, FWIW for the lint we're going to have to tristate the bool field anyway, as a "specified raw, keyword but not on current epoch, and keyword on current epoch", and we can have the macro matcher consider the last two to be equal. But I'm not certain. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not only about macros, what bothers me is that the "pretend these are raw" implementation works on fundamentally wrong level. There are no keywords in the token world, that's why neither lexer nor macros weren't concerned about keywords previously. Keywords appear only when we introduce some grammar on those tokens, so the edition-keyword problem need to be solved on grammar/syntax level as well. This means I need some time to flesh this out, maybe make a prototype (this shouldn't be a large change), I'm not satisfied with what this PR does at all. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Okay, so --- in the changes I haven't made yet (but planned to for the linting step once we figure that out better), there will be three states:
This will mean that we no longer pretend things are raw, and we can do equality differently in different contexts. For epoch hygiene to work we basically have to do this at the token level, though. I don't like having keywords pollute the lexer, but I don't see a better way of doing this that handles macros well. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Linting what exactly? Identifiers that are not keywords in this edition, but will be keywords in the next edition? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We'd also need to lint stuff in macro defs and invocations, which complicates things. As an edition breakage it's important that we lint everything. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Regarding reporting "really everything", I think this is more of a problem with lint infrastructure rather than with edition keywords specifically. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed, but it's not clear how to fix it. The proposal we had was that the parser can keep track of lint levels for specific lints and we just lint in the parser. We can also stash lints by span as suggested by @oli-obk There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (though that still requires some way of visiting them) |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT | ||
// file at the top-level directory of this distribution and at | ||
// http://rust-lang.org/COPYRIGHT. | ||
// | ||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | ||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | ||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | ||
// option. This file may not be copied, modified, or distributed | ||
// except according to those terms. | ||
|
||
// compile-flags: -Zedition=2018 -Zunstable-options | ||
|
||
#![allow(unused)] | ||
|
||
pub fn main() { | ||
let async = 1; | ||
//~^ ERROR expected pattern, found reserved keyword `async` | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT | ||
// file at the top-level directory of this distribution and at | ||
// http://rust-lang.org/COPYRIGHT. | ||
// | ||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | ||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | ||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | ||
// option. This file may not be copied, modified, or distributed | ||
// except according to those terms. | ||
|
||
// compile-flags: -Zedition=2015 -Zunstable-options | ||
#![feature(raw_identifiers)] | ||
|
||
#[macro_export] | ||
macro_rules! produces_async { | ||
() => (pub fn async() {}) | ||
} | ||
|
||
#[macro_export] | ||
macro_rules! produces_async_raw { | ||
() => (pub fn r#async() {}) | ||
} | ||
|
||
#[macro_export] | ||
macro_rules! consumes_async { | ||
(async) => (1) | ||
} | ||
|
||
#[macro_export] | ||
macro_rules! consumes_async_raw { | ||
(r#async) => (1) | ||
} | ||
|
||
#[macro_export] | ||
macro_rules! consumes_ident { | ||
($i:ident) => ($i) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
*below