Reserve gen
keyword for gen {}
blocks and gen fn
in 2024 edition
This commit is contained in:
parent
ccb160d343
commit
a61cf673cd
14 changed files with 138 additions and 4 deletions
|
@ -2357,6 +2357,12 @@ pub enum Async {
|
||||||
No,
|
No,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Encodable, Decodable, Debug)]
|
||||||
|
pub enum Gen {
|
||||||
|
Yes { span: Span, closure_id: NodeId, return_impl_trait_id: NodeId },
|
||||||
|
No,
|
||||||
|
}
|
||||||
|
|
||||||
impl Async {
|
impl Async {
|
||||||
pub fn is_async(self) -> bool {
|
pub fn is_async(self) -> bool {
|
||||||
matches!(self, Async::Yes { .. })
|
matches!(self, Async::Yes { .. })
|
||||||
|
|
|
@ -197,6 +197,7 @@ pub fn ident_can_begin_expr(name: Symbol, span: Span, is_raw: bool) -> bool {
|
||||||
kw::Continue,
|
kw::Continue,
|
||||||
kw::False,
|
kw::False,
|
||||||
kw::For,
|
kw::For,
|
||||||
|
kw::Gen,
|
||||||
kw::If,
|
kw::If,
|
||||||
kw::Let,
|
kw::Let,
|
||||||
kw::Loop,
|
kw::Loop,
|
||||||
|
|
|
@ -278,6 +278,9 @@ parse_found_expr_would_be_stmt = expected expression, found `{$token}`
|
||||||
parse_function_body_equals_expr = function body cannot be `= expression;`
|
parse_function_body_equals_expr = function body cannot be `= expression;`
|
||||||
.suggestion = surround the expression with `{"{"}` and `{"}"}` instead of `=` and `;`
|
.suggestion = surround the expression with `{"{"}` and `{"}"}` instead of `=` and `;`
|
||||||
|
|
||||||
|
parse_gen_block = `gen` blocks are not yet implemented
|
||||||
|
.help = only the keyword is reserved for now
|
||||||
|
|
||||||
parse_generic_args_in_pat_require_turbofish_syntax = generic args in patterns require the turbofish syntax
|
parse_generic_args_in_pat_require_turbofish_syntax = generic args in patterns require the turbofish syntax
|
||||||
|
|
||||||
parse_generic_parameters_without_angle_brackets = generic parameters without surrounding angle brackets
|
parse_generic_parameters_without_angle_brackets = generic parameters without surrounding angle brackets
|
||||||
|
|
|
@ -520,6 +520,14 @@ pub(crate) struct CatchAfterTry {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(parse_gen_block)]
|
||||||
|
#[help]
|
||||||
|
pub(crate) struct GenBlock {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(parse_comma_after_base_struct)]
|
#[diag(parse_comma_after_base_struct)]
|
||||||
#[note]
|
#[note]
|
||||||
|
|
|
@ -1422,6 +1422,9 @@ impl<'a> Parser<'a> {
|
||||||
} else if this.is_try_block() {
|
} else if this.is_try_block() {
|
||||||
this.expect_keyword(kw::Try)?;
|
this.expect_keyword(kw::Try)?;
|
||||||
this.parse_try_block(lo)
|
this.parse_try_block(lo)
|
||||||
|
} else if this.is_gen_block() {
|
||||||
|
this.expect_keyword(kw::Gen)?;
|
||||||
|
this.parse_gen_block(lo)
|
||||||
} else if this.eat_keyword(kw::Return) {
|
} else if this.eat_keyword(kw::Return) {
|
||||||
this.parse_expr_return()
|
this.parse_expr_return()
|
||||||
} else if this.eat_keyword(kw::Continue) {
|
} else if this.eat_keyword(kw::Continue) {
|
||||||
|
@ -3040,6 +3043,14 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parses a `gen {...}` expression (`gen` token already eaten).
|
||||||
|
fn parse_gen_block(&mut self, _span_lo: Span) -> PResult<'a, P<Expr>> {
|
||||||
|
let (_attrs, _body) = self.parse_inner_attrs_and_block()?;
|
||||||
|
|
||||||
|
Err(errors::GenBlock { span: self.prev_token.span }
|
||||||
|
.into_diagnostic(&self.sess.span_diagnostic))
|
||||||
|
}
|
||||||
|
|
||||||
fn is_do_catch_block(&self) -> bool {
|
fn is_do_catch_block(&self) -> bool {
|
||||||
self.token.is_keyword(kw::Do)
|
self.token.is_keyword(kw::Do)
|
||||||
&& self.is_keyword_ahead(1, &[kw::Catch])
|
&& self.is_keyword_ahead(1, &[kw::Catch])
|
||||||
|
@ -3059,6 +3070,13 @@ impl<'a> Parser<'a> {
|
||||||
&& self.token.uninterpolated_span().at_least_rust_2018()
|
&& self.token.uninterpolated_span().at_least_rust_2018()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_gen_block(&self) -> bool {
|
||||||
|
self.token.is_keyword(kw::Gen)
|
||||||
|
&& self
|
||||||
|
.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block())
|
||||||
|
&& self.token.uninterpolated_span().at_least_rust_2024()
|
||||||
|
}
|
||||||
|
|
||||||
/// Parses an `async move? {...}` expression.
|
/// Parses an `async move? {...}` expression.
|
||||||
fn parse_async_block(&mut self) -> PResult<'a, P<Expr>> {
|
fn parse_async_block(&mut self) -> PResult<'a, P<Expr>> {
|
||||||
let lo = self.token.span;
|
let lo = self.token.span;
|
||||||
|
|
|
@ -2297,9 +2297,9 @@ impl<'a> Parser<'a> {
|
||||||
// `pub` is added in case users got confused with the ordering like `async pub fn`,
|
// `pub` is added in case users got confused with the ordering like `async pub fn`,
|
||||||
// only if it wasn't preceded by `default` as `default pub` is invalid.
|
// only if it wasn't preceded by `default` as `default pub` is invalid.
|
||||||
let quals: &[Symbol] = if check_pub {
|
let quals: &[Symbol] = if check_pub {
|
||||||
&[kw::Pub, kw::Const, kw::Async, kw::Unsafe, kw::Extern]
|
&[kw::Pub, kw::Gen, kw::Const, kw::Async, kw::Unsafe, kw::Extern]
|
||||||
} else {
|
} else {
|
||||||
&[kw::Const, kw::Async, kw::Unsafe, kw::Extern]
|
&[kw::Gen, kw::Const, kw::Async, kw::Unsafe, kw::Extern]
|
||||||
};
|
};
|
||||||
self.check_keyword_case(kw::Fn, case) // Definitely an `fn`.
|
self.check_keyword_case(kw::Fn, case) // Definitely an `fn`.
|
||||||
// `$qual fn` or `$qual $qual`:
|
// `$qual fn` or `$qual $qual`:
|
||||||
|
@ -2353,6 +2353,9 @@ impl<'a> Parser<'a> {
|
||||||
let async_start_sp = self.token.span;
|
let async_start_sp = self.token.span;
|
||||||
let asyncness = self.parse_asyncness(case);
|
let asyncness = self.parse_asyncness(case);
|
||||||
|
|
||||||
|
let _gen_start_sp = self.token.span;
|
||||||
|
let genness = self.parse_genness(case);
|
||||||
|
|
||||||
let unsafe_start_sp = self.token.span;
|
let unsafe_start_sp = self.token.span;
|
||||||
let unsafety = self.parse_unsafety(case);
|
let unsafety = self.parse_unsafety(case);
|
||||||
|
|
||||||
|
@ -2368,6 +2371,10 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Gen::Yes { span, .. } = genness {
|
||||||
|
self.sess.emit_err(errors::GenBlock { span });
|
||||||
|
}
|
||||||
|
|
||||||
if !self.eat_keyword_case(kw::Fn, case) {
|
if !self.eat_keyword_case(kw::Fn, case) {
|
||||||
// It is possible for `expect_one_of` to recover given the contents of
|
// It is possible for `expect_one_of` to recover given the contents of
|
||||||
// `self.expected_tokens`, therefore, do not use `self.unexpected()` which doesn't
|
// `self.expected_tokens`, therefore, do not use `self.unexpected()` which doesn't
|
||||||
|
|
|
@ -11,6 +11,7 @@ mod stmt;
|
||||||
mod ty;
|
mod ty;
|
||||||
|
|
||||||
use crate::lexer::UnmatchedDelim;
|
use crate::lexer::UnmatchedDelim;
|
||||||
|
use ast::Gen;
|
||||||
pub use attr_wrapper::AttrWrapper;
|
pub use attr_wrapper::AttrWrapper;
|
||||||
pub use diagnostics::AttemptLocalParseRecovery;
|
pub use diagnostics::AttemptLocalParseRecovery;
|
||||||
pub(crate) use expr::ForbiddenLetReason;
|
pub(crate) use expr::ForbiddenLetReason;
|
||||||
|
@ -1126,6 +1127,16 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parses genness: `gen` or nothing.
|
||||||
|
fn parse_genness(&mut self, case: Case) -> Gen {
|
||||||
|
if self.token.span.at_least_rust_2024() && self.eat_keyword_case(kw::Gen, case) {
|
||||||
|
let span = self.prev_token.uninterpolated_span();
|
||||||
|
Gen::Yes { span, closure_id: DUMMY_NODE_ID, return_impl_trait_id: DUMMY_NODE_ID }
|
||||||
|
} else {
|
||||||
|
Gen::No
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Parses unsafety: `unsafe` or nothing.
|
/// Parses unsafety: `unsafe` or nothing.
|
||||||
fn parse_unsafety(&mut self, case: Case) -> Unsafe {
|
fn parse_unsafety(&mut self, case: Case) -> Unsafe {
|
||||||
if self.eat_keyword_case(kw::Unsafe, case) {
|
if self.eat_keyword_case(kw::Unsafe, case) {
|
||||||
|
|
|
@ -98,6 +98,7 @@ symbols! {
|
||||||
Builtin: "builtin",
|
Builtin: "builtin",
|
||||||
Catch: "catch",
|
Catch: "catch",
|
||||||
Default: "default",
|
Default: "default",
|
||||||
|
Gen: "gen",
|
||||||
MacroRules: "macro_rules",
|
MacroRules: "macro_rules",
|
||||||
Raw: "raw",
|
Raw: "raw",
|
||||||
Union: "union",
|
Union: "union",
|
||||||
|
@ -2188,8 +2189,9 @@ impl Symbol {
|
||||||
self >= kw::Abstract && self <= kw::Yield
|
self >= kw::Abstract && self <= kw::Yield
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_unused_keyword_conditional(self, edition: impl FnOnce() -> Edition) -> bool {
|
fn is_unused_keyword_conditional(self, edition: impl Copy + FnOnce() -> Edition) -> bool {
|
||||||
self == kw::Try && edition() >= Edition::Edition2018
|
self == kw::Try && edition().at_least_rust_2018()
|
||||||
|
|| self == kw::Gen && edition().at_least_rust_2024()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_reserved(self, edition: impl Copy + FnOnce() -> Edition) -> bool {
|
pub fn is_reserved(self, edition: impl Copy + FnOnce() -> Edition) -> bool {
|
||||||
|
|
10
tests/ui/coroutine/gen_block.e2024.stderr
Normal file
10
tests/ui/coroutine/gen_block.e2024.stderr
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
error: `gen` blocks are not yet implemented
|
||||||
|
--> $DIR/gen_block.rs:5:18
|
||||||
|
|
|
||||||
|
LL | let x = gen {};
|
||||||
|
| ^
|
||||||
|
|
|
||||||
|
= help: only the keyword is reserved for now
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
29
tests/ui/coroutine/gen_block.none.stderr
Normal file
29
tests/ui/coroutine/gen_block.none.stderr
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
error: expected identifier, found reserved keyword `yield`
|
||||||
|
--> $DIR/gen_block.rs:8:19
|
||||||
|
|
|
||||||
|
LL | let y = gen { yield 42 };
|
||||||
|
| --- ^^^^^ expected identifier, found reserved keyword
|
||||||
|
| |
|
||||||
|
| while parsing this struct
|
||||||
|
|
||||||
|
error[E0422]: cannot find struct, variant or union type `gen` in this scope
|
||||||
|
--> $DIR/gen_block.rs:5:13
|
||||||
|
|
|
||||||
|
LL | let x = gen {};
|
||||||
|
| ^^^ not found in this scope
|
||||||
|
|
||||||
|
error[E0422]: cannot find struct, variant or union type `gen` in this scope
|
||||||
|
--> $DIR/gen_block.rs:8:13
|
||||||
|
|
|
||||||
|
LL | let y = gen { yield 42 };
|
||||||
|
| ^^^ not found in this scope
|
||||||
|
|
||||||
|
error[E0422]: cannot find struct, variant or union type `gen` in this scope
|
||||||
|
--> $DIR/gen_block.rs:11:5
|
||||||
|
|
|
||||||
|
LL | gen {};
|
||||||
|
| ^^^ not found in this scope
|
||||||
|
|
||||||
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0422`.
|
13
tests/ui/coroutine/gen_block.rs
Normal file
13
tests/ui/coroutine/gen_block.rs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
// revisions: e2024 none
|
||||||
|
//[e2024] compile-flags: --edition 2024 -Zunstable-options
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let x = gen {};
|
||||||
|
//[none]~^ ERROR: cannot find
|
||||||
|
//[e2024]~^^ ERROR: `gen` blocks are not yet implemented
|
||||||
|
let y = gen { yield 42 };
|
||||||
|
//[none]~^ ERROR: found reserved keyword `yield`
|
||||||
|
//[none]~| ERROR: cannot find
|
||||||
|
gen {};
|
||||||
|
//[none]~^ ERROR: cannot find
|
||||||
|
}
|
10
tests/ui/coroutine/gen_fn.e2024.stderr
Normal file
10
tests/ui/coroutine/gen_fn.e2024.stderr
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
error: `gen` blocks are not yet implemented
|
||||||
|
--> $DIR/gen_fn.rs:4:1
|
||||||
|
|
|
||||||
|
LL | gen fn foo() {}
|
||||||
|
| ^^^
|
||||||
|
|
|
||||||
|
= help: only the keyword is reserved for now
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
8
tests/ui/coroutine/gen_fn.none.stderr
Normal file
8
tests/ui/coroutine/gen_fn.none.stderr
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
error: expected one of `#`, `async`, `const`, `default`, `extern`, `fn`, `pub`, `unsafe`, or `use`, found `gen`
|
||||||
|
--> $DIR/gen_fn.rs:4:1
|
||||||
|
|
|
||||||
|
LL | gen fn foo() {}
|
||||||
|
| ^^^ expected one of 9 possible tokens
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
8
tests/ui/coroutine/gen_fn.rs
Normal file
8
tests/ui/coroutine/gen_fn.rs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
// revisions: e2024 none
|
||||||
|
//[e2024] compile-flags: --edition 2024 -Zunstable-options
|
||||||
|
|
||||||
|
gen fn foo() {}
|
||||||
|
//[none]~^ ERROR: expected one of `#`, `async`, `const`, `default`, `extern`, `fn`, `pub`, `unsafe`, or `use`, found `gen`
|
||||||
|
//[e2024]~^^ ERROR: `gen` blocks are not yet implemented
|
||||||
|
|
||||||
|
fn main() {}
|
Loading…
Add table
Add a link
Reference in a new issue