[case testIsNone] from typing import Optional class A: pass def f(x: Optional[A]) -> int: if x is None: return 1 return 2 [out] def f(x): x :: union[__main__.A, None] r0 :: object r1 :: bit L0: r0 = load_address _Py_NoneStruct r1 = x == r0 if r1 goto L1 else goto L2 :: bool L1: return 2 L2: return 4 [case testIsNotNone] from typing import Optional class A: pass def f(x: Optional[A]) -> int: if x is not None: return 1 return 2 [out] def f(x): x :: union[__main__.A, None] r0 :: object r1 :: bit L0: r0 = load_address _Py_NoneStruct r1 = x != r0 if r1 goto L1 else goto L2 :: bool L1: return 2 L2: return 4 [case testIsTruthy] from typing import Optional class A: pass def f(x: Optional[A]) -> int: if x: return 1 return 2 [out] def f(x): x :: union[__main__.A, None] r0 :: object r1 :: bit L0: r0 = load_address _Py_NoneStruct r1 = x != r0 if r1 goto L1 else goto L2 :: bool L1: return 2 L2: return 4 [case testIsTruthyOverride] from typing import Optional class A: pass class B(A): def __bool__(self) -> bool: return False def f(x: Optional[A]) -> int: if x: return 1 return 2 [out] def B.__bool__(self): self :: __main__.B L0: return 0 def f(x): x :: union[__main__.A, None] r0 :: object r1 :: bit r2 :: __main__.A r3 :: i32 r4 :: bit r5 :: bool L0: r0 = load_address _Py_NoneStruct r1 = x != r0 if r1 goto L1 else goto L3 :: bool L1: r2 = cast(__main__.A, x) r3 = PyObject_IsTrue(r2) r4 = r3 >= 0 :: signed r5 = truncate r3: i32 to builtins.bool if r5 goto L2 else goto L3 :: bool L2: return 2 L3: return 4 [case testAssignToOptional] from typing import Optional class A: a: Optional[int] def f(x: Optional[A], y: Optional[A], z: Optional[int]) -> None: x = None x = A() x = y z = 1 a = A() a.a = 1 a.a = None [out] def f(x, y, z): x, y :: union[__main__.A, None] z :: union[int, None] r0 :: object r1 :: __main__.A r2 :: object r3, a :: __main__.A r4 :: object r5 :: bool r6 :: object r7 :: bool L0: r0 = box(None, 1) x = r0 r1 = A() x = r1 x = y r2 = object 1 z = r2 r3 = A() a = r3 r4 = object 1 a.a = r4; r5 = is_error r6 = box(None, 1) a.a = r6; r7 = is_error return 1 [case testBoxOptionalListItem] from typing import List, Optional def f(x: List[Optional[int]]) -> None: x[0] = 0 x[1] = None [out] def f(x): x :: list r0 :: object r1 :: bit r2 :: object r3 :: bit L0: r0 = object 0 r1 = CPyList_SetItem(x, 0, r0) r2 = box(None, 1) r3 = CPyList_SetItem(x, 2, r2) return 1 [case testNarrowDownFromOptional] from typing import Optional class A: pass def f(x: Optional[A]) -> A: y = A() if x is not None: y = x return x return y [out] def f(x): x :: union[__main__.A, None] r0, y :: __main__.A r1 :: object r2 :: bit r3, r4 :: __main__.A L0: r0 = A() y = r0 r1 = load_address _Py_NoneStruct r2 = x != r1 if r2 goto L1 else goto L2 :: bool L1: r3 = cast(__main__.A, x) y = r3 r4 = cast(__main__.A, x) return r4 L2: return y [case testPartialOptionalType] def f(y: int) -> None: x = None if y == 1: x = y if x is not None: y = x [out] def f(y): y :: int r0 :: object x :: union[int, None] r1 :: bit r2, r3 :: object r4 :: bit r5 :: int L0: r0 = box(None, 1) x = r0 r1 = y == 2 if r1 goto L1 else goto L2 :: bool L1: r2 = box(int, y) x = r2 L2: r3 = load_address _Py_NoneStruct r4 = x != r3 if r4 goto L3 else goto L4 :: bool L3: r5 = unbox(int, x) y = r5 L4: return 1 [case testUnionType] from typing import Union class A: a: int def f(x: Union[int, A]) -> int: if isinstance(x, int): return x + 1 else: return x.a [out] def f(x): x :: union[int, __main__.A] r0 :: object r1 :: i32 r2 :: bit r3 :: bool r4, r5 :: int r6 :: __main__.A r7 :: int L0: r0 = load_address PyLong_Type r1 = PyObject_IsInstance(x, r0) r2 = r1 >= 0 :: signed r3 = truncate r1: i32 to builtins.bool if r3 goto L1 else goto L2 :: bool L1: r4 = unbox(int, x) r5 = CPyTagged_Add(r4, 2) return r5 L2: r6 = borrow cast(__main__.A, x) r7 = r6.a keep_alive x return r7 L3: unreachable [case testUnionTypeInList] from typing import List, Union def f(x: List[Union[int, str]]) -> object: return x[0] [out] def f(x): x :: list r0 :: object r1 :: union[int, str] L0: r0 = CPyList_GetItemShort(x, 0) r1 = cast(union[int, str], r0) return r1 [case testUnionAttributeAccess] from typing import Union class A: a: int class B: a: object def get(o: Union[A, B]) -> None: z = o.a def set(o: Union[A, B], s: str) -> None: o.a = s [out] def get(o): o :: union[__main__.A, __main__.B] r0 :: object r1 :: ptr r2 :: object r3 :: bit r4 :: __main__.A r5 :: int r6, r7 :: object r8 :: __main__.B r9, z :: object L0: r0 = __main__.A :: type r1 = get_element_ptr o ob_type :: PyObject r2 = load_mem r1 :: builtins.object* keep_alive o r3 = r2 == r0 if r3 goto L1 else goto L2 :: bool L1: r4 = cast(__main__.A, o) r5 = r4.a r6 = box(int, r5) r7 = r6 goto L3 L2: r8 = cast(__main__.B, o) r9 = r8.a r7 = r9 L3: z = r7 return 1 def set(o, s): o :: union[__main__.A, __main__.B] s, r0 :: str r1 :: i32 r2 :: bit L0: r0 = 'a' r1 = PyObject_SetAttr(o, r0, s) r2 = r1 >= 0 :: signed return 1 [case testUnionMethodCall] from typing import Union class A: def f(self, x: int) -> int: return x class B: def f(self, x: object) -> object: return x class C: def f(self, x: object) -> int: return 0 def g(o: Union[A, B, C]) -> None: z = o.f(1) [out] def A.f(self, x): self :: __main__.A x :: int L0: return x def B.f(self, x): self :: __main__.B x :: object L0: return x def C.f(self, x): self :: __main__.C x :: object L0: return 0 def g(o): o :: union[__main__.A, __main__.B, __main__.C] r0 :: object r1 :: ptr r2 :: object r3 :: bit r4 :: __main__.A r5 :: int r6, r7, r8 :: object r9 :: ptr r10 :: object r11 :: bit r12 :: __main__.B r13, r14 :: object r15 :: __main__.C r16 :: object r17 :: int r18, z :: object L0: r0 = __main__.A :: type r1 = get_element_ptr o ob_type :: PyObject r2 = load_mem r1 :: builtins.object* keep_alive o r3 = r2 == r0 if r3 goto L1 else goto L2 :: bool L1: r4 = cast(__main__.A, o) r5 = r4.f(2) r6 = box(int, r5) r7 = r6 goto L5 L2: r8 = __main__.B :: type r9 = get_element_ptr o ob_type :: PyObject r10 = load_mem r9 :: builtins.object* keep_alive o r11 = r10 == r8 if r11 goto L3 else goto L4 :: bool L3: r12 = cast(__main__.B, o) r13 = object 1 r14 = r12.f(r13) r7 = r14 goto L5 L4: r15 = cast(__main__.C, o) r16 = object 1 r17 = r15.f(r16) r18 = box(int, r17) r7 = r18 L5: z = r7 return 1 [case testUnionWithNonNativeItem] from typing import Union from m import B class A: x: int def f(o: Union[A, B]) -> None: o.x def g(o: Union[B, A]) -> None: o.x [file m.py] class B: x: int [out] def f(o): o :: union[__main__.A, object] r0 :: object r1 :: ptr r2 :: object r3 :: bit r4 :: __main__.A r5, r6 :: int r7 :: object r8 :: str r9 :: object r10 :: int L0: r0 = __main__.A :: type r1 = get_element_ptr o ob_type :: PyObject r2 = load_mem r1 :: builtins.object* keep_alive o r3 = r2 == r0 if r3 goto L1 else goto L2 :: bool L1: r4 = cast(__main__.A, o) r5 = r4.x r6 = r5 goto L3 L2: r7 = o r8 = 'x' r9 = CPyObject_GetAttr(r7, r8) r10 = unbox(int, r9) r6 = r10 L3: return 1 def g(o): o :: union[object, __main__.A] r0 :: object r1 :: ptr r2 :: object r3 :: bit r4 :: __main__.A r5, r6 :: int r7 :: object r8 :: str r9 :: object r10 :: int L0: r0 = __main__.A :: type r1 = get_element_ptr o ob_type :: PyObject r2 = load_mem r1 :: builtins.object* keep_alive o r3 = r2 == r0 if r3 goto L1 else goto L2 :: bool L1: r4 = cast(__main__.A, o) r5 = r4.x r6 = r5 goto L3 L2: r7 = o r8 = 'x' r9 = CPyObject_GetAttr(r7, r8) r10 = unbox(int, r9) r6 = r10 L3: return 1 [case testUnionWithNoNativeItems] from typing import Union from m import A, B def f(o: Union[A, B]) -> None: o.x [file m.py] class A: x: object class B: x: int [out] def f(o): o :: object r0 :: str r1 :: object L0: r0 = 'x' r1 = CPyObject_GetAttr(o, r0) return 1