1
Fork 0

Auto merge of #83386 - mark-i-m:stabilize-pat2015, r=nikomatsakis

Stabilize `:pat_param` and remove `:pat2021`

Blocked on #83384

cc `@rust-lang/lang` #79278

If I understand `@nikomatsakis` in  https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/or.20patterns/near/231133873, another FCP is not needed.

r? `@nikomatsakis`
This commit is contained in:
bors 2021-04-28 20:35:17 +00:00
commit ca075d268d
15 changed files with 66 additions and 121 deletions

View file

@ -688,16 +688,12 @@ pub enum NonterminalKind {
Item, Item,
Block, Block,
Stmt, Stmt,
Pat2015 { PatParam {
/// Keep track of whether the user used `:pat2015` or `:pat` and we inferred it from the /// Keep track of whether the user used `:pat_param` or `:pat` and we inferred it from the
/// edition of the span. This is used for diagnostics.
inferred: bool,
},
Pat2021 {
/// Keep track of whether the user used `:pat2015` or `:pat` and we inferred it from the
/// edition of the span. This is used for diagnostics. /// edition of the span. This is used for diagnostics.
inferred: bool, inferred: bool,
}, },
PatWithOr,
Expr, Expr,
Ty, Ty,
Ident, Ident,
@ -722,12 +718,11 @@ impl NonterminalKind {
sym::stmt => NonterminalKind::Stmt, sym::stmt => NonterminalKind::Stmt,
sym::pat => match edition() { sym::pat => match edition() {
Edition::Edition2015 | Edition::Edition2018 => { Edition::Edition2015 | Edition::Edition2018 => {
NonterminalKind::Pat2015 { inferred: true } NonterminalKind::PatParam { inferred: true }
} }
Edition::Edition2021 => NonterminalKind::Pat2021 { inferred: true }, Edition::Edition2021 => NonterminalKind::PatWithOr,
}, },
sym::pat2015 => NonterminalKind::Pat2015 { inferred: false }, sym::pat_param => NonterminalKind::PatParam { inferred: false },
sym::pat2021 => NonterminalKind::Pat2021 { inferred: false },
sym::expr => NonterminalKind::Expr, sym::expr => NonterminalKind::Expr,
sym::ty => NonterminalKind::Ty, sym::ty => NonterminalKind::Ty,
sym::ident => NonterminalKind::Ident, sym::ident => NonterminalKind::Ident,
@ -745,10 +740,8 @@ impl NonterminalKind {
NonterminalKind::Item => sym::item, NonterminalKind::Item => sym::item,
NonterminalKind::Block => sym::block, NonterminalKind::Block => sym::block,
NonterminalKind::Stmt => sym::stmt, NonterminalKind::Stmt => sym::stmt,
NonterminalKind::Pat2015 { inferred: false } => sym::pat2015, NonterminalKind::PatParam { inferred: false } => sym::pat_param,
NonterminalKind::Pat2021 { inferred: false } => sym::pat2021, NonterminalKind::PatParam { inferred: true } | NonterminalKind::PatWithOr => sym::pat,
NonterminalKind::Pat2015 { inferred: true }
| NonterminalKind::Pat2021 { inferred: true } => sym::pat,
NonterminalKind::Expr => sym::expr, NonterminalKind::Expr => sym::expr,
NonterminalKind::Ty => sym::ty, NonterminalKind::Ty => sym::ty,
NonterminalKind::Ident => sym::ident, NonterminalKind::Ident => sym::ident,

View file

@ -955,15 +955,15 @@ fn check_matcher_core(
if let TokenTree::MetaVarDecl(span, name, Some(kind)) = *token { if let TokenTree::MetaVarDecl(span, name, Some(kind)) = *token {
for next_token in &suffix_first.tokens { for next_token in &suffix_first.tokens {
// Check if the old pat is used and the next token is `|`. // Check if the old pat is used and the next token is `|`.
if let NonterminalKind::Pat2015 { inferred: true } = kind { if let NonterminalKind::PatParam { inferred: true } = kind {
if let TokenTree::Token(token) = next_token { if let TokenTree::Token(token) = next_token {
if let BinOp(token) = token.kind { if let BinOp(token) = token.kind {
if let token::BinOpToken::Or = token { if let token::BinOpToken::Or = token {
// It is suggestion to use pat2015, for example: $x:pat -> $x:pat2015. // It is suggestion to use pat_param, for example: $x:pat -> $x:pat_param.
let suggestion = quoted_tt_to_string(&TokenTree::MetaVarDecl( let suggestion = quoted_tt_to_string(&TokenTree::MetaVarDecl(
span, span,
name, name,
Some(NonterminalKind::Pat2015 { inferred: false }), Some(NonterminalKind::PatParam { inferred: false }),
)); ));
sess.buffer_lint_with_diagnostic( sess.buffer_lint_with_diagnostic(
&OR_PATTERNS_BACK_COMPAT, &OR_PATTERNS_BACK_COMPAT,
@ -1105,7 +1105,7 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
_ => IsInFollow::No(TOKENS), _ => IsInFollow::No(TOKENS),
} }
} }
NonterminalKind::Pat2015 { .. } => { NonterminalKind::PatParam { .. } => {
const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`|`", "`if`", "`in`"]; const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`|`", "`if`", "`in`"];
match tok { match tok {
TokenTree::Token(token) => match token.kind { TokenTree::Token(token) => match token.kind {
@ -1116,7 +1116,7 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
_ => IsInFollow::No(TOKENS), _ => IsInFollow::No(TOKENS),
} }
} }
NonterminalKind::Pat2021 { .. } => { NonterminalKind::PatWithOr { .. } => {
const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`if`", "`in`"]; const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`if`", "`in`"];
match tok { match tok {
TokenTree::Token(token) => match token.kind { TokenTree::Token(token) => match token.kind {

View file

@ -6,8 +6,8 @@ use rustc_ast::tokenstream;
use rustc_ast::{NodeId, DUMMY_NODE_ID}; use rustc_ast::{NodeId, DUMMY_NODE_ID};
use rustc_ast_pretty::pprust; use rustc_ast_pretty::pprust;
use rustc_feature::Features; use rustc_feature::Features;
use rustc_session::parse::{feature_err, ParseSess}; use rustc_session::parse::ParseSess;
use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::symbol::{kw, Ident};
use rustc_span::Span; use rustc_span::Span;
@ -62,21 +62,6 @@ pub(super) fn parse(
Some((frag, _)) => { Some((frag, _)) => {
let span = token.span.with_lo(start_sp.lo()); let span = token.span.with_lo(start_sp.lo());
match frag.name {
sym::pat2015 | sym::pat2021 => {
if !features.edition_macro_pats {
feature_err(
sess,
sym::edition_macro_pats,
frag.span,
"`pat2015` and `pat2021` are unstable.",
)
.emit();
}
}
_ => {}
}
let kind = let kind =
token::NonterminalKind::from_symbol(frag.name, || { token::NonterminalKind::from_symbol(frag.name, || {
span.edition() span.edition()

View file

@ -607,9 +607,6 @@ declare_features! (
/// Allows arbitrary expressions in key-value attributes at parse time. /// Allows arbitrary expressions in key-value attributes at parse time.
(active, extended_key_value_attributes, "1.50.0", Some(78835), None), (active, extended_key_value_attributes, "1.50.0", Some(78835), None),
/// `:pat2015` and `:pat2021` macro matchers.
(active, edition_macro_pats, "1.51.0", Some(54883), None),
/// Allows const generics to have default values (e.g. `struct Foo<const N: usize = 3>(...);`). /// Allows const generics to have default values (e.g. `struct Foo<const N: usize = 3>(...);`).
(active, const_generics_defaults, "1.51.0", Some(44580), None), (active, const_generics_defaults, "1.51.0", Some(44580), None),

View file

@ -710,7 +710,7 @@ pub trait LintContext: Sized {
db.note(&note); db.note(&note);
} }
BuiltinLintDiagnostics::OrPatternsBackCompat(span,suggestion) => { BuiltinLintDiagnostics::OrPatternsBackCompat(span,suggestion) => {
db.span_suggestion(span, "use pat2015 to preserve semantics", suggestion, Applicability::MachineApplicable); db.span_suggestion(span, "use pat_param to preserve semantics", suggestion, Applicability::MachineApplicable);
} }
} }
// Rewrap `db`, and pass control to the user. // Rewrap `db`, and pass control to the user.

View file

@ -61,7 +61,8 @@ impl<'a> Parser<'a> {
}, },
_ => false, _ => false,
}, },
NonterminalKind::Pat2015 { .. } | NonterminalKind::Pat2021 { .. } => match token.kind { NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr { .. } => {
match token.kind {
token::Ident(..) | // box, ref, mut, and other identifiers (can stricten) token::Ident(..) | // box, ref, mut, and other identifiers (can stricten)
token::OpenDelim(token::Paren) | // tuple pattern token::OpenDelim(token::Paren) | // tuple pattern
token::OpenDelim(token::Bracket) | // slice pattern token::OpenDelim(token::Bracket) | // slice pattern
@ -75,10 +76,11 @@ impl<'a> Parser<'a> {
token::Lt | // path (UFCS constant) token::Lt | // path (UFCS constant)
token::BinOp(token::Shl) => true, // path (double UFCS) token::BinOp(token::Shl) => true, // path (double UFCS)
// leading vert `|` or-pattern // leading vert `|` or-pattern
token::BinOp(token::Or) => matches!(kind, NonterminalKind::Pat2021 {..}), token::BinOp(token::Or) => matches!(kind, NonterminalKind::PatWithOr {..}),
token::Interpolated(ref nt) => may_be_ident(nt), token::Interpolated(ref nt) => may_be_ident(nt),
_ => false, _ => false,
}, }
}
NonterminalKind::Lifetime => match token.kind { NonterminalKind::Lifetime => match token.kind {
token::Lifetime(_) => true, token::Lifetime(_) => true,
token::Interpolated(ref nt) => { token::Interpolated(ref nt) => {
@ -118,10 +120,10 @@ impl<'a> Parser<'a> {
return Err(self.struct_span_err(self.token.span, "expected a statement")); return Err(self.struct_span_err(self.token.span, "expected a statement"));
} }
}, },
NonterminalKind::Pat2015 { .. } | NonterminalKind::Pat2021 { .. } => { NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr { .. } => {
token::NtPat(self.collect_tokens_no_attrs(|this| match kind { token::NtPat(self.collect_tokens_no_attrs(|this| match kind {
NonterminalKind::Pat2015 { .. } => this.parse_pat_no_top_alt(None), NonterminalKind::PatParam { .. } => this.parse_pat_no_top_alt(None),
NonterminalKind::Pat2021 { .. } => { NonterminalKind::PatWithOr { .. } => {
this.parse_pat_allow_top_alt(None, RecoverComma::No) this.parse_pat_allow_top_alt(None, RecoverComma::No)
} }
_ => unreachable!(), _ => unreachable!(),

View file

@ -853,8 +853,7 @@ symbols! {
partial_ord, partial_ord,
passes, passes,
pat, pat,
pat2015, pat_param,
pat2021,
path, path,
pattern_parentheses, pattern_parentheses,
phantom_data, phantom_data,

View file

@ -1,8 +0,0 @@
// Feature gate test for `edition_macro_pats` feature.
macro_rules! foo {
($x:pat2015) => {}; //~ERROR `pat2015` and `pat2021` are unstable
($x:pat2021) => {}; //~ERROR `pat2015` and `pat2021` are unstable
}
fn main() {}

View file

@ -1,21 +0,0 @@
error[E0658]: `pat2015` and `pat2021` are unstable.
--> $DIR/feature-gate-edition_macro_pats.rs:4:9
|
LL | ($x:pat2015) => {};
| ^^^^^^^
|
= note: see issue #54883 <https://github.com/rust-lang/rust/issues/54883> for more information
= help: add `#![feature(edition_macro_pats)]` to the crate attributes to enable
error[E0658]: `pat2015` and `pat2021` are unstable.
--> $DIR/feature-gate-edition_macro_pats.rs:5:9
|
LL | ($x:pat2021) => {};
| ^^^^^^^
|
= note: see issue #54883 <https://github.com/rust-lang/rust/issues/54883> for more information
= help: add `#![feature(edition_macro_pats)]` to the crate attributes to enable
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0658`.

View file

@ -1,10 +1,9 @@
// run-pass // run-pass
// edition:2021
#![feature(edition_macro_pats)]
macro_rules! foo { macro_rules! foo {
(a $x:pat2015) => {}; (a $x:pat_param) => {};
(b $x:pat2021) => {}; (b $x:pat) => {};
} }
fn main() { fn main() {

View file

@ -1,15 +1,14 @@
// run-rustfix // run-rustfix
#![feature(edition_macro_pats)]
#![deny(or_patterns_back_compat)] #![deny(or_patterns_back_compat)]
#![allow(unused_macros)] #![allow(unused_macros)]
macro_rules! foo { ($x:pat2015 | $y:pat) => {} } //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro macro_rules! foo { ($x:pat_param | $y:pat) => {} } //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
macro_rules! bar { ($($x:pat2015)+ | $($y:pat)+) => {} } //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro macro_rules! bar { ($($x:pat_param)+ | $($y:pat)+) => {} } //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
macro_rules! baz { ($x:pat2015 | $y:pat2015) => {} } // should be ok macro_rules! baz { ($x:pat_param | $y:pat_param) => {} } // should be ok
macro_rules! qux { ($x:pat2015 | $y:pat) => {} } // should be ok macro_rules! qux { ($x:pat_param | $y:pat) => {} } // should be ok
macro_rules! ogg { ($x:pat2015 | $y:pat2015) => {} } //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro macro_rules! ogg { ($x:pat_param | $y:pat_param) => {} } //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
macro_rules! match_any { macro_rules! match_any {
( $expr:expr , $( $( $pat:pat2015 )|+ => $expr_arm:expr ),+ ) => { //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro ( $expr:expr , $( $( $pat:pat_param )|+ => $expr_arm:expr ),+ ) => { //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
match $expr { match $expr {
$( $(
$( $pat => $expr_arm, )+ $( $pat => $expr_arm, )+

View file

@ -1,13 +1,12 @@
// run-rustfix // run-rustfix
#![feature(edition_macro_pats)]
#![deny(or_patterns_back_compat)] #![deny(or_patterns_back_compat)]
#![allow(unused_macros)] #![allow(unused_macros)]
macro_rules! foo { ($x:pat | $y:pat) => {} } //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro macro_rules! foo { ($x:pat | $y:pat) => {} } //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
macro_rules! bar { ($($x:pat)+ | $($y:pat)+) => {} } //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro macro_rules! bar { ($($x:pat)+ | $($y:pat)+) => {} } //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
macro_rules! baz { ($x:pat2015 | $y:pat2015) => {} } // should be ok macro_rules! baz { ($x:pat_param | $y:pat_param) => {} } // should be ok
macro_rules! qux { ($x:pat2015 | $y:pat) => {} } // should be ok macro_rules! qux { ($x:pat_param | $y:pat) => {} } // should be ok
macro_rules! ogg { ($x:pat | $y:pat2015) => {} } //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro macro_rules! ogg { ($x:pat | $y:pat_param) => {} } //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
macro_rules! match_any { macro_rules! match_any {
( $expr:expr , $( $( $pat:pat )|+ => $expr_arm:expr ),+ ) => { //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro ( $expr:expr , $( $( $pat:pat )|+ => $expr_arm:expr ),+ ) => { //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
match $expr { match $expr {

View file

@ -1,32 +1,32 @@
error: the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro error: the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
--> $DIR/macro-or-patterns-back-compat.rs:6:21 --> $DIR/macro-or-patterns-back-compat.rs:5:21
| |
LL | macro_rules! foo { ($x:pat | $y:pat) => {} } LL | macro_rules! foo { ($x:pat | $y:pat) => {} }
| ^^^^^^ help: use pat2015 to preserve semantics: `$x:pat2015` | ^^^^^^ help: use pat_param to preserve semantics: `$x:pat_param`
| |
note: the lint level is defined here note: the lint level is defined here
--> $DIR/macro-or-patterns-back-compat.rs:4:9 --> $DIR/macro-or-patterns-back-compat.rs:3:9
| |
LL | #![deny(or_patterns_back_compat)] LL | #![deny(or_patterns_back_compat)]
| ^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^
error: the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro error: the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
--> $DIR/macro-or-patterns-back-compat.rs:7:23 --> $DIR/macro-or-patterns-back-compat.rs:6:23
| |
LL | macro_rules! bar { ($($x:pat)+ | $($y:pat)+) => {} } LL | macro_rules! bar { ($($x:pat)+ | $($y:pat)+) => {} }
| ^^^^^^ help: use pat2015 to preserve semantics: `$x:pat2015` | ^^^^^^ help: use pat_param to preserve semantics: `$x:pat_param`
error: the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro error: the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
--> $DIR/macro-or-patterns-back-compat.rs:10:21 --> $DIR/macro-or-patterns-back-compat.rs:9:21
| |
LL | macro_rules! ogg { ($x:pat | $y:pat2015) => {} } LL | macro_rules! ogg { ($x:pat | $y:pat_param) => {} }
| ^^^^^^ help: use pat2015 to preserve semantics: `$x:pat2015` | ^^^^^^ help: use pat_param to preserve semantics: `$x:pat_param`
error: the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro error: the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
--> $DIR/macro-or-patterns-back-compat.rs:12:26 --> $DIR/macro-or-patterns-back-compat.rs:11:26
| |
LL | ( $expr:expr , $( $( $pat:pat )|+ => $expr_arm:expr ),+ ) => { LL | ( $expr:expr , $( $( $pat:pat )|+ => $expr_arm:expr ),+ ) => {
| ^^^^^^^^ help: use pat2015 to preserve semantics: `$pat:pat2015` | ^^^^^^^^ help: use pat_param to preserve semantics: `$pat:pat_param`
error: aborting due to 4 previous errors error: aborting due to 4 previous errors

View file

@ -1,11 +1,12 @@
#![feature(edition_macro_pats)] // edition:2021
#![allow(unused_macros)] #![allow(unused_macros)]
macro_rules! foo { ($x:pat2021 | $y:pat2021) => {} } //~ ERROR `$x:pat2021` is followed by `|`, which is not allowed for `pat2021` fragments macro_rules! foo { ($x:pat | $y:pat) => {} } //~ ERROR `$x:pat` is followed by `|`, which is not allowed for `pat` fragments
macro_rules! baz { ($x:pat2015 | $y:pat2015) => {} } // should be ok macro_rules! baz { ($x:pat_param | $y:pat_param) => {} } // should be ok
macro_rules! qux { ($x:pat2015 | $y:pat2021) => {} } // should be ok macro_rules! qux { ($x:pat_param | $y:pat) => {} } // should be ok
macro_rules! ogg { ($x:pat2021 | $y:pat2015) => {} } //~ ERROR `$x:pat2021` is followed by `|`, which is not allowed for `pat2021` fragments macro_rules! ogg { ($x:pat | $y:pat_param) => {} } //~ ERROR `$x:pat` is followed by `|`, which is not allowed for `pat` fragments
macro_rules! match_any { macro_rules! match_any {
( $expr:expr , $( $( $pat:pat2021 )|+ => $expr_arm:pat2021 ),+ ) => { //~ ERROR `$pat:pat2021` may be followed by `|`, which is not allowed for `pat2021` fragments ( $expr:expr , $( $( $pat:pat)|+ => $expr_arm:pat),+ ) => { //~ ERROR `$pat:pat` may be followed by `|`, which is not allowed for `pat` fragments
match $expr { match $expr {
$( $(
$( $pat => $expr_arm, )+ $( $pat => $expr_arm, )+

View file

@ -1,24 +1,24 @@
error: `$x:pat2021` is followed by `|`, which is not allowed for `pat2021` fragments error: `$x:pat` is followed by `|`, which is not allowed for `pat` fragments
--> $DIR/macro-pat2021-pattern-followed-by-or.rs:3:32 --> $DIR/macro-pat2021-pattern-followed-by-or.rs:4:28
| |
LL | macro_rules! foo { ($x:pat2021 | $y:pat2021) => {} } LL | macro_rules! foo { ($x:pat | $y:pat) => {} }
| ^ not allowed after `pat2021` fragments | ^ not allowed after `pat` fragments
| |
= note: allowed there are: `=>`, `,`, `=`, `if` or `in` = note: allowed there are: `=>`, `,`, `=`, `if` or `in`
error: `$x:pat2021` is followed by `|`, which is not allowed for `pat2021` fragments error: `$x:pat` is followed by `|`, which is not allowed for `pat` fragments
--> $DIR/macro-pat2021-pattern-followed-by-or.rs:6:32 --> $DIR/macro-pat2021-pattern-followed-by-or.rs:7:28
| |
LL | macro_rules! ogg { ($x:pat2021 | $y:pat2015) => {} } LL | macro_rules! ogg { ($x:pat | $y:pat_param) => {} }
| ^ not allowed after `pat2021` fragments | ^ not allowed after `pat` fragments
| |
= note: allowed there are: `=>`, `,`, `=`, `if` or `in` = note: allowed there are: `=>`, `,`, `=`, `if` or `in`
error: `$pat:pat2021` may be followed by `|`, which is not allowed for `pat2021` fragments error: `$pat:pat` may be followed by `|`, which is not allowed for `pat` fragments
--> $DIR/macro-pat2021-pattern-followed-by-or.rs:8:40 --> $DIR/macro-pat2021-pattern-followed-by-or.rs:9:35
| |
LL | ( $expr:expr , $( $( $pat:pat2021 )|+ => $expr_arm:pat2021 ),+ ) => { LL | ( $expr:expr , $( $( $pat:pat)|+ => $expr_arm:pat),+ ) => {
| ^ not allowed after `pat2021` fragments | ^ not allowed after `pat` fragments
| |
= note: allowed there are: `=>`, `,`, `=`, `if` or `in` = note: allowed there are: `=>`, `,`, `=`, `if` or `in`