-- Test cases for reference count insertion. [case testReturnLiteral] def f() -> int: return 1 [out] def f(): L0: return 2 [case testReturnLocal] def f() -> int: x = 1 return x [out] def f(): x :: int L0: x = 2 return x [case testLocalVars] def f() -> int: x = 1 y = x x = y return x [out] def f(): x, y :: int L0: x = 2 y = x x = y return x [case testLocalVars2] def f() -> int: x = 1 y = x z = x return y + z [out] def f(): x, y, z, r0 :: int L0: x = 2 inc_ref x :: int y = x z = x r0 = CPyTagged_Add(y, z) dec_ref y :: int dec_ref z :: int return r0 [case testFreeAtReturn] def f() -> int: x = 1 y = 2 if x == 1: return x return y [out] def f(): x, y :: int r0 :: bit L0: x = 2 y = 4 r0 = x == 2 if r0 goto L3 else goto L4 :: bool L1: return x L2: return y L3: dec_ref y :: int goto L1 L4: dec_ref x :: int goto L2 [case testArgumentsInOps] def f(a: int, b: int) -> int: x = a + 1 y = x + a return y [out] def f(a, b): a, b, r0, x, r1, y :: int L0: r0 = CPyTagged_Add(a, 2) x = r0 r1 = CPyTagged_Add(x, a) dec_ref x :: int y = r1 return y [case testArgumentsInAssign] def f(a: int) -> int: x = a y = a x = 1 return x + y [out] def f(a): a, x, y, r0 :: int L0: inc_ref a :: int x = a dec_ref x :: int inc_ref a :: int y = a x = 2 r0 = CPyTagged_Add(x, y) dec_ref x :: int dec_ref y :: int return r0 [case testAssignToArgument1] def f(a: int) -> int: a = 1 y = a return y [out] def f(a): a, y :: int L0: a = 2 y = a return y [case testAssignToArgument2] def f(a: int) -> int: a = 1 a = 2 a = 3 return a [out] def f(a): a :: int L0: a = 2 dec_ref a :: int a = 4 dec_ref a :: int a = 6 return a [case testAssignToArgument3] def f(a: int) -> int: x = 1 a = x y = x return a [out] def f(a): a, x, y :: int L0: x = 2 inc_ref x :: int a = x y = x dec_ref y :: int return a [case testReturnArgument] def f(a: int) -> int: return a [out] def f(a): a :: int L0: inc_ref a :: int return a [case testConditionalAssignToArgument1] def f(a: int) -> int: if a == a: a = 1 else: x = 2 y = a + 1 return y [out] def f(a): a :: int r0 :: native_int r1, r2, r3 :: bit x, r4, y :: int L0: r0 = a & 1 r1 = r0 != 0 if r1 goto L1 else goto L2 :: bool L1: r2 = CPyTagged_IsEq_(a, a) if r2 goto L3 else goto L4 :: bool L2: r3 = a == a if r3 goto L3 else goto L4 :: bool L3: a = 2 goto L5 L4: x = 4 dec_ref x :: int goto L6 L5: r4 = CPyTagged_Add(a, 2) dec_ref a :: int y = r4 return y L6: inc_ref a :: int goto L5 [case testConditionalAssignToArgument2] def f(a: int) -> int: if a == a: x = 2 else: a = 1 y = a + 1 return y [out] def f(a): a :: int r0 :: native_int r1, r2, r3 :: bit x, r4, y :: int L0: r0 = a & 1 r1 = r0 != 0 if r1 goto L1 else goto L2 :: bool L1: r2 = CPyTagged_IsEq_(a, a) if r2 goto L3 else goto L4 :: bool L2: r3 = a == a if r3 goto L3 else goto L4 :: bool L3: x = 4 dec_ref x :: int goto L6 L4: a = 2 L5: r4 = CPyTagged_Add(a, 2) dec_ref a :: int y = r4 return y L6: inc_ref a :: int goto L5 [case testConditionalAssignToArgument3] def f(a: int) -> int: if a == a: a = 1 return a [out] def f(a): a :: int r0 :: native_int r1, r2, r3 :: bit L0: r0 = a & 1 r1 = r0 != 0 if r1 goto L1 else goto L2 :: bool L1: r2 = CPyTagged_IsEq_(a, a) if r2 goto L3 else goto L5 :: bool L2: r3 = a == a if r3 goto L3 else goto L5 :: bool L3: a = 2 L4: return a L5: inc_ref a :: int goto L4 [case testAssignRegisterToItself] def f(a: int) -> int: a = a x = 1 x = x return x + a -- This is correct but bad code [out] def f(a): a, x, r0 :: int L0: inc_ref a :: int a = a x = 2 inc_ref x :: int dec_ref x :: int x = x r0 = CPyTagged_Add(x, a) dec_ref x :: int dec_ref a :: int return r0 [case testIncrement1] def f(a: int) -> int: a = a + 1 x = 1 x = x + 1 return a + x [out] def f(a): a, r0, x, r1, r2 :: int L0: r0 = CPyTagged_Add(a, 2) a = r0 x = 2 r1 = CPyTagged_Add(x, 2) dec_ref x :: int x = r1 r2 = CPyTagged_Add(a, x) dec_ref a :: int dec_ref x :: int return r2 [case testIncrement2] def f() -> None: x = 1 x = x + 1 [out] def f(): x, r0 :: int L0: x = 2 r0 = CPyTagged_Add(x, 2) dec_ref x :: int x = r0 dec_ref x :: int return 1 [case testAdd1] def f() -> None: y = 1 x = y + 1 [out] def f(): y, r0, x :: int L0: y = 2 r0 = CPyTagged_Add(y, 2) dec_ref y :: int x = r0 dec_ref x :: int return 1 [case testAdd2] def f(a: int) -> int: a = a + a x = a x = x + x return x [out] def f(a): a, r0, x, r1 :: int L0: r0 = CPyTagged_Add(a, a) a = r0 x = a r1 = CPyTagged_Add(x, x) dec_ref x :: int x = r1 return x [case testAdd3] def f(a: int) -> int: x = a + a y = x + x return y [out] def f(a): a, r0, x, r1, y :: int L0: r0 = CPyTagged_Add(a, a) x = r0 r1 = CPyTagged_Add(x, x) dec_ref x :: int y = r1 return y [case testAdd4] def f(a: int) -> None: x = a + a y = 1 z = y + y [out] def f(a): a, r0, x, y, r1, z :: int L0: r0 = CPyTagged_Add(a, a) x = r0 dec_ref x :: int y = 2 r1 = CPyTagged_Add(y, y) dec_ref y :: int z = r1 dec_ref z :: int return 1 [case testAdd5] def f(a: int) -> None: a = a + a x = 1 x = x + x [out] def f(a): a, r0, x, r1 :: int L0: r0 = CPyTagged_Add(a, a) a = r0 dec_ref a :: int x = 2 r1 = CPyTagged_Add(x, x) dec_ref x :: int x = r1 dec_ref x :: int return 1 [case testReturnInMiddleOfFunction] def f() -> int: x = 1 y = 2 z = 3 if z == z: return z a = 1 return x + y - a [out] def f(): x, y, z :: int r0 :: native_int r1, r2, r3 :: bit a, r4, r5 :: int L0: x = 2 y = 4 z = 6 r0 = z & 1 r1 = r0 != 0 if r1 goto L1 else goto L2 :: bool L1: r2 = CPyTagged_IsEq_(z, z) if r2 goto L5 else goto L6 :: bool L2: r3 = z == z if r3 goto L5 else goto L6 :: bool L3: return z L4: a = 2 r4 = CPyTagged_Add(x, y) dec_ref x :: int dec_ref y :: int r5 = CPyTagged_Subtract(r4, a) dec_ref r4 :: int dec_ref a :: int return r5 L5: dec_ref x :: int dec_ref y :: int goto L3 L6: dec_ref z :: int goto L4 [case testLoop] def f(a: int) -> int: sum = 0 i = 0 while i <= a: sum = sum + i i = i + 1 return sum [out] def f(a): a, sum, i :: int r0 :: native_int r1 :: bit r2 :: native_int r3, r4, r5 :: bit r6, r7 :: int L0: sum = 0 i = 0 L1: r0 = i & 1 r1 = r0 != 0 if r1 goto L3 else goto L2 :: bool L2: r2 = a & 1 r3 = r2 != 0 if r3 goto L3 else goto L4 :: bool L3: r4 = CPyTagged_IsLt_(a, i) if r4 goto L7 else goto L5 :: bool L4: r5 = i <= a :: signed if r5 goto L5 else goto L7 :: bool L5: r6 = CPyTagged_Add(sum, i) dec_ref sum :: int sum = r6 r7 = CPyTagged_Add(i, 2) dec_ref i :: int i = r7 goto L1 L6: return sum L7: dec_ref i :: int goto L6 [case testCall] def f(a: int) -> int: return f(a + 1) [out] def f(a): a, r0, r1 :: int L0: r0 = CPyTagged_Add(a, 2) r1 = f(r0) dec_ref r0 :: int return r1 [case testError] def f(x: List[int]) -> None: pass # E: Name "List" is not defined \ # N: Did you forget to import it from "typing"? (Suggestion: "from typing import List") [case testNewList] def f() -> int: a = [0, 1] return 0 [out] def f(): r0 :: list r1, r2 :: object r3, r4, r5 :: ptr a :: list L0: r0 = PyList_New(2) r1 = object 0 r2 = object 1 r3 = get_element_ptr r0 ob_item :: PyListObject r4 = load_mem r3 :: ptr* inc_ref r1 set_mem r4, r1 :: builtins.object* r5 = r4 + WORD_SIZE*1 inc_ref r2 set_mem r5, r2 :: builtins.object* a = r0 dec_ref a return 0 [case testListSet] from typing import List def f(a: List[int], b: List[int]) -> None: a[0] = b[0] [out] def f(a, b): a, b :: list r0 :: object r1 :: int r2 :: object r3 :: bit L0: r0 = CPyList_GetItemShort(b, 0) r1 = unbox(int, r0) dec_ref r0 r2 = box(int, r1) r3 = CPyList_SetItem(a, 0, r2) return 1 [case testTupleRefcount] from typing import Tuple def f(x: Tuple[Tuple[int, bool], bool]) -> int: return x[0][0] [out] def f(x): x :: tuple[tuple[int, bool], bool] r0 :: tuple[int, bool] r1 :: int L0: r0 = x[0] r1 = r0[0] dec_ref r0 return r1 [case testUserClassRefCount] class C: x: 'C' def f() -> None: c = C() c.x = C() [out] def f(): r0, c, r1 :: __main__.C r2 :: bool L0: r0 = C() c = r0 r1 = C() c.x = r1; r2 = is_error dec_ref c return 1 [case testCastRefCount] class C: pass def f() -> None: a = [C()] d = a[0] [out] def f(): r0 :: __main__.C r1 :: list r2, r3 :: ptr a :: list r4 :: object r5, d :: __main__.C L0: r0 = C() r1 = PyList_New(1) r2 = get_element_ptr r1 ob_item :: PyListObject r3 = load_mem r2 :: ptr* set_mem r3, r0 :: builtins.object* a = r1 r4 = CPyList_GetItemShort(a, 0) dec_ref a r5 = cast(__main__.C, r4) d = r5 dec_ref d return 1 [case testUnaryBranchSpecialCase] def f(x: bool) -> int: if x: return 1 return 2 [out] def f(x): x :: bool L0: if x goto L1 else goto L2 :: bool L1: return 2 L2: return 4 [case testUnicodeLiteral] def f() -> str: return "some string" [out] def f(): r0 :: str L0: r0 = 'some string' inc_ref r0 return r0 [case testPyMethodCall] def g(x: str) -> int: return int(x, base=2) [out] def g(x): x :: str r0 :: object r1 :: str r2 :: tuple r3 :: object r4 :: dict r5 :: object r6 :: int L0: r0 = load_address PyLong_Type r1 = 'base' r2 = PyTuple_Pack(1, x) r3 = object 2 r4 = CPyDict_Build(1, r1, r3) r5 = PyObject_Call(r0, r2, r4) dec_ref r2 dec_ref r4 r6 = unbox(int, r5) dec_ref r5 return r6 [case testListAppend] from typing import List def f(a: List[int], x: int) -> None: a.append(x) [out] def f(a, x): a :: list x :: int r0 :: object r1 :: int32 r2 :: bit L0: inc_ref x :: int r0 = box(int, x) r1 = PyList_Append(a, r0) dec_ref r0 r2 = r1 >= 0 :: signed return 1 [case testForDict] from typing import Dict def f(d: Dict[int, int]) -> None: for key in d: d[key] [out] def f(d): d :: dict r0 :: short_int r1 :: native_int r2 :: short_int r3 :: object r4 :: tuple[bool, short_int, object] r5 :: short_int r6 :: bool r7 :: object r8, key :: int r9, r10 :: object r11 :: int r12, r13 :: bit L0: r0 = 0 r1 = PyDict_Size(d) r2 = r1 << 1 r3 = CPyDict_GetKeysIter(d) L1: r4 = CPyDict_NextKey(r3, r0) r5 = r4[1] r0 = r5 r6 = r4[0] if r6 goto L2 else goto L6 :: bool L2: r7 = r4[2] dec_ref r4 r8 = unbox(int, r7) dec_ref r7 key = r8 r9 = box(int, key) r10 = CPyDict_GetItem(d, r9) dec_ref r9 r11 = unbox(int, r10) dec_ref r10 dec_ref r11 :: int L3: r12 = CPyDict_CheckSize(d, r2) goto L1 L4: r13 = CPy_NoErrOccured() L5: return 1 L6: dec_ref r3 dec_ref r4 goto L4 [case testBorrowRefs] def make_garbage(arg: object) -> None: b = True while b: arg = None b = False [out] def make_garbage(arg): arg :: object b :: bool r0 :: object L0: b = 1 L1: if b goto L2 else goto L3 :: bool L2: r0 = box(None, 1) inc_ref r0 arg = r0 dec_ref arg b = 0 goto L1 L3: return 1 [case testGetElementPtrLifeTime] from typing import List def f() -> int: x: List[str] = [] return len(x) [out] def f(): r0, x :: list r1 :: ptr r2 :: native_int r3 :: short_int L0: r0 = PyList_New(0) x = r0 r1 = get_element_ptr x ob_size :: PyVarObject r2 = load_mem r1 :: native_int* dec_ref x r3 = r2 << 1 return r3 [case testSometimesUninitializedVariable] def f(x: bool) -> int: if x: y = 1 else: z = 2 return y + z [out] def f(x): x :: bool r0, y, r1, z :: int r2, r3 :: bool r4 :: int L0: r0 = :: int y = r0 r1 = :: int z = r1 if x goto L8 else goto L9 :: bool L1: y = 2 goto L3 L2: z = 4 L3: if is_error(y) goto L10 else goto L5 L4: r2 = raise UnboundLocalError('local variable "y" referenced before assignment') unreachable L5: if is_error(z) goto L11 else goto L7 L6: r3 = raise UnboundLocalError('local variable "z" referenced before assignment') unreachable L7: r4 = CPyTagged_Add(y, z) xdec_ref y :: int xdec_ref z :: int return r4 L8: xdec_ref y :: int goto L1 L9: xdec_ref z :: int goto L2 L10: xdec_ref z :: int goto L4 L11: xdec_ref y :: int goto L6 [case testVectorcall_python3_8] from typing import Any def call(f: Any, x: int) -> int: return f(x) [out] def call(f, x): f :: object x :: int r0 :: object r1 :: object[1] r2 :: object_ptr r3 :: object r4 :: int L0: inc_ref x :: int r0 = box(int, x) r1 = [r0] r2 = load_address r1 r3 = _PyObject_Vectorcall(f, r2, 1, 0) dec_ref r0 r4 = unbox(int, r3) dec_ref r3 return r4 [case testVectorcallMethod_python3_9_64bit] from typing import Any def call(o: Any, x: int) -> int: return o.m(x) [out] def call(o, x): o :: object x :: int r0 :: str r1 :: object r2 :: object[2] r3 :: object_ptr r4 :: object r5 :: int L0: r0 = 'm' inc_ref x :: int r1 = box(int, x) r2 = [o, r1] r3 = load_address r2 r4 = PyObject_VectorcallMethod(r0, r3, 9223372036854775810, 0) dec_ref r1 r5 = unbox(int, r4) dec_ref r4 return r5 [case testBorrowAttribute] def g() -> int: d = D() return d.c.x def f(d: D) -> int: return d.c.x class C: x: int class D: c: C [out] def g(): r0, d :: __main__.D r1 :: __main__.C r2 :: int L0: r0 = D() d = r0 r1 = borrow d.c r2 = r1.x dec_ref d return r2 def f(d): d :: __main__.D r0 :: __main__.C r1 :: int L0: r0 = borrow d.c r1 = r0.x return r1 [case testBorrowAttributeTwice] def f(e: E) -> int: return e.d.c.x class C: x: int class D: c: C class E: d: D [out] def f(e): e :: __main__.E r0 :: __main__.D r1 :: __main__.C r2 :: int L0: r0 = borrow e.d r1 = borrow r0.c r2 = r1.x return r2 [case testBorrowAttributeIsNone] from typing import Optional def f(c: C) -> bool: return c.x is not None def g(c: C) -> bool: return c.x is None class C: x: Optional[str] [out] def f(c): c :: __main__.C r0 :: union[str, None] r1 :: object r2 :: bit L0: r0 = borrow c.x r1 = load_address _Py_NoneStruct r2 = r0 != r1 return r2 def g(c): c :: __main__.C r0 :: union[str, None] r1 :: object r2 :: bit L0: r0 = borrow c.x r1 = load_address _Py_NoneStruct r2 = r0 == r1 return r2 [case testBorrowAttributeNarrowOptional] from typing import Optional def f(c: C) -> bool: if c.x is not None: return c.x.b return False class C: x: Optional[D] class D: b: bool [out] def f(c): c :: __main__.C r0 :: union[__main__.D, None] r1 :: object r2 :: bit r3 :: union[__main__.D, None] r4 :: __main__.D r5 :: bool L0: r0 = borrow c.x r1 = load_address _Py_NoneStruct r2 = r0 != r1 if r2 goto L1 else goto L2 :: bool L1: r3 = borrow c.x r4 = borrow cast(__main__.D, r3) r5 = r4.b return r5 L2: return 0 [case testBorrowLenArgument] from typing import List def f(x: C) -> int: return len(x.a) class C: a: List[str] [out] def f(x): x :: __main__.C r0 :: list r1 :: ptr r2 :: native_int r3 :: short_int L0: r0 = borrow x.a r1 = get_element_ptr r0 ob_size :: PyVarObject r2 = load_mem r1 :: native_int* r3 = r2 << 1 return r3 [case testBorrowIsinstanceArgument] from typing import List def f(x: C) -> bool: if isinstance(x.a, D): return x.a.b else: return True class C: a: object class D: b: bool [out] def f(x): x :: __main__.C r0, r1 :: object r2 :: ptr r3 :: object r4 :: bit r5 :: object r6 :: __main__.D r7 :: bool L0: r0 = borrow x.a r1 = __main__.D :: type r2 = get_element_ptr r0 ob_type :: PyObject r3 = load_mem r2 :: builtins.object* r4 = r3 == r1 if r4 goto L1 else goto L2 :: bool L1: r5 = borrow x.a r6 = borrow cast(__main__.D, r5) r7 = r6.b return r7 L2: return 1 [case testBorrowListGetItem1] from typing import List def literal_index(x: C) -> str: return x.a[0] def negative_index(x: C) -> str: return x.a[-1] def lvar_index(x: C, n: int) -> str: return x.a[n] class C: a: List[str] [out] def literal_index(x): x :: __main__.C r0 :: list r1 :: object r2 :: str L0: r0 = borrow x.a r1 = CPyList_GetItemShort(r0, 0) r2 = cast(str, r1) return r2 def negative_index(x): x :: __main__.C r0 :: list r1 :: object r2 :: str L0: r0 = borrow x.a r1 = CPyList_GetItemShort(r0, -2) r2 = cast(str, r1) return r2 def lvar_index(x, n): x :: __main__.C n :: int r0 :: list r1 :: object r2 :: str L0: r0 = borrow x.a r1 = CPyList_GetItem(r0, n) r2 = cast(str, r1) return r2 [case testBorrowListGetItem2] from typing import List def attr_before_index(x: C) -> str: return x.a[x.n] def attr_after_index(a: List[C], i: int) -> int: return a[i].n def attr_after_index_literal(a: List[C]) -> int: return a[0].n class C: a: List[str] n: int [out] def attr_before_index(x): x :: __main__.C r0 :: list r1 :: int r2 :: object r3 :: str L0: r0 = borrow x.a r1 = borrow x.n r2 = CPyList_GetItem(r0, r1) r3 = cast(str, r2) return r3 def attr_after_index(a, i): a :: list i :: int r0 :: object r1 :: __main__.C r2 :: int L0: r0 = CPyList_GetItemBorrow(a, i) r1 = borrow cast(__main__.C, r0) r2 = r1.n return r2 def attr_after_index_literal(a): a :: list r0 :: object r1 :: __main__.C r2 :: int L0: r0 = CPyList_GetItemShortBorrow(a, 0) r1 = borrow cast(__main__.C, r0) r2 = r1.n return r2 [case testCannotBorrowListGetItem] from typing import List def func_index(x: C) -> str: return x.a[f()] def f() -> int: return 0 class C: a: List[str] [out] def func_index(x): x :: __main__.C r0 :: list r1 :: int r2 :: object r3 :: str L0: r0 = x.a r1 = f() r2 = CPyList_GetItem(r0, r1) dec_ref r0 dec_ref r1 :: int r3 = cast(str, r2) return r3 def f(): L0: return 0 [case testBorrowListGetItemKeepAlive] from typing import List def f() -> str: a = [C()] return a[0].s class C: s: str [out] def f(): r0 :: __main__.C r1 :: list r2, r3 :: ptr a :: list r4 :: object r5 :: __main__.C r6 :: str L0: r0 = C() r1 = PyList_New(1) r2 = get_element_ptr r1 ob_item :: PyListObject r3 = load_mem r2 :: ptr* set_mem r3, r0 :: builtins.object* a = r1 r4 = CPyList_GetItemShortBorrow(a, 0) r5 = borrow cast(__main__.C, r4) r6 = r5.s dec_ref a return r6 [case testBorrowSetAttrObject] from typing import Optional def f(x: Optional[C]) -> None: if x is not None: x.b = True def g(x: D) -> None: x.c.b = False class C: b: bool class D: c: C [out] def f(x): x :: union[__main__.C, None] r0 :: object r1 :: bit r2 :: __main__.C r3 :: bool L0: r0 = load_address _Py_NoneStruct r1 = x != r0 if r1 goto L1 else goto L2 :: bool L1: r2 = borrow cast(__main__.C, x) r2.b = 1; r3 = is_error L2: return 1 def g(x): x :: __main__.D r0 :: __main__.C r1 :: bool L0: r0 = borrow x.c r0.b = 0; r1 = is_error return 1 [case testBorrowIntEquality] def add(c: C) -> bool: return c.x == c.y class C: x: int y: int [out] def add(c): c :: __main__.C r0, r1 :: int r2 :: native_int r3, r4 :: bit r5 :: bool r6 :: bit L0: r0 = borrow c.x r1 = borrow c.y r2 = r0 & 1 r3 = r2 == 0 if r3 goto L1 else goto L2 :: bool L1: r4 = r0 == r1 r5 = r4 goto L3 L2: r6 = CPyTagged_IsEq_(r0, r1) r5 = r6 L3: return r5 [case testBorrowIntLessThan] def add(c: C) -> bool: return c.x < c.y class C: x: int y: int [out] def add(c): c :: __main__.C r0, r1 :: int r2 :: native_int r3 :: bit r4 :: native_int r5, r6, r7 :: bit r8 :: bool r9 :: bit L0: r0 = borrow c.x r1 = borrow c.y r2 = r0 & 1 r3 = r2 == 0 r4 = r1 & 1 r5 = r4 == 0 r6 = r3 & r5 if r6 goto L1 else goto L2 :: bool L1: r7 = r0 < r1 :: signed r8 = r7 goto L3 L2: r9 = CPyTagged_IsLt_(r0, r1) r8 = r9 L3: return r8 [case testBorrowIntCompareFinal] from typing_extensions import Final X: Final = 10 def add(c: C) -> bool: return c.x == X class C: x: int [out] def add(c): c :: __main__.C r0 :: int r1 :: native_int r2, r3 :: bit r4 :: bool r5 :: bit L0: r0 = borrow c.x r1 = r0 & 1 r2 = r1 == 0 if r2 goto L1 else goto L2 :: bool L1: r3 = r0 == 20 r4 = r3 goto L3 L2: r5 = CPyTagged_IsEq_(r0, 20) r4 = r5 L3: return r4 [case testBorrowIntArithmetic] def add(c: C) -> int: return c.x + c.y def sub(c: C) -> int: return c.x - c.y class C: x: int y: int [out] def add(c): c :: __main__.C r0, r1, r2 :: int L0: r0 = borrow c.x r1 = borrow c.y r2 = CPyTagged_Add(r0, r1) return r2 def sub(c): c :: __main__.C r0, r1, r2 :: int L0: r0 = borrow c.x r1 = borrow c.y r2 = CPyTagged_Subtract(r0, r1) return r2 [case testBorrowIntComparisonInIf] def add(c: C, n: int) -> bool: if c.x == c.y: return True return False class C: x: int y: int [out] def add(c, n): c :: __main__.C n, r0, r1 :: int r2 :: native_int r3, r4, r5 :: bit L0: r0 = borrow c.x r1 = borrow c.y r2 = r0 & 1 r3 = r2 != 0 if r3 goto L1 else goto L2 :: bool L1: r4 = CPyTagged_IsEq_(r0, r1) if r4 goto L3 else goto L4 :: bool L2: r5 = r0 == r1 if r5 goto L3 else goto L4 :: bool L3: return 1 L4: return 0 [case testBorrowIntInPlaceOp] def add(c: C, n: int) -> None: c.x += n def sub(c: C, n: int) -> None: c.x -= c.y class C: x: int y: int [out] def add(c, n): c :: __main__.C n, r0, r1 :: int r2 :: bool L0: r0 = borrow c.x r1 = CPyTagged_Add(r0, n) c.x = r1; r2 = is_error return 1 def sub(c, n): c :: __main__.C n, r0, r1, r2 :: int r3 :: bool L0: r0 = borrow c.x r1 = borrow c.y r2 = CPyTagged_Subtract(r0, r1) c.x = r2; r3 = is_error return 1