Skip to content

Commit 186e1cd

Browse files
authored
[mypyc] Fix crash when exception variable is captured by nested function (#22249)
Fixes mypyc/mypyc#1184. This crashed with "unexpected type DeletedType": ```python def f() -> None: try: raise RuntimeError() except RuntimeError as exc: fn = lambda: print(exc) ``` Mypy gives the variable of an except clause the type `DeletedType` after the except block, and this type is used when adding a captured variable to the environment class of the function. Now we map `DeletedType` to `object`.
1 parent e4840e7 commit 186e1cd

2 files changed

Lines changed: 33 additions & 0 deletions

File tree

‎mypyc/irbuild/mapper.py‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from mypy.types import (
77
AnyType,
88
CallableType,
9+
DeletedType,
910
Instance,
1011
LiteralType,
1112
NoneTyp,
@@ -166,6 +167,9 @@ def type_to_rtype(self, typ: Type | None) -> RType:
166167
elif isinstance(typ, (UninhabitedType, UnboundType)):
167168
# Sure, whatever!
168169
return object_rprimitive
170+
elif isinstance(typ, DeletedType):
171+
# The type of an exception variable after the except block, for example
172+
return object_rprimitive
169173

170174
# I think we've covered everything that is supposed to
171175
# actually show up, so anything else is a bug somewhere.

‎mypyc/test-data/run-exceptions.test‎

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -665,3 +665,32 @@ from typing import Any
665665
class OtherException(Exception):
666666
def __new__(cls) -> Any:
667667
return ValueError("other")
668+
669+
[case testExceptionVariableCapturedByNestedFunction]
670+
from typing import Callable, Iterator
671+
672+
def call(f: Callable[[], str]) -> str:
673+
return f()
674+
675+
def test_lambda() -> None:
676+
try:
677+
raise RuntimeError("x")
678+
except RuntimeError as exc:
679+
assert call(lambda: str(exc)) == "x"
680+
681+
def test_nested_function() -> None:
682+
try:
683+
raise ValueError("y")
684+
except Exception as exc:
685+
def f() -> str:
686+
return type(exc).__name__ + str(exc)
687+
assert call(f) == "ValueErrory"
688+
689+
def gen() -> Iterator[str]:
690+
try:
691+
raise KeyError("z")
692+
except KeyError as exc:
693+
yield call(lambda: repr(exc))
694+
695+
def test_generator() -> None:
696+
assert list(gen()) == ["KeyError('z')"]

0 commit comments

Comments
 (0)