| -- Test cases for exception handling insertion transform. | |
| -- | |
| -- The result includes refcount handling since these two transforms interact. | |
| [case testListGetAndUnboxError] | |
| from typing import List | |
| def f(x: List[int]) -> int: | |
| return x[0] | |
| [out] | |
| def f(x): | |
| x :: list | |
| r0 :: object | |
| r1, r2 :: int | |
| L0: | |
| r0 = CPyList_GetItemShort(x, 0) | |
| if is_error(r0) goto L3 (error at f:3) else goto L1 | |
| L1: | |
| r1 = unbox(int, r0) | |
| dec_ref r0 | |
| if is_error(r1) goto L3 (error at f:3) else goto L2 | |
| L2: | |
| return r1 | |
| L3: | |
| r2 = <error> :: int | |
| return r2 | |
| [case testListAppendAndSetItemError] | |
| from typing import List | |
| def f(x: List[int], y: int, z: int) -> None: | |
| x.append(y) | |
| x[y] = z | |
| [out] | |
| def f(x, y, z): | |
| x :: list | |
| y, z :: int | |
| r0 :: object | |
| r1 :: i32 | |
| r2 :: bit | |
| r3 :: object | |
| r4 :: bit | |
| r5 :: None | |
| L0: | |
| inc_ref y :: int | |
| r0 = box(int, y) | |
| r1 = PyList_Append(x, r0) | |
| dec_ref r0 | |
| r2 = r1 >= 0 :: signed | |
| if not r2 goto L3 (error at f:3) else goto L1 :: bool | |
| L1: | |
| inc_ref z :: int | |
| r3 = box(int, z) | |
| r4 = CPyList_SetItem(x, y, r3) | |
| if not r4 goto L3 (error at f:4) else goto L2 :: bool | |
| L2: | |
| return 1 | |
| L3: | |
| r5 = <error> :: None | |
| return r5 | |
| [case testOptionalHandling] | |
| from typing import Optional | |
| class A: pass | |
| def f(x: Optional[A]) -> int: | |
| if x is None: | |
| return 1 | |
| if x is not None: | |
| return 2 | |
| return 3 | |
| [out] | |
| def f(x): | |
| x :: union[__main__.A, None] | |
| r0 :: object | |
| r1 :: bit | |
| r2 :: __main__.A | |
| r3 :: object | |
| r4 :: bit | |
| r5 :: int | |
| L0: | |
| r0 = load_address _Py_NoneStruct | |
| r1 = x == r0 | |
| if r1 goto L1 else goto L2 :: bool | |
| L1: | |
| return 2 | |
| L2: | |
| r2 = borrow cast(__main__.A, x) | |
| if is_error(r2) goto L6 (error at f:8) else goto L3 | |
| L3: | |
| r3 = load_address _Py_NoneStruct | |
| r4 = r2 != r3 | |
| if r4 goto L4 else goto L5 :: bool | |
| L4: | |
| return 4 | |
| L5: | |
| return 6 | |
| L6: | |
| r5 = <error> :: int | |
| return r5 | |
| [case testListSum_withgil] | |
| from typing import List | |
| def sum(a: List[int], l: int) -> int: | |
| sum = 0 | |
| i = 0 | |
| while i < l: | |
| sum = sum + a[i] | |
| i = i + 1 | |
| return sum | |
| [out] | |
| def sum(a, l): | |
| a :: list | |
| l, sum, i :: int | |
| r0 :: bit | |
| r1 :: object | |
| r2, r3, r4, r5 :: int | |
| L0: | |
| sum = 0 | |
| i = 0 | |
| L1: | |
| r0 = int_lt i, l | |
| if r0 goto L2 else goto L7 :: bool | |
| L2: | |
| r1 = CPyList_GetItemBorrow(a, i) | |
| if is_error(r1) goto L8 (error at sum:6) else goto L3 | |
| L3: | |
| r2 = unbox(int, r1) | |
| if is_error(r2) goto L8 (error at sum:6) else goto L4 | |
| L4: | |
| r3 = CPyTagged_Add(sum, r2) | |
| dec_ref sum :: int | |
| dec_ref r2 :: int | |
| sum = r3 | |
| r4 = CPyTagged_Add(i, 2) | |
| dec_ref i :: int | |
| i = r4 | |
| goto L1 | |
| L5: | |
| return sum | |
| L6: | |
| r5 = <error> :: int | |
| return r5 | |
| L7: | |
| dec_ref i :: int | |
| goto L5 | |
| L8: | |
| dec_ref sum :: int | |
| dec_ref i :: int | |
| goto L6 | |
| [case testTryExcept] | |
| def g() -> None: | |
| try: | |
| object() | |
| except: | |
| print("weeee") | |
| [out] | |
| def g(): | |
| r0 :: object | |
| r1 :: str | |
| r2, r3 :: object | |
| r4 :: tuple[object, object, object] | |
| r5 :: str | |
| r6 :: object | |
| r7 :: str | |
| r8 :: object | |
| r9 :: object[1] | |
| r10 :: object_ptr | |
| r11 :: object | |
| r12 :: bit | |
| r13 :: None | |
| L0: | |
| L1: | |
| r0 = builtins :: module | |
| r1 = 'object' | |
| r2 = CPyObject_GetAttr(r0, r1) | |
| if is_error(r2) goto L3 (error at g:3) else goto L2 | |
| L2: | |
| r3 = PyObject_Vectorcall(r2, 0, 0, 0) | |
| dec_ref r2 | |
| if is_error(r3) goto L3 (error at g:3) else goto L10 | |
| L3: | |
| r4 = CPy_CatchError() | |
| r5 = 'weeee' | |
| r6 = builtins :: module | |
| r7 = 'print' | |
| r8 = CPyObject_GetAttr(r6, r7) | |
| if is_error(r8) goto L6 (error at g:5) else goto L4 | |
| L4: | |
| r9 = [r5] | |
| r10 = load_address r9 | |
| r11 = PyObject_Vectorcall(r8, r10, 1, 0) | |
| dec_ref r8 | |
| if is_error(r11) goto L6 (error at g:5) else goto L11 | |
| L5: | |
| CPy_RestoreExcInfo(r4) | |
| dec_ref r4 | |
| goto L8 | |
| L6: | |
| CPy_RestoreExcInfo(r4) | |
| dec_ref r4 | |
| r12 = CPy_KeepPropagating() | |
| if not r12 goto L9 else goto L7 :: bool | |
| L7: | |
| unreachable | |
| L8: | |
| return 1 | |
| L9: | |
| r13 = <error> :: None | |
| return r13 | |
| L10: | |
| dec_ref r3 | |
| goto L8 | |
| L11: | |
| dec_ref r11 | |
| goto L5 | |
| [case testGenopsTryFinally] | |
| def a() -> str: | |
| try: | |
| print() | |
| return 'hi' | |
| finally: | |
| print('goodbye!') | |
| [out] | |
| def a(): | |
| r0 :: object | |
| r1 :: str | |
| r2, r3 :: object | |
| r4, r5 :: str | |
| r6, r7 :: tuple[object, object, object] | |
| r8 :: str | |
| r9 :: tuple[object, object, object] | |
| r10 :: str | |
| r11 :: object | |
| r12 :: str | |
| r13 :: object | |
| r14 :: object[1] | |
| r15 :: object_ptr | |
| r16 :: object | |
| r17 :: bit | |
| r18 :: str | |
| L0: | |
| L1: | |
| r0 = builtins :: module | |
| r1 = 'print' | |
| r2 = CPyObject_GetAttr(r0, r1) | |
| if is_error(r2) goto L5 (error at a:3) else goto L2 | |
| L2: | |
| r3 = PyObject_Vectorcall(r2, 0, 0, 0) | |
| dec_ref r2 | |
| if is_error(r3) goto L5 (error at a:3) else goto L19 | |
| L3: | |
| r4 = 'hi' | |
| inc_ref r4 | |
| r5 = r4 | |
| L4: | |
| r6 = <error> :: tuple[object, object, object] | |
| r7 = r6 | |
| goto L6 | |
| L5: | |
| r8 = <error> :: str | |
| r5 = r8 | |
| r9 = CPy_CatchError() | |
| r7 = r9 | |
| L6: | |
| r10 = 'goodbye!' | |
| r11 = builtins :: module | |
| r12 = 'print' | |
| r13 = CPyObject_GetAttr(r11, r12) | |
| if is_error(r13) goto L20 (error at a:6) else goto L7 | |
| L7: | |
| r14 = [r10] | |
| r15 = load_address r14 | |
| r16 = PyObject_Vectorcall(r13, r15, 1, 0) | |
| dec_ref r13 | |
| if is_error(r16) goto L20 (error at a:6) else goto L21 | |
| L8: | |
| if is_error(r7) goto L11 else goto L22 | |
| L9: | |
| CPy_Reraise() | |
| if not 0 goto L13 else goto L23 :: bool | |
| L10: | |
| unreachable | |
| L11: | |
| if is_error(r5) goto L17 else goto L12 | |
| L12: | |
| return r5 | |
| L13: | |
| if is_error(r7) goto L15 else goto L14 | |
| L14: | |
| CPy_RestoreExcInfo(r7) | |
| xdec_ref r7 | |
| L15: | |
| r17 = CPy_KeepPropagating() | |
| if not r17 goto L18 else goto L16 :: bool | |
| L16: | |
| unreachable | |
| L17: | |
| unreachable | |
| L18: | |
| r18 = <error> :: str | |
| return r18 | |
| L19: | |
| dec_ref r3 | |
| goto L3 | |
| L20: | |
| xdec_ref r5 | |
| goto L13 | |
| L21: | |
| dec_ref r16 | |
| goto L8 | |
| L22: | |
| xdec_ref r5 | |
| goto L9 | |
| L23: | |
| xdec_ref r7 | |
| goto L10 | |
| [case testDocstring1] | |
| def lol() -> None: | |
| """Hello""" | |
| pass | |
| [out] | |
| def lol(): | |
| L0: | |
| return 1 | |
| [case testExceptUndefined1] | |
| from typing import Any | |
| def lol(x: Any) -> object: | |
| try: | |
| st = x.foo | |
| except: | |
| return '' | |
| # No uninit check should be generated, since the exception branch always returns | |
| return st | |
| [out] | |
| def lol(x): | |
| x :: object | |
| r0 :: str | |
| r1, st :: object | |
| r2 :: tuple[object, object, object] | |
| r3 :: str | |
| L0: | |
| L1: | |
| r0 = 'foo' | |
| r1 = CPyObject_GetAttr(x, r0) | |
| if is_error(r1) goto L3 (error at lol:4) else goto L2 | |
| L2: | |
| st = r1 | |
| goto L4 | |
| L3: | |
| r2 = CPy_CatchError() | |
| r3 = '' | |
| CPy_RestoreExcInfo(r2) | |
| dec_ref r2 | |
| inc_ref r3 | |
| return r3 | |
| L4: | |
| return st | |
| [case testExceptUndefined2] | |
| from typing import Any | |
| def lol(x: Any) -> object: | |
| try: | |
| a = x.foo | |
| b = x.bar | |
| except: | |
| pass | |
| # uninit checks are needed, since the exception can skip initializing the vars | |
| return a + b | |
| [out] | |
| def lol(x): | |
| x, r0, a, r1, b :: object | |
| r2 :: str | |
| r3 :: object | |
| r4 :: str | |
| r5 :: object | |
| r6 :: tuple[object, object, object] | |
| r7, r8 :: bool | |
| r9, r10 :: object | |
| L0: | |
| r0 = <error> :: object | |
| a = r0 | |
| r1 = <error> :: object | |
| b = r1 | |
| L1: | |
| r2 = 'foo' | |
| r3 = CPyObject_GetAttr(x, r2) | |
| if is_error(r3) goto L4 (error at lol:4) else goto L15 | |
| L2: | |
| a = r3 | |
| r4 = 'bar' | |
| r5 = CPyObject_GetAttr(x, r4) | |
| if is_error(r5) goto L4 (error at lol:5) else goto L16 | |
| L3: | |
| b = r5 | |
| goto L6 | |
| L4: | |
| r6 = CPy_CatchError() | |
| L5: | |
| CPy_RestoreExcInfo(r6) | |
| dec_ref r6 | |
| L6: | |
| if is_error(a) goto L17 else goto L9 | |
| L7: | |
| r7 = raise UnboundLocalError('local variable "a" referenced before assignment') | |
| if not r7 goto L14 (error at lol:9) else goto L8 :: bool | |
| L8: | |
| unreachable | |
| L9: | |
| if is_error(b) goto L18 else goto L12 | |
| L10: | |
| r8 = raise UnboundLocalError('local variable "b" referenced before assignment') | |
| if not r8 goto L14 (error at lol:9) else goto L11 :: bool | |
| L11: | |
| unreachable | |
| L12: | |
| r9 = PyNumber_Add(a, b) | |
| xdec_ref a | |
| xdec_ref b | |
| if is_error(r9) goto L14 (error at lol:9) else goto L13 | |
| L13: | |
| return r9 | |
| L14: | |
| r10 = <error> :: object | |
| return r10 | |
| L15: | |
| xdec_ref a | |
| goto L2 | |
| L16: | |
| xdec_ref b | |
| goto L3 | |
| L17: | |
| xdec_ref b | |
| goto L7 | |
| L18: | |
| xdec_ref a | |
| goto L10 | |
| [case testMaybeUninitVarExc] | |
| def f(b: bool) -> None: | |
| u = 'a' | |
| while b: | |
| v = 'b' | |
| if v is not u: | |
| break | |
| print(v) | |
| [out] | |
| def f(b): | |
| b :: bool | |
| r0, v, r1, u, r2 :: str | |
| r3, r4 :: bit | |
| r5 :: object | |
| r6 :: str | |
| r7 :: object | |
| r8 :: bool | |
| r9 :: object[1] | |
| r10 :: object_ptr | |
| r11 :: object | |
| r12 :: bool | |
| r13 :: None | |
| L0: | |
| r0 = <error> :: str | |
| v = r0 | |
| r1 = 'a' | |
| inc_ref r1 | |
| u = r1 | |
| L1: | |
| if b goto L13 else goto L14 :: bool | |
| L2: | |
| r2 = 'b' | |
| inc_ref r2 | |
| v = r2 | |
| r3 = v == u | |
| r4 = r3 ^ 1 | |
| if r4 goto L14 else goto L1 :: bool | |
| L3: | |
| r5 = builtins :: module | |
| r6 = 'print' | |
| r7 = CPyObject_GetAttr(r5, r6) | |
| if is_error(r7) goto L15 (error at f:7) else goto L4 | |
| L4: | |
| if is_error(v) goto L16 else goto L7 | |
| L5: | |
| r8 = raise UnboundLocalError('local variable "v" referenced before assignment') | |
| if not r8 goto L12 (error at f:7) else goto L6 :: bool | |
| L6: | |
| unreachable | |
| L7: | |
| r9 = [v] | |
| r10 = load_address r9 | |
| r11 = PyObject_Vectorcall(r7, r10, 1, 0) | |
| dec_ref r7 | |
| if is_error(r11) goto L15 (error at f:7) else goto L17 | |
| L8: | |
| if is_error(v) goto L9 else goto L11 | |
| L9: | |
| r12 = raise UnboundLocalError('local variable "v" referenced before assignment') | |
| if not r12 goto L12 (error at f:7) else goto L10 :: bool | |
| L10: | |
| unreachable | |
| L11: | |
| xdec_ref v | |
| return 1 | |
| L12: | |
| r13 = <error> :: None | |
| return r13 | |
| L13: | |
| xdec_ref v | |
| goto L2 | |
| L14: | |
| dec_ref u | |
| goto L3 | |
| L15: | |
| xdec_ref v | |
| goto L12 | |
| L16: | |
| dec_ref r7 | |
| goto L5 | |
| L17: | |
| dec_ref r11 | |
| goto L8 | |
| [case testExceptionWithOverlappingErrorValue] | |
| from mypy_extensions import i64 | |
| def f() -> i64: | |
| return 0 | |
| def g() -> i64: | |
| return f() | |
| [out] | |
| def f(): | |
| L0: | |
| return 0 | |
| def g(): | |
| r0 :: i64 | |
| r1 :: bit | |
| r2 :: object | |
| r3 :: i64 | |
| L0: | |
| r0 = f() | |
| r1 = r0 == -113 | |
| if r1 goto L2 else goto L1 :: bool | |
| L1: | |
| return r0 | |
| L2: | |
| r2 = PyErr_Occurred() | |
| if not is_error(r2) goto L3 (error at g:7) else goto L1 | |
| L3: | |
| r3 = <error> :: i64 | |
| return r3 | |
| [case testExceptionWithNativeAttributeGetAndSet_withgil] | |
| class C: | |
| def __init__(self, x: int) -> None: | |
| self.x = x | |
| def foo(c: C, x: int) -> None: | |
| c.x = x - c.x | |
| [out] | |
| def C.__init__(self, x): | |
| self :: __main__.C | |
| x :: int | |
| L0: | |
| inc_ref x :: int | |
| self.x = x | |
| return 1 | |
| def foo(c, x): | |
| c :: __main__.C | |
| x, r0, r1 :: int | |
| r2 :: bool | |
| L0: | |
| r0 = borrow c.x | |
| r1 = CPyTagged_Subtract(x, r0) | |
| c.x = r1 | |
| return 1 | |
| [case testExceptionWithNativeAttributeGetAndSet_nogil] | |
| class C: | |
| def __init__(self, x: int) -> None: | |
| self.x = x | |
| def foo(c: C, x: int) -> None: | |
| c.x = x - c.x | |
| [out] | |
| def C.__init__(self, x): | |
| self :: __main__.C | |
| x :: int | |
| L0: | |
| inc_ref x :: int | |
| self.x = x | |
| return 1 | |
| def foo(c, x): | |
| c :: __main__.C | |
| x, r0, r1 :: int | |
| r2 :: bool | |
| L0: | |
| r0 = c.x | |
| r1 = CPyTagged_Subtract(x, r0) | |
| dec_ref r0 :: int | |
| c.x = r1 | |
| return 1 | |
| [case testExceptionWithOverlappingFloatErrorValue] | |
| def f() -> float: | |
| return 0.0 | |
| def g() -> float: | |
| return f() | |
| [out] | |
| def f(): | |
| L0: | |
| return 0.0 | |
| def g(): | |
| r0 :: float | |
| r1 :: bit | |
| r2 :: object | |
| r3 :: float | |
| L0: | |
| r0 = f() | |
| r1 = r0 == -113.0 | |
| if r1 goto L2 else goto L1 :: bool | |
| L1: | |
| return r0 | |
| L2: | |
| r2 = PyErr_Occurred() | |
| if not is_error(r2) goto L3 (error at g:5) else goto L1 | |
| L3: | |
| r3 = <error> :: float | |
| return r3 | |
| [case testExceptionWithLowLevelIntAttribute] | |
| from mypy_extensions import i32, i64 | |
| class C: | |
| def __init__(self, x: i32, y: i64) -> None: | |
| self.x = x | |
| self.y = y | |
| def f(c: C) -> None: | |
| c.x | |
| c.y | |
| [out] | |
| def C.__init__(self, x, y): | |
| self :: __main__.C | |
| x :: i32 | |
| y :: i64 | |
| L0: | |
| self.x = x | |
| self.y = y | |
| return 1 | |
| def f(c): | |
| c :: __main__.C | |
| r0 :: i32 | |
| r1 :: i64 | |
| L0: | |
| r0 = c.x | |
| r1 = c.y | |
| return 1 | |
| [case testConditionallyUndefinedI64] | |
| from mypy_extensions import i64 | |
| def f(x: i64) -> i64: | |
| if x: | |
| y: i64 = 2 | |
| return y | |
| [out] | |
| def f(x): | |
| x, r0, y :: i64 | |
| __locals_bitmap0 :: u32 | |
| r1 :: bit | |
| r2, r3 :: u32 | |
| r4 :: bit | |
| r5 :: bool | |
| r6 :: i64 | |
| L0: | |
| r0 = <error> :: i64 | |
| y = r0 | |
| __locals_bitmap0 = 0 | |
| r1 = x != 0 | |
| if r1 goto L1 else goto L2 :: bool | |
| L1: | |
| y = 2 | |
| r2 = __locals_bitmap0 | 1 | |
| __locals_bitmap0 = r2 | |
| L2: | |
| r3 = __locals_bitmap0 & 1 | |
| r4 = r3 == 0 | |
| if r4 goto L3 else goto L5 :: bool | |
| L3: | |
| r5 = raise UnboundLocalError('local variable "y" referenced before assignment') | |
| if not r5 goto L6 (error at f:6) else goto L4 :: bool | |
| L4: | |
| unreachable | |
| L5: | |
| return y | |
| L6: | |
| r6 = <error> :: i64 | |
| return r6 | |
| [case testExceptionWithFloatAttribute] | |
| class C: | |
| def __init__(self, x: float, y: float) -> None: | |
| self.x = x | |
| if x: | |
| self.y = y | |
| def f(c: C) -> float: | |
| return c.x + c.y | |
| [out] | |
| def C.__init__(self, x, y): | |
| self :: __main__.C | |
| x, y :: float | |
| r0 :: bit | |
| L0: | |
| self.x = x | |
| r0 = x != 0.0 | |
| if r0 goto L1 else goto L2 :: bool | |
| L1: | |
| self.y = y | |
| L2: | |
| return 1 | |
| def f(c): | |
| c :: __main__.C | |
| r0, r1 :: float | |
| r2 :: bit | |
| r3 :: float | |
| r4 :: object | |
| r5 :: float | |
| L0: | |
| r0 = c.x | |
| r1 = c.y | |
| r2 = r1 == -113.0 | |
| if r2 goto L2 else goto L1 :: bool | |
| L1: | |
| r3 = r0 + r1 | |
| return r3 | |
| L2: | |
| r4 = PyErr_Occurred() | |
| if not is_error(r4) goto L3 (error at f:8) else goto L1 | |
| L3: | |
| r5 = <error> :: float | |
| return r5 | |
| [case testVecI64Remove] | |
| from librt.vecs import vec, remove | |
| from mypy_extensions import i64 | |
| def f(v: vec[i64], i: i64, n: i64) -> None: | |
| v = remove(v, n) | |
| [out] | |
| def f(v, i, n): | |
| v :: vec[i64] | |
| i, n :: i64 | |
| r0 :: vec[i64] | |
| r1 :: None | |
| L0: | |
| inc_ref v | |
| r0 = VecI64Api.remove(v, n) | |
| if is_error(r0) goto L2 (error at f:5) else goto L1 | |
| L1: | |
| v = r0 | |
| dec_ref v | |
| return 1 | |
| L2: | |
| r1 = <error> :: None | |
| return r1 |