-- 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 :: int32 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