Skip to content

Commit

Permalink
Detect assignment expressions before Python 3.8
Browse files Browse the repository at this point in the history
This PR is the first in a series derived from #16308, each of which add support
for detecting one version-related syntax error from #6591. This one should be
the largest because it also includes a couple of additional changes:
1. the `syntax_errors!` macro, which makes adding more variants a bit easier
2. the `Parser::add_unsupported_syntax_error` method

Otherwise I think the general structure will be the same for each syntax error:
* Detecting the error in the parser
* Inline parser tests for the new error
* New ruff CLI tests for the new error

Because of the second point here, this PR is currently stacked on #16357.

As noted above, there are new inline parser tests, as well as new ruff CLI
tests. Once #16379 is resolved, there should also be new mdtests for red-knot,
but this PR does not currently include those.
  • Loading branch information
ntBre committed Feb 26, 2025
1 parent 7fa1359 commit fecf010
Show file tree
Hide file tree
Showing 7 changed files with 176 additions and 3 deletions.
41 changes: 41 additions & 0 deletions crates/ruff/tests/lint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2628,6 +2628,47 @@ class A(Generic[T]):
);
}

#[test]
fn walrus_before_py38() {
// ok
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.args(STDIN_BASE_OPTIONS)
.args(["--stdin-filename", "test.py"])
.arg("--target-version=py38")
.arg("-")
.pass_stdin(r#"if x := 1: pass"#),
@r"
success: false
exit_code: 1
----- stdout -----
test.py:1:10: E701 Multiple statements on one line (colon)
Found 1 error.
----- stderr -----
"
);

// not ok on 3.7 with preview
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.args(STDIN_BASE_OPTIONS)
.args(["--stdin-filename", "test.py"])
.arg("--target-version=py37")
.arg("--preview")
.arg("-")
.pass_stdin(r#"if x := 1: pass"#),
@r"
success: false
exit_code: 1
----- stdout -----
test.py:1:4: SyntaxError: Cannot use named assignment expression (`:=`) on Python 3.7 (syntax was added in Python 3.8)
test.py:1:10: E701 Multiple statements on one line (colon)
Found 2 errors.
----- stderr -----
"
);
}

#[test]
fn match_before_py310() {
// ok on 3.10
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# parse_options: { "target_version": "3.7" }
if x := 1: ...
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# parse_options: { "target_version": "3.8" }
if x := 1: ...
1 change: 1 addition & 0 deletions crates/ruff_python_parser/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,7 @@ macro_rules! syntax_errors {

syntax_errors! {
(MatchBeforePy310, PY310, "`match` statement"),
(WalrusBeforePy38, PY38, "named assignment expression (`:=`)"),
}

#[cfg(target_pointer_width = "64")]
Expand Down
20 changes: 17 additions & 3 deletions crates/ruff_python_parser/src/parser/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use rustc_hash::{FxBuildHasher, FxHashSet};
use ruff_python_ast::name::Name;
use ruff_python_ast::{
self as ast, BoolOp, CmpOp, ConversionFlag, Expr, ExprContext, FStringElement, FStringElements,
IpyEscapeKind, Number, Operator, StringFlags, UnaryOp,
IpyEscapeKind, Number, Operator, PythonVersion, StringFlags, UnaryOp,
};
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};

Expand All @@ -16,7 +16,7 @@ use crate::parser::{helpers, FunctionKind, Parser};
use crate::string::{parse_fstring_literal_element, parse_string_literal, StringType};
use crate::token::{TokenKind, TokenValue};
use crate::token_set::TokenSet;
use crate::{FStringErrorType, Mode, ParseErrorType};
use crate::{FStringErrorType, Mode, ParseErrorType, UnsupportedSyntaxErrorKind};

use super::{FStringElementsKind, Parenthesized, RecoveryContextKind};

Expand Down Expand Up @@ -2161,10 +2161,24 @@ impl<'src> Parser<'src> {

let value = self.parse_conditional_expression_or_higher();

let range = self.node_range(start);

// test_err walrus_before_py38
// # parse_options: { "target_version": "3.7" }
// if x := 1: ...

// test_ok walrus_after_py38
// # parse_options: { "target_version": "3.8" }
// if x := 1: ...

if self.options.target_version < PythonVersion::PY38 {
self.add_unsupported_syntax_error(UnsupportedSyntaxErrorKind::WalrusBeforePy38, range);
}

ast::ExprNamed {
target: Box::new(target),
value: Box::new(value.expr),
range: self.node_range(start),
range,
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
---
source: crates/ruff_python_parser/tests/fixtures.rs
input_file: crates/ruff_python_parser/resources/inline/err/walrus_before_py38.py
---
## AST

```
Module(
ModModule {
range: 0..60,
body: [
If(
StmtIf {
range: 45..59,
test: Named(
ExprNamed {
range: 48..54,
target: Name(
ExprName {
range: 48..49,
id: Name("x"),
ctx: Store,
},
),
value: NumberLiteral(
ExprNumberLiteral {
range: 53..54,
value: Int(
1,
),
},
),
},
),
body: [
Expr(
StmtExpr {
range: 56..59,
value: EllipsisLiteral(
ExprEllipsisLiteral {
range: 56..59,
},
),
},
),
],
elif_else_clauses: [],
},
),
],
},
)
```
## Unsupported Syntax Errors

|
1 | # parse_options: { "target_version": "3.7" }
2 | if x := 1: ...
| ^^^^^^ Syntax Error: Cannot use named assignment expression (`:=`) on Python 3.7 (syntax was added in Python 3.8)
|
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
---
source: crates/ruff_python_parser/tests/fixtures.rs
input_file: crates/ruff_python_parser/resources/inline/ok/walrus_after_py38.py
---
## AST

```
Module(
ModModule {
range: 0..60,
body: [
If(
StmtIf {
range: 45..59,
test: Named(
ExprNamed {
range: 48..54,
target: Name(
ExprName {
range: 48..49,
id: Name("x"),
ctx: Store,
},
),
value: NumberLiteral(
ExprNumberLiteral {
range: 53..54,
value: Int(
1,
),
},
),
},
),
body: [
Expr(
StmtExpr {
range: 56..59,
value: EllipsisLiteral(
ExprEllipsisLiteral {
range: 56..59,
},
),
},
),
],
elif_else_clauses: [],
},
),
],
},
)
```

0 comments on commit fecf010

Please sign in to comment.