Skip to content

Commit d32c4d3

Browse files
authored
Fix native parser crash caused by invalid assignment expression (#21882)
This came up when fuzz testing the native parser. Created using Claude Code.
1 parent 8b3e7d8 commit d32c4d3

2 files changed

Lines changed: 18 additions & 1 deletion

File tree

mypy/nativeparse.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1579,7 +1579,14 @@ def read_expression(state: State, data: ReadBuffer) -> Expression:
15791579
elif tag == nodes.ASSIGNMENT_EXPR:
15801580
target = read_expression(state, data)
15811581
value = read_expression(state, data)
1582-
assert isinstance(target, NameExpr), f"Expected NameExpr for target, got {type(target)}"
1582+
if not isinstance(target, NameExpr):
1583+
# The only valid target of ":=" is a plain name, but ruff's error
1584+
# recovery can produce other targets for invalid code such as
1585+
# "(f() := 1)". Ruff already reports a syntax error in this case, so
1586+
# here we just recover with a placeholder name instead of crashing.
1587+
placeholder = NameExpr("")
1588+
placeholder.set_line(target)
1589+
target = placeholder
15831590
expr = AssignmentExpr(target, value)
15841591
read_loc(data, expr)
15851592
expect_end_tag(data)

test-data/unit/native-parser.test

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2572,6 +2572,16 @@ MypyFile:1(
25722572
Block:3(
25732573
PassStmt:3())))
25742574

2575+
[case testSyntaxError10]
2576+
(f() := 1)
2577+
[out]
2578+
1:2: error: Assignment expression target must be an identifier
2579+
MypyFile:1(
2580+
ExpressionStmt:1(
2581+
AssignmentExpr:1(
2582+
NameExpr()
2583+
IntExpr(1))))
2584+
25752585
[case testArgConstructorTooManyArgs]
25762586
from typing import Callable
25772587
from mypy_extensions import Arg

0 commit comments

Comments
 (0)