Skip to content

Commit c4ecd2b

Browse files
authored
Fix a crash on walrus in comprehension at class scope (#14556)
Fixes #14201 The fix is trivial, turn an assert condition into a blocker error (with message matching Python syntax error). I also add a test case for a crash from the same issue that looks already fixed.
1 parent 6413aac commit c4ecd2b

File tree

3 files changed

+34
-0
lines changed

3 files changed

+34
-0
lines changed

mypy/semanal.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2658,8 +2658,33 @@ def visit_import_all(self, i: ImportAll) -> None:
26582658

26592659
def visit_assignment_expr(self, s: AssignmentExpr) -> None:
26602660
s.value.accept(self)
2661+
if self.is_func_scope():
2662+
if not self.check_valid_comprehension(s):
2663+
return
26612664
self.analyze_lvalue(s.target, escape_comprehensions=True, has_explicit_value=True)
26622665

2666+
def check_valid_comprehension(self, s: AssignmentExpr) -> bool:
2667+
"""Check that assignment expression is not nested within comprehension at class scope.
2668+
2669+
class C:
2670+
[(j := i) for i in [1, 2, 3]]
2671+
is a syntax error that is not enforced by Python parser, but at later steps.
2672+
"""
2673+
for i, is_comprehension in enumerate(reversed(self.is_comprehension_stack)):
2674+
if not is_comprehension and i < len(self.locals) - 1:
2675+
if self.locals[-1 - i] is None:
2676+
self.fail(
2677+
"Assignment expression within a comprehension"
2678+
" cannot be used in a class body",
2679+
s,
2680+
code=codes.SYNTAX,
2681+
serious=True,
2682+
blocker=True,
2683+
)
2684+
return False
2685+
break
2686+
return True
2687+
26632688
def visit_assignment_stmt(self, s: AssignmentStmt) -> None:
26642689
self.statement = s
26652690

test-data/unit/check-python38.test

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -734,3 +734,8 @@ class C(Generic[T]):
734734
[out]
735735
main:10: note: Revealed type is "builtins.int"
736736
main:10: note: Revealed type is "builtins.str"
737+
738+
[case testNoCrashOnAssignmentExprClass]
739+
class C:
740+
[(j := i) for i in [1, 2, 3]] # E: Assignment expression within a comprehension cannot be used in a class body
741+
[builtins fixtures/list.pyi]

test-data/unit/check-statements.test

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2194,3 +2194,7 @@ class B: pass
21942194

21952195
def foo(x: int) -> Union[Generator[A, None, None], Generator[B, None, None]]:
21962196
yield x # E: Incompatible types in "yield" (actual type "int", expected type "Union[A, B]")
2197+
2198+
[case testNoCrashOnStarRightHandSide]
2199+
x = *(1, 2, 3) # E: Can use starred expression only as assignment target
2200+
[builtins fixtures/tuple.pyi]

0 commit comments

Comments
 (0)