Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,62 @@ async def g():
(x async for x in g())
```

## Rebound comprehension variable

Walrus operators cannot rebind variables already in use as iterators:

```py
# error: [invalid-syntax] "assignment expression cannot rebind comprehension variable"
[x := 2 for x in range(10)]

# error: [invalid-syntax] "assignment expression cannot rebind comprehension variable"
{y := 5 for y in range(10)}
```

## Multiple case assignments

Variable names in pattern matching must be unique within a single pattern:

```toml
[environment]
python-version = "3.10"
```

```py
x = [1, 2]
match x:
# error: [invalid-syntax] "multiple assignments to name `a` in pattern"
case [a, a]:
pass
case _:
pass

d = {"key": "value"}
match d:
# error: [invalid-syntax] "multiple assignments to name `b` in pattern"
case {"key": b, "other": b}:
pass
```

## Duplicate type parameter

Type parameter names must be unique in a generic class or function definition:

```toml
[environment]
python-version = "3.12"
```

```py
# error: [invalid-syntax] "duplicate type parameter"
class C[T, T]:
pass

# error: [invalid-syntax] "duplicate type parameter"
def f[X, Y, X]():
pass
```

## `await` outside async function

This error includes `await`, `async for`, `async with`, and `async` comprehensions.
Expand Down
54 changes: 44 additions & 10 deletions crates/ruff_linter/src/linter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1006,19 +1006,22 @@ mod tests {
}

#[test_case(
"error_on_310",
"async_in_sync_error_on_310",
"async def f(): return [[x async for x in foo(n)] for n in range(3)]",
PythonVersion::PY310
PythonVersion::PY310,
"AsyncComprehensionOutsideAsyncFunction"
)]
#[test_case(
"okay_on_311",
"async_in_sync_okay_on_311",
"async def f(): return [[x async for x in foo(n)] for n in range(3)]",
PythonVersion::PY311
PythonVersion::PY311,
"AsyncComprehensionOutsideAsyncFunction"
)]
#[test_case(
"okay_on_310",
"async_in_sync_okay_on_310",
"async def test(): return [[x async for x in elements(n)] async for n in range(3)]",
PythonVersion::PY310
PythonVersion::PY310,
"AsyncComprehensionOutsideAsyncFunction"
)]
#[test_case(
"deferred_function_body",
Expand All @@ -1028,15 +1031,46 @@ mod tests {
def g(): ...
[x async for x in foo()]
",
PythonVersion::PY310
PythonVersion::PY310,
"AsyncComprehensionOutsideAsyncFunction"
)]
#[test_case("false_positive", "[x async for x in y]", PythonVersion::PY310)]
fn test_async_comprehension_in_sync_comprehension(
#[test_case(
"async_in_sync_false_positive",
"[x async for x in y]",
PythonVersion::PY310,
"AsyncComprehensionOutsideAsyncFunction"
)]
#[test_case(
"rebound_comprehension",
"[x:= 2 for x in range(2)]",
PythonVersion::PY310,
"ReboundComprehensionVariable"
)]
#[test_case(
"duplicate_type_param",
"class C[T, T]: pass",
PythonVersion::PY312,
"DuplicateTypeParameter"
)]
#[test_case(
"multiple_case_assignment",
"
match x:
case [a, a]:
pass
case _:
pass
",
PythonVersion::PY310,
"MultipleCaseAssignment"
)]
fn test_semantic_errors(
name: &str,
contents: &str,
python_version: PythonVersion,
error_type: &str,
) {
let snapshot = format!("async_comprehension_in_sync_comprehension_{name}_{python_version}");
let snapshot = format!("semantic_syntax_error_{error_type}_{name}_{python_version}");
let messages = test_snippet_syntax_errors(
contents,
&LinterSettings {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
---
source: crates/ruff_linter/src/linter.rs
---

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
source: crates/ruff_linter/src/linter.rs
---
<filename>:1:12: SyntaxError: duplicate type parameter
|
1 | class C[T, T]: pass
| ^
|
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
source: crates/ruff_linter/src/linter.rs
---
<filename>:3:14: SyntaxError: multiple assignments to name `a` in pattern
|
2 | match x:
3 | case [a, a]:
| ^
4 | pass
5 | case _:
|
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
source: crates/ruff_linter/src/linter.rs
---
<filename>:1:2: SyntaxError: assignment expression cannot rebind comprehension variable
|
1 | [x:= 2 for x in range(2)]
| ^
|
Loading