Skip to content

Commit

Permalink
Reserve gen keyword for gen {} blocks and gen fn in 2024 edition
Browse files Browse the repository at this point in the history
  • Loading branch information
oli-obk committed Oct 5, 2023
1 parent e293927 commit 7e1e1b5
Show file tree
Hide file tree
Showing 14 changed files with 138 additions and 4 deletions.
6 changes: 6 additions & 0 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2418,6 +2418,12 @@ pub enum Async {
No,
}

#[derive(Copy, Clone, Encodable, Decodable, Debug)]
pub enum Gen {
Yes { span: Span, closure_id: NodeId, return_impl_trait_id: NodeId },
No,
}

impl Async {
pub fn is_async(self) -> bool {
matches!(self, Async::Yes { .. })
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_ast/src/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ pub fn ident_can_begin_expr(name: Symbol, span: Span, is_raw: bool) -> bool {
kw::Continue,
kw::False,
kw::For,
kw::Gen,
kw::If,
kw::Let,
kw::Loop,
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_parse/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,9 @@ parse_found_expr_would_be_stmt = expected expression, found `{$token}`
parse_function_body_equals_expr = function body cannot be `= expression;`
.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_parameters_without_angle_brackets = generic parameters without surrounding angle brackets
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_parse/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,14 @@ pub(crate) struct CatchAfterTry {
pub span: Span,
}

#[derive(Diagnostic)]
#[diag(parse_gen_block)]
#[help]
pub(crate) struct GenBlock {
#[primary_span]
pub span: Span,
}

#[derive(Diagnostic)]
#[diag(parse_comma_after_base_struct)]
#[note]
Expand Down
18 changes: 18 additions & 0 deletions compiler/rustc_parse/src/parser/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1421,6 +1421,9 @@ impl<'a> Parser<'a> {
} else if this.is_try_block() {
this.expect_keyword(kw::Try)?;
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) {
this.parse_expr_return()
} else if this.eat_keyword(kw::Continue) {
Expand Down Expand Up @@ -2996,6 +2999,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 {
self.token.is_keyword(kw::Do)
&& self.is_keyword_ahead(1, &[kw::Catch])
Expand All @@ -3015,6 +3026,13 @@ impl<'a> Parser<'a> {
&& 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.
fn parse_async_block(&mut self) -> PResult<'a, P<Expr>> {
let lo = self.token.span;
Expand Down
11 changes: 9 additions & 2 deletions compiler/rustc_parse/src/parser/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2293,9 +2293,9 @@ impl<'a> Parser<'a> {
// `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.
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 {
&[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`.
// `$qual fn` or `$qual $qual`:
Expand Down Expand Up @@ -2349,6 +2349,9 @@ impl<'a> Parser<'a> {
let async_start_sp = self.token.span;
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 unsafety = self.parse_unsafety(case);

Expand All @@ -2364,6 +2367,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) {
// 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
Expand Down
11 changes: 11 additions & 0 deletions compiler/rustc_parse/src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ mod stmt;
mod ty;

use crate::lexer::UnmatchedDelim;
use ast::Gen;
pub use attr_wrapper::AttrWrapper;
pub use diagnostics::AttemptLocalParseRecovery;
pub(crate) use expr::ForbiddenLetReason;
Expand Down Expand Up @@ -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.
fn parse_unsafety(&mut self, case: Case) -> Unsafe {
if self.eat_keyword_case(kw::Unsafe, case) {
Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ symbols! {
Builtin: "builtin",
Catch: "catch",
Default: "default",
Gen: "gen",
MacroRules: "macro_rules",
Raw: "raw",
Union: "union",
Expand Down Expand Up @@ -2132,8 +2133,9 @@ impl Symbol {
self >= kw::Abstract && self <= kw::Yield
}

fn is_unused_keyword_conditional(self, edition: impl FnOnce() -> Edition) -> bool {
self == kw::Try && edition() >= Edition::Edition2018
fn is_unused_keyword_conditional(self, edition: impl Copy + FnOnce() -> Edition) -> bool {
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 {
Expand Down
10 changes: 10 additions & 0 deletions tests/ui/generator/gen_block.e2024.stderr
Original file line number Diff line number Diff line change
@@ -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 changes: 29 additions & 0 deletions tests/ui/generator/gen_block.none.stderr
Original file line number Diff line number Diff line change
@@ -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 changes: 13 additions & 0 deletions tests/ui/generator/gen_block.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 10 additions & 0 deletions tests/ui/generator/gen_fn.e2024.stderr
Original file line number Diff line number Diff line change
@@ -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 changes: 8 additions & 0 deletions tests/ui/generator/gen_fn.none.stderr
Original file line number Diff line number Diff line change
@@ -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 changes: 8 additions & 0 deletions tests/ui/generator/gen_fn.rs
Original file line number Diff line number Diff line change
@@ -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() {}

0 comments on commit 7e1e1b5

Please sign in to comment.