-- 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 = :: 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 = :: 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 = :: int return r5 [case testListSum] 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 :: native_int r1 :: bit r2 :: native_int r3, r4, r5 :: bit r6 :: object r7, r8, r9, r10 :: int L0: sum = 0 i = 0 L1: r0 = i & 1 r1 = r0 != 0 if r1 goto L3 else goto L2 :: bool L2: r2 = l & 1 r3 = r2 != 0 if r3 goto L3 else goto L4 :: bool L3: r4 = CPyTagged_IsLt_(i, l) if r4 goto L5 else goto L10 :: bool L4: r5 = i < l :: signed if r5 goto L5 else goto L10 :: bool L5: r6 = CPyList_GetItemBorrow(a, i) if is_error(r6) goto L11 (error at sum:6) else goto L6 L6: r7 = unbox(int, r6) if is_error(r7) goto L11 (error at sum:6) else goto L7 L7: r8 = CPyTagged_Add(sum, r7) dec_ref sum :: int dec_ref r7 :: int sum = r8 r9 = CPyTagged_Add(i, 2) dec_ref i :: int i = r9 goto L1 L8: return sum L9: r10 = :: int return r10 L10: dec_ref i :: int goto L8 L11: dec_ref sum :: int dec_ref i :: int goto L9 [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, r9 :: object r10 :: bit r11 :: 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_CallFunctionObjArgs(r2, 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 = PyObject_CallFunctionObjArgs(r8, r5, 0) dec_ref r8 if is_error(r9) 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 r10 = CPy_KeepPropagating() if not r10 goto L9 else goto L7 :: bool L7: unreachable L8: return 1 L9: r11 = :: None return r11 L10: dec_ref r3 goto L8 L11: dec_ref r9 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, r14 :: object r15 :: bit r16 :: 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_CallFunctionObjArgs(r2, 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 = :: tuple[object, object, object] r7 = r6 goto L6 L5: r8 = :: 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 = PyObject_CallFunctionObjArgs(r13, r10, 0) dec_ref r13 if is_error(r14) 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: r15 = CPy_KeepPropagating() if not r15 goto L18 else goto L16 :: bool L16: unreachable L17: unreachable L18: r16 = :: str return r16 L19: dec_ref r3 goto L3 L20: xdec_ref r5 goto L13 L21: dec_ref r14 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 = :: object a = r0 r1 = :: 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 = :: 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 r10 :: None L0: r0 = :: str v = r0 r1 = 'a' inc_ref r1 u = r1 L1: if b goto L10 else goto L11 :: bool L2: r2 = 'b' inc_ref r2 v = r2 r3 = v == u r4 = r3 ^ 1 if r4 goto L11 else goto L1 :: bool L3: r5 = builtins :: module r6 = 'print' r7 = CPyObject_GetAttr(r5, r6) if is_error(r7) goto L12 (error at f:7) else goto L4 L4: if is_error(v) goto L13 else goto L7 L5: r8 = raise UnboundLocalError('local variable "v" referenced before assignment') if not r8 goto L9 (error at f:7) else goto L6 :: bool L6: unreachable L7: r9 = PyObject_CallFunctionObjArgs(r7, v, 0) dec_ref r7 xdec_ref v if is_error(r9) goto L9 (error at f:7) else goto L14 L8: return 1 L9: r10 = :: None return r10 L10: xdec_ref v goto L2 L11: dec_ref u goto L3 L12: xdec_ref v goto L9 L13: dec_ref r7 goto L5 L14: dec_ref r9 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 = :: i64 return r3 [case testExceptionWithNativeAttributeGetAndSet] 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 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 = :: 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 = :: 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:-1) else goto L4 :: bool L4: unreachable L5: return y L6: r6 = :: 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 = :: float return r5