Skip to content

Commit 52b425b

Browse files
authored
[mypyc] Implement the walrus operator (#9624)
My assessment that this would not be too hard was accurate. Fixes mypyc/mypyc#765.
1 parent ecec8bb commit 52b425b

File tree

4 files changed

+62
-3
lines changed

4 files changed

+62
-3
lines changed

mypyc/irbuild/expression.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
ConditionalExpr, ComparisonExpr, IntExpr, FloatExpr, ComplexExpr, StrExpr,
1212
BytesExpr, EllipsisExpr, ListExpr, TupleExpr, DictExpr, SetExpr, ListComprehension,
1313
SetComprehension, DictionaryComprehension, SliceExpr, GeneratorExpr, CastExpr, StarExpr,
14+
AssignmentExpr,
1415
Var, RefExpr, MypyFile, TypeInfo, TypeApplication, LDEF, ARG_POS
1516
)
1617
from mypy.types import TupleType, get_proper_type, Instance
@@ -682,3 +683,10 @@ def transform_generator_expr(builder: IRBuilder, o: GeneratorExpr) -> Value:
682683
return builder.call_c(
683684
iter_op, [translate_list_comprehension(builder, o)], o.line
684685
)
686+
687+
688+
def transform_assignment_expr(builder: IRBuilder, o: AssignmentExpr) -> Value:
689+
value = builder.accept(o.value)
690+
target = builder.get_assignment_target(o.target)
691+
builder.assign(target, value, o.line)
692+
return value

mypyc/irbuild/visitor.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
transform_dictionary_comprehension,
7777
transform_slice_expr,
7878
transform_generator_expr,
79+
transform_assignment_expr,
7980
)
8081

8182

@@ -264,10 +265,8 @@ def visit_yield_from_expr(self, o: YieldFromExpr) -> Value:
264265
def visit_await_expr(self, o: AwaitExpr) -> Value:
265266
return transform_await_expr(self.builder, o)
266267

267-
# Unimplemented constructs
268-
269268
def visit_assignment_expr(self, o: AssignmentExpr) -> Value:
270-
self.bail("I Am The Walrus (unimplemented)", o.line)
269+
return transform_assignment_expr(self.builder, o)
271270

272271
# Unimplemented constructs that shouldn't come up because they are py2 only
273272

mypyc/test-data/run-python38.test

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
[case testWalrus1]
2+
from typing import Optional
3+
4+
def foo(x: int) -> Optional[int]:
5+
if x < 0:
6+
return None
7+
return x
8+
9+
def test(x: int) -> str:
10+
if (n := foo(x)) is not None:
11+
return str(x)
12+
else:
13+
return "<fail>"
14+
15+
[file driver.py]
16+
from native import test
17+
18+
assert test(10) == "10"
19+
assert test(-1) == "<fail>"
20+
21+
22+
[case testWalrus2]
23+
from typing import Optional, Tuple, List
24+
25+
class Node:
26+
def __init__(self, val: int, next: Optional['Node']) -> None:
27+
self.val = val
28+
self.next = next
29+
30+
def pairs(nobe: Optional[Node]) -> List[Tuple[int, int]]:
31+
if nobe is None:
32+
return []
33+
l = []
34+
while next := nobe.next:
35+
l.append((nobe.val, next.val))
36+
nobe = next
37+
return l
38+
39+
def make(l: List[int]) -> Optional[Node]:
40+
cur: Optional[Node] = None
41+
for x in reversed(l):
42+
cur = Node(x, cur)
43+
return cur
44+
45+
[file driver.py]
46+
from native import Node, make, pairs
47+
48+
assert pairs(make([1,2,3])) == [(1,2), (2,3)]
49+
assert pairs(make([1])) == []
50+
assert pairs(make([])) == []

mypyc/test/test_run.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@
5050
'run-bench.test',
5151
'run-mypy-sim.test',
5252
]
53+
if sys.version_info >= (3, 8):
54+
files.append('run-python38.test')
5355

5456
setup_format = """\
5557
from setuptools import setup

0 commit comments

Comments
 (0)