[case testGetAttribute]
class A:
    x: int

def f(a: A) -> int:
    return a.x
[out]
def f(a):
    a :: __main__.A
    r0 :: int
L0:
    r0 = a.x
    return r0

[case testSetAttribute]
class A:
    x: int

def f(a: A) -> None:
    a.x = 1
[out]
def f(a):
    a :: __main__.A
    r0 :: bool
L0:
    a.x = 2; r0 = is_error
    return 1

[case testUserClassInList]
class C:
    x: int

def f() -> int:
    c = C()
    c.x = 5
    a = [c]
    d = a[0]
    return d.x + 1
[out]
def f():
    r0, c :: __main__.C
    r1 :: bool
    r2 :: list
    r3, r4 :: ptr
    a :: list
    r5 :: object
    r6, d :: __main__.C
    r7, r8 :: int
L0:
    r0 = C()
    c = r0
    c.x = 10; r1 = is_error
    r2 = PyList_New(1)
    r3 = get_element_ptr r2 ob_item :: PyListObject
    r4 = load_mem r3 :: ptr*
    set_mem r4, c :: builtins.object*
    keep_alive r2
    a = r2
    r5 = CPyList_GetItemShort(a, 0)
    r6 = cast(__main__.C, r5)
    d = r6
    r7 = borrow d.x
    r8 = CPyTagged_Add(r7, 2)
    keep_alive d
    return r8

[case testMethodCall]
class A:
    def f(self, x: int, y: str) -> int:
        return x + 10

def g(a: A) -> None:
    a.f(1, 'hi')
[out]
def A.f(self, x, y):
    self :: __main__.A
    x :: int
    y :: str
    r0 :: int
L0:
    r0 = CPyTagged_Add(x, 20)
    return r0
def g(a):
    a :: __main__.A
    r0 :: str
    r1 :: int
L0:
    r0 = 'hi'
    r1 = a.f(2, r0)
    return 1

[case testForwardUse]
def g(a: A) -> int:
    return a.n

class A:
    n : int

[out]
def g(a):
    a :: __main__.A
    r0 :: int
L0:
    r0 = a.n
    return r0

[case testOptionalMember]
from typing import Optional
class Node:
    next: Optional[Node]
    def length(self) -> int:
        if self.next is not None:
            return 1 + self.next.length()
        return 1
[out]
def Node.length(self):
    self :: __main__.Node
    r0 :: union[__main__.Node, None]
    r1 :: object
    r2 :: bit
    r3 :: union[__main__.Node, None]
    r4 :: __main__.Node
    r5, r6 :: int
L0:
    r0 = borrow self.next
    r1 = load_address _Py_NoneStruct
    r2 = r0 != r1
    keep_alive self
    if r2 goto L1 else goto L2 :: bool
L1:
    r3 = self.next
    r4 = cast(__main__.Node, r3)
    r5 = r4.length()
    r6 = CPyTagged_Add(2, r5)
    return r6
L2:
    return 2

[case testSubclass]
class A:
    def __init__(self) -> None:
        self.x = 10
class B(A):
    def __init__(self) -> None:
        self.x = 20
        self.y = 30
[out]
def A.__init__(self):
    self :: __main__.A
L0:
    self.x = 20
    return 1
def B.__init__(self):
    self :: __main__.B
L0:
    self.x = 40
    self.y = 60
    return 1

[case testAttrLvalue]
class O(object):
    def __init__(self) -> None:
        self.x = 1

def increment(o: O) -> O:
    o.x += 1
    return o
[out]
def O.__init__(self):
    self :: __main__.O
L0:
    self.x = 2
    return 1
def increment(o):
    o :: __main__.O
    r0, r1 :: int
    r2 :: bool
L0:
    r0 = borrow o.x
    r1 = CPyTagged_Add(r0, 2)
    o.x = r1; r2 = is_error
    return o

[case testSubclass_toplevel]
from typing import TypeVar, Generic
from mypy_extensions import trait
T = TypeVar('T')
class C:
    pass

@trait
class S:
    pass

class D(C, S, Generic[T]):
    pass

[out]
def __top_level__():
    r0, r1 :: object
    r2 :: bit
    r3 :: str
    r4, r5 :: object
    r6 :: str
    r7 :: dict
    r8, r9 :: object
    r10 :: str
    r11 :: dict
    r12 :: object
    r13 :: str
    r14 :: dict
    r15 :: str
    r16, r17 :: object
    r18 :: dict
    r19 :: str
    r20 :: i32
    r21 :: bit
    r22 :: object
    r23 :: str
    r24, r25 :: object
    r26 :: bool
    r27 :: str
    r28 :: tuple
    r29 :: i32
    r30 :: bit
    r31 :: dict
    r32 :: str
    r33 :: i32
    r34 :: bit
    r35 :: object
    r36 :: str
    r37, r38 :: object
    r39 :: str
    r40 :: tuple
    r41 :: i32
    r42 :: bit
    r43 :: dict
    r44 :: str
    r45 :: i32
    r46 :: bit
    r47, r48 :: object
    r49 :: dict
    r50 :: str
    r51 :: object
    r52 :: dict
    r53 :: str
    r54, r55 :: object
    r56 :: tuple
    r57 :: str
    r58, r59 :: object
    r60 :: bool
    r61, r62 :: str
    r63 :: tuple
    r64 :: i32
    r65 :: bit
    r66 :: dict
    r67 :: str
    r68 :: i32
    r69 :: bit
L0:
    r0 = builtins :: module
    r1 = load_address _Py_NoneStruct
    r2 = r0 != r1
    if r2 goto L2 else goto L1 :: bool
L1:
    r3 = 'builtins'
    r4 = PyImport_Import(r3)
    builtins = r4 :: module
L2:
    r5 = ('TypeVar', 'Generic')
    r6 = 'typing'
    r7 = __main__.globals :: static
    r8 = CPyImport_ImportFromMany(r6, r5, r5, r7)
    typing = r8 :: module
    r9 = ('trait',)
    r10 = 'mypy_extensions'
    r11 = __main__.globals :: static
    r12 = CPyImport_ImportFromMany(r10, r9, r9, r11)
    mypy_extensions = r12 :: module
    r13 = 'T'
    r14 = __main__.globals :: static
    r15 = 'TypeVar'
    r16 = CPyDict_GetItem(r14, r15)
    r17 = PyObject_CallFunctionObjArgs(r16, r13, 0)
    r18 = __main__.globals :: static
    r19 = 'T'
    r20 = CPyDict_SetItem(r18, r19, r17)
    r21 = r20 >= 0 :: signed
    r22 = <error> :: object
    r23 = '__main__'
    r24 = __main__.C_template :: type
    r25 = CPyType_FromTemplate(r24, r22, r23)
    r26 = C_trait_vtable_setup()
    r27 = '__mypyc_attrs__'
    r28 = PyTuple_Pack(0)
    r29 = PyObject_SetAttr(r25, r27, r28)
    r30 = r29 >= 0 :: signed
    __main__.C = r25 :: type
    r31 = __main__.globals :: static
    r32 = 'C'
    r33 = CPyDict_SetItem(r31, r32, r25)
    r34 = r33 >= 0 :: signed
    r35 = <error> :: object
    r36 = '__main__'
    r37 = __main__.S_template :: type
    r38 = CPyType_FromTemplate(r37, r35, r36)
    r39 = '__mypyc_attrs__'
    r40 = PyTuple_Pack(0)
    r41 = PyObject_SetAttr(r38, r39, r40)
    r42 = r41 >= 0 :: signed
    __main__.S = r38 :: type
    r43 = __main__.globals :: static
    r44 = 'S'
    r45 = CPyDict_SetItem(r43, r44, r38)
    r46 = r45 >= 0 :: signed
    r47 = __main__.C :: type
    r48 = __main__.S :: type
    r49 = __main__.globals :: static
    r50 = 'Generic'
    r51 = CPyDict_GetItem(r49, r50)
    r52 = __main__.globals :: static
    r53 = 'T'
    r54 = CPyDict_GetItem(r52, r53)
    r55 = PyObject_GetItem(r51, r54)
    r56 = PyTuple_Pack(3, r47, r48, r55)
    r57 = '__main__'
    r58 = __main__.D_template :: type
    r59 = CPyType_FromTemplate(r58, r56, r57)
    r60 = D_trait_vtable_setup()
    r61 = '__mypyc_attrs__'
    r62 = '__dict__'
    r63 = PyTuple_Pack(1, r62)
    r64 = PyObject_SetAttr(r59, r61, r63)
    r65 = r64 >= 0 :: signed
    __main__.D = r59 :: type
    r66 = __main__.globals :: static
    r67 = 'D'
    r68 = CPyDict_SetItem(r66, r67, r59)
    r69 = r68 >= 0 :: signed
    return 1

[case testIsInstance]
class A: pass
class B(A): pass

def f(x: A) -> B:
    if isinstance(x, B):
        return x
    return B()
[out]
def f(x):
    x :: __main__.A
    r0 :: object
    r1 :: ptr
    r2 :: object
    r3 :: bit
    r4, r5 :: __main__.B
L0:
    r0 = __main__.B :: type
    r1 = get_element_ptr x ob_type :: PyObject
    r2 = load_mem r1 :: builtins.object*
    keep_alive x
    r3 = r2 == r0
    if r3 goto L1 else goto L2 :: bool
L1:
    r4 = cast(__main__.B, x)
    return r4
L2:
    r5 = B()
    return r5

[case testIsInstanceTuple]
from typing import Union
class R: pass
class A(R): pass
class B(R): pass
class C(R): pass

def f(x: R) -> Union[A, B]:
    if isinstance(x, (A, B)):
        return x
    return A()
[out]
def f(x):
    x :: __main__.R
    r0 :: object
    r1 :: ptr
    r2 :: object
    r3 :: bit
    r4 :: bool
    r5 :: object
    r6 :: ptr
    r7 :: object
    r8 :: bit
    r9 :: union[__main__.A, __main__.B]
    r10 :: __main__.A
L0:
    r0 = __main__.A :: type
    r1 = get_element_ptr x ob_type :: PyObject
    r2 = load_mem r1 :: builtins.object*
    keep_alive x
    r3 = r2 == r0
    if r3 goto L1 else goto L2 :: bool
L1:
    r4 = r3
    goto L3
L2:
    r5 = __main__.B :: type
    r6 = get_element_ptr x ob_type :: PyObject
    r7 = load_mem r6 :: builtins.object*
    keep_alive x
    r8 = r7 == r5
    r4 = r8
L3:
    if r4 goto L4 else goto L5 :: bool
L4:
    r9 = cast(union[__main__.A, __main__.B], x)
    return r9
L5:
    r10 = A()
    return r10

[case testIsInstanceFewSubclasses]
class R: pass
class A(R): pass

def f(x: object) -> R:
    if isinstance(x, R):
        return x
    return A()
[out]
def f(x):
    x, r0 :: object
    r1 :: ptr
    r2 :: object
    r3 :: bit
    r4 :: bool
    r5 :: object
    r6 :: ptr
    r7 :: object
    r8 :: bit
    r9 :: __main__.R
    r10 :: __main__.A
L0:
    r0 = __main__.A :: type
    r1 = get_element_ptr x ob_type :: PyObject
    r2 = load_mem r1 :: builtins.object*
    keep_alive x
    r3 = r2 == r0
    if r3 goto L1 else goto L2 :: bool
L1:
    r4 = r3
    goto L3
L2:
    r5 = __main__.R :: type
    r6 = get_element_ptr x ob_type :: PyObject
    r7 = load_mem r6 :: builtins.object*
    keep_alive x
    r8 = r7 == r5
    r4 = r8
L3:
    if r4 goto L4 else goto L5 :: bool
L4:
    r9 = cast(__main__.R, x)
    return r9
L5:
    r10 = A()
    return r10

[case testIsInstanceFewSubclassesTrait]
from mypy_extensions import trait
class B: pass
@trait
class R: pass
class A(B, R): pass
class C(B, R): pass

def f(x: object) -> R:
    if isinstance(x, R):
        return x
    return A()
[out]
def f(x):
    x, r0 :: object
    r1 :: ptr
    r2 :: object
    r3 :: bit
    r4 :: bool
    r5 :: object
    r6 :: ptr
    r7 :: object
    r8 :: bit
    r9 :: __main__.R
    r10 :: __main__.A
L0:
    r0 = __main__.A :: type
    r1 = get_element_ptr x ob_type :: PyObject
    r2 = load_mem r1 :: builtins.object*
    keep_alive x
    r3 = r2 == r0
    if r3 goto L1 else goto L2 :: bool
L1:
    r4 = r3
    goto L3
L2:
    r5 = __main__.C :: type
    r6 = get_element_ptr x ob_type :: PyObject
    r7 = load_mem r6 :: builtins.object*
    keep_alive x
    r8 = r7 == r5
    r4 = r8
L3:
    if r4 goto L4 else goto L5 :: bool
L4:
    r9 = cast(__main__.R, x)
    return r9
L5:
    r10 = A()
    return r10

[case testIsInstanceManySubclasses]
class R: pass
class A(R): pass
class B(R): pass
class C(R): pass

def f(x: object) -> R:
    if isinstance(x, R):
        return x
    return B()
[out]
def f(x):
    x, r0 :: object
    r1 :: bool
    r2 :: __main__.R
    r3 :: __main__.B
L0:
    r0 = __main__.R :: type
    r1 = CPy_TypeCheck(x, r0)
    if r1 goto L1 else goto L2 :: bool
L1:
    r2 = cast(__main__.R, x)
    return r2
L2:
    r3 = B()
    return r3

[case testFakeSuper]
class A:
    def __init__(self, x: int) -> None:
        self.x = x
class B(A):
    def __init__(self, x: int, y: int) -> None:
        A.__init__(self, x)
        self.y = y
[out]
def A.__init__(self, x):
    self :: __main__.A
    x :: int
L0:
    self.x = x
    return 1
def B.__init__(self, x, y):
    self :: __main__.B
    x, y :: int
    r0 :: None
L0:
    r0 = A.__init__(self, x)
    self.y = y
    return 1

[case testClassMethod]
class C:
    @staticmethod
    def foo(x: int) -> int: return 10 + x
    @classmethod
    def bar(cls, x: int) -> int: return 10 + x

def lol() -> int:
    return C.foo(1) + C.bar(2)
[out]
def C.foo(x):
    x, r0 :: int
L0:
    r0 = CPyTagged_Add(20, x)
    return r0
def C.bar(cls, x):
    cls :: object
    x, r0 :: int
L0:
    r0 = CPyTagged_Add(20, x)
    return r0
def lol():
    r0 :: int
    r1 :: object
    r2, r3 :: int
L0:
    r0 = C.foo(2)
    r1 = __main__.C :: type
    r2 = C.bar(r1, 4)
    r3 = CPyTagged_Add(r0, r2)
    return r3

[case testCallClassMethodViaCls]
class C:
    @classmethod
    def f(cls, x: int) -> int:
        return cls.g(x)

    @classmethod
    def g(cls, x: int) -> int:
        return x

class D:
    @classmethod
    def f(cls, x: int) -> int:
        # TODO: This could aso be optimized, since g is not ever overridden
        return cls.g(x)

    @classmethod
    def g(cls, x: int) -> int:
        return x

class DD(D):
    pass
[out]
def C.f(cls, x):
    cls :: object
    x :: int
    r0 :: object
    r1 :: int
L0:
    r0 = __main__.C :: type
    r1 = C.g(r0, x)
    return r1
def C.g(cls, x):
    cls :: object
    x :: int
L0:
    return x
def D.f(cls, x):
    cls :: object
    x :: int
    r0 :: str
    r1, r2 :: object
    r3 :: int
L0:
    r0 = 'g'
    r1 = box(int, x)
    r2 = CPyObject_CallMethodObjArgs(cls, r0, r1, 0)
    r3 = unbox(int, r2)
    return r3
def D.g(cls, x):
    cls :: object
    x :: int
L0:
    return x

[case testCannotAssignToClsArgument]
from typing import Any, cast

class C:
    @classmethod
    def m(cls) -> None:
        cls = cast(Any, D)  # E: Cannot assign to the first argument of classmethod
        cls, x = cast(Any, D), 1  # E: Cannot assign to the first argument of classmethod
        cls, x = cast(Any, [1, 2])  # E: Cannot assign to the first argument of classmethod
        cls.m()

class D:
    pass

[case testSuper1]
class A:
    def __init__(self, x: int) -> None:
        self.x = x
class B(A):
    def __init__(self, x: int, y: int) -> None:
        super().__init__(x)
        self.y = y
[out]
def A.__init__(self, x):
    self :: __main__.A
    x :: int
L0:
    self.x = x
    return 1
def B.__init__(self, x, y):
    self :: __main__.B
    x, y :: int
    r0 :: None
L0:
    r0 = A.__init__(self, x)
    self.y = y
    return 1

[case testSuper2]
from mypy_extensions import trait
@trait
class T:
    def foo(self) -> None: pass

class X(T):
    def foo(self) -> None:
        super().foo()
[out]
def T.foo(self):
    self :: __main__.T
L0:
    return 1
def X.foo(self):
    self :: __main__.X
    r0 :: None
L0:
    r0 = T.foo(self)
    return 1

[case testSuperCallToObjectInitIsOmitted]
class C:
    def __init__(self) -> None:
        super().__init__()
class D: pass
class E(D):
    def __init__(self) -> None:
        super().__init__()
class F(C):
    def __init__(self) -> None:
        super().__init__()
class DictSubclass(dict):
    def __init__(self) -> None:
        super().__init__()
[out]
def C.__init__(self):
    self :: __main__.C
L0:
    return 1
def E.__init__(self):
    self :: __main__.E
L0:
    return 1
def F.__init__(self):
    self :: __main__.F
    r0 :: None
L0:
    r0 = C.__init__(self)
    return 1
def DictSubclass.__init__(self):
    self :: dict
    r0 :: object
    r1 :: str
    r2, r3, r4 :: object
    r5 :: str
    r6, r7 :: object
L0:
    r0 = builtins :: module
    r1 = 'super'
    r2 = CPyObject_GetAttr(r0, r1)
    r3 = __main__.DictSubclass :: type
    r4 = PyObject_CallFunctionObjArgs(r2, r3, self, 0)
    r5 = '__init__'
    r6 = CPyObject_GetAttr(r4, r5)
    r7 = PyObject_CallFunctionObjArgs(r6, 0)
    return 1

[case testClassVariable]
from typing import ClassVar
class A:
    x = 10  # type: ClassVar[int]

def f() -> int:
    return A.x
[out]
def f():
    r0 :: object
    r1 :: str
    r2 :: object
    r3 :: int
L0:
    r0 = __main__.A :: type
    r1 = 'x'
    r2 = CPyObject_GetAttr(r0, r1)
    r3 = unbox(int, r2)
    return r3

[case testNoEqDefined]
class A:
    pass

def f(a: A, b: A) -> bool:
    return a == b

def f2(a: A, b: A) -> bool:
    return a != b

[out]
def f(a, b):
    a, b :: __main__.A
    r0 :: bit
L0:
    r0 = a == b
    return r0
def f2(a, b):
    a, b :: __main__.A
    r0 :: bit
L0:
    r0 = a != b
    return r0

[case testEqDefined]
class Base:
    def __eq__(self, other: object) -> bool:
        return False
class Derived(Base):
    def __eq__(self, other: object) -> bool:
        return True

def f(a: Base, b: Base) -> bool:
    return a == b

def f2(a: Base, b: Base) -> bool:
    return a != b

def fOpt(a: Derived, b: Derived) -> bool:
    return a == b

def fOpt2(a: Derived, b: Derived) -> bool:
    return a != b

[out]
def Base.__eq__(self, other):
    self :: __main__.Base
    other, r0 :: object
L0:
    r0 = box(bool, 0)
    return r0
def Base.__ne__(__mypyc_self__, rhs):
    __mypyc_self__ :: __main__.Base
    rhs, r0, r1 :: object
    r2 :: bit
    r3 :: i32
    r4 :: bit
    r5 :: bool
    r6 :: object
L0:
    r0 = __mypyc_self__.__eq__(rhs)
    r1 = load_address _Py_NotImplementedStruct
    r2 = r0 == r1
    if r2 goto L2 else goto L1 :: bool
L1:
    r3 = PyObject_Not(r0)
    r4 = r3 >= 0 :: signed
    r5 = truncate r3: i32 to builtins.bool
    r6 = box(bool, r5)
    return r6
L2:
    return r1
def Derived.__eq__(self, other):
    self :: __main__.Derived
    other, r0 :: object
L0:
    r0 = box(bool, 1)
    return r0
def f(a, b):
    a, b :: __main__.Base
    r0 :: object
    r1 :: bool
L0:
    r0 = PyObject_RichCompare(a, b, 2)
    r1 = unbox(bool, r0)
    return r1
def f2(a, b):
    a, b :: __main__.Base
    r0 :: object
    r1 :: bool
L0:
    r0 = PyObject_RichCompare(a, b, 3)
    r1 = unbox(bool, r0)
    return r1
def fOpt(a, b):
    a, b :: __main__.Derived
    r0 :: object
    r1 :: bool
L0:
    r0 = a.__eq__(b)
    r1 = unbox(bool, r0)
    return r1
def fOpt2(a, b):
    a, b :: __main__.Derived
    r0 :: object
    r1 :: bool
L0:
    r0 = a.__ne__(b)
    r1 = unbox(bool, r0)
    return r1

[case testEqDefinedLater]
def f(a: 'Base', b: 'Base') -> bool:
    return a == b

def f2(a: 'Base', b: 'Base') -> bool:
    return a != b

def fOpt(a: 'Derived', b: 'Derived') -> bool:
    return a == b

def fOpt2(a: 'Derived', b: 'Derived') -> bool:
    return a != b

class Base:
    pass
class Derived(Base):
    def __eq__(self, other: object) -> bool:
        return True

[out]
def f(a, b):
    a, b :: __main__.Base
    r0 :: object
    r1 :: bool
L0:
    r0 = PyObject_RichCompare(a, b, 2)
    r1 = unbox(bool, r0)
    return r1
def f2(a, b):
    a, b :: __main__.Base
    r0 :: object
    r1 :: bool
L0:
    r0 = PyObject_RichCompare(a, b, 3)
    r1 = unbox(bool, r0)
    return r1
def fOpt(a, b):
    a, b :: __main__.Derived
    r0 :: object
    r1 :: bool
L0:
    r0 = a.__eq__(b)
    r1 = unbox(bool, r0)
    return r1
def fOpt2(a, b):
    a, b :: __main__.Derived
    r0 :: str
    r1 :: object
    r2 :: bool
L0:
    r0 = '__ne__'
    r1 = CPyObject_CallMethodObjArgs(a, r0, b, 0)
    r2 = unbox(bool, r1)
    return r2
def Derived.__eq__(self, other):
    self :: __main__.Derived
    other, r0 :: object
L0:
    r0 = box(bool, 1)
    return r0
def Derived.__ne__(__mypyc_self__, rhs):
    __mypyc_self__ :: __main__.Derived
    rhs, r0, r1 :: object
    r2 :: bit
    r3 :: i32
    r4 :: bit
    r5 :: bool
    r6 :: object
L0:
    r0 = __mypyc_self__.__eq__(rhs)
    r1 = load_address _Py_NotImplementedStruct
    r2 = r0 == r1
    if r2 goto L2 else goto L1 :: bool
L1:
    r3 = PyObject_Not(r0)
    r4 = r3 >= 0 :: signed
    r5 = truncate r3: i32 to builtins.bool
    r6 = box(bool, r5)
    return r6
L2:
    return r1

[case testDefaultVars]
from typing import ClassVar, Optional
class A:
    x = 10
    def lol(self) -> None:
        self.x = 100

LOL = 'lol'
class B(A):
    y = LOL
    z: Optional[str] = None
    b = True
    bogus = None  # type: int
[out]
def A.lol(self):
    self :: __main__.A
    r0 :: bool
L0:
    self.x = 200; r0 = is_error
    return 1
def A.__mypyc_defaults_setup(__mypyc_self__):
    __mypyc_self__ :: __main__.A
L0:
    __mypyc_self__.x = 20
    return 1
def B.__mypyc_defaults_setup(__mypyc_self__):
    __mypyc_self__ :: __main__.B
    r0 :: dict
    r1 :: str
    r2 :: object
    r3 :: str
    r4 :: object
L0:
    __mypyc_self__.x = 20
    r0 = __main__.globals :: static
    r1 = 'LOL'
    r2 = CPyDict_GetItem(r0, r1)
    r3 = cast(str, r2)
    __mypyc_self__.y = r3
    r4 = box(None, 1)
    __mypyc_self__.z = r4
    __mypyc_self__.b = 1
    return 1

[case testSubclassDictSpecalized]
from typing import Dict
class WelpDict(Dict[str, int]):
    pass
def foo(x: WelpDict) -> None:
    # we care that the specalized op gets used
    x.update(x)
[out]
def foo(x):
    x :: dict
    r0 :: i32
    r1 :: bit
L0:
    r0 = CPyDict_Update(x, x)
    r1 = r0 >= 0 :: signed
    return 1

[case testNoSpuriousLinearity]
# Make sure that the non-trait MRO linearity check isn't affected by processing order
class A(B): pass
class B(C): pass
class C: pass
[out]

[case testDeletableSemanticAnalysis]
class Err1:
    __deletable__ = 'x'  # E: "__deletable__" must be initialized with a list or tuple expression
class Err2:
    __deletable__ = [
        1  # E: Invalid "__deletable__" item; string literal expected
    ]
class Err3:
    __deletable__ = ['x', ['y'], 'z']  # E: Invalid "__deletable__" item; string literal expected
class Err4:
    __deletable__ = (1,)  # E: Invalid "__deletable__" item; string literal expected
a = ['x']
class Err5:
    __deletable__ = a  # E: "__deletable__" must be initialized with a list or tuple expression

class Ok1:
    __deletable__ = ('x',)
    x: int
class Ok2:
    __deletable__ = ['x']
    x: int

[case testInvalidDeletableAttribute]
class NotDeletable:
    __deletable__ = ['x']
    x: int
    y: int

def g(o: NotDeletable) -> None:
    del o.x
    del o.y  # E: "y" cannot be deleted \
             # N: Using "__deletable__ = ['<attr>']" in the class body enables "del obj.<attr>"

class Base:
    x: int

class Deriv(Base):
    __deletable__ = ['x']  # E: Attribute "x" not defined in "Deriv" (defined in "Base")

class UndefinedDeletable:
    __deletable__ = ['x']  # E: Attribute "x" not defined

class DeletableProperty:
    __deletable__ = ['prop']  # E: Cannot make property "prop" deletable

    @property
    def prop(self) -> int:
        return 5

[case testFinalDeletable]
from typing import Final

class DeletableFinal1:
    x: Final[int]  # E: Deletable attribute cannot be final

    __deletable__ = ['x']

    def __init__(self, x: int) -> None:
        self.x = x

class DeletableFinal2:
    X: Final = 0  # E: Deletable attribute cannot be final

    __deletable__ = ['X']

[case testNeedAnnotateClassVar]
from typing import Final, ClassVar, Type

class C:
    a = 'A'
    b: str = 'B'
    f: Final = 'F'
    c: ClassVar = 'C'

class D(C):
    pass

def f() -> None:
    C.a  # E: Cannot access instance attribute "a" through class object \
         # N: (Hint: Use "x: Final = ..." or "x: ClassVar = ..." to define a class attribute)
    C.b  # E: Cannot access instance attribute "b" through class object \
         # N: (Hint: Use "x: Final = ..." or "x: ClassVar = ..." to define a class attribute)
    C.f
    C.c

    D.a  # E: Cannot access instance attribute "a" through class object \
         # N: (Hint: Use "x: Final = ..." or "x: ClassVar = ..." to define a class attribute)
    D.b  # E: Cannot access instance attribute "b" through class object \
         # N: (Hint: Use "x: Final = ..." or "x: ClassVar = ..." to define a class attribute)
    D.f
    D.c

def g(c: Type[C], d: Type[D]) -> None:
    c.a  # E: Cannot access instance attribute "a" through class object \
         # N: (Hint: Use "x: Final = ..." or "x: ClassVar = ..." to define a class attribute)
    c.f
    c.c

    d.a  # E: Cannot access instance attribute "a" through class object \
         # N: (Hint: Use "x: Final = ..." or "x: ClassVar = ..." to define a class attribute)
    d.f
    d.c

[case testSetAttributeWithDefaultInInit]
class C:
    s = ''

    def __init__(self, s: str) -> None:
        self.s = s
[out]
def C.__init__(self, s):
    self :: __main__.C
    s :: str
    r0 :: bool
L0:
    self.s = s; r0 = is_error
    return 1
def C.__mypyc_defaults_setup(__mypyc_self__):
    __mypyc_self__ :: __main__.C
    r0 :: str
L0:
    r0 = ''
    __mypyc_self__.s = r0
    return 1

[case testBorrowAttribute]
def f(d: D) -> int:
    return d.c.x

class C:
    x: int
class D:
    c: C
[out]
def f(d):
    d :: __main__.D
    r0 :: __main__.C
    r1 :: int
L0:
    r0 = borrow d.c
    r1 = r0.x
    keep_alive d
    return r1

[case testNoBorrowOverPropertyAccess]
class C:
    d: D
class D:
    @property
    def e(self) -> E:
        return E()
class E:
    x: int
def f(c: C) -> int:
    return c.d.e.x
[out]
def D.e(self):
    self :: __main__.D
    r0 :: __main__.E
L0:
    r0 = E()
    return r0
def f(c):
    c :: __main__.C
    r0 :: __main__.D
    r1 :: __main__.E
    r2 :: int
L0:
    r0 = c.d
    r1 = r0.e
    r2 = r1.x
    return r2

[case testBorrowResultOfCustomGetItemInIfStatement]
from typing import List

class C:
    def __getitem__(self, x: int) -> List[int]:
        return []

def f(x: C) -> None:
    # In this case the keep_alive must come before the branch, as otherwise
    # reference count transform will get confused.
    if x[1][0] == 2:
        y = 1
    else:
        y = 2
[out]
def C.__getitem__(self, x):
    self :: __main__.C
    x :: int
    r0 :: list
L0:
    r0 = PyList_New(0)
    return r0
def f(x):
    x :: __main__.C
    r0 :: list
    r1 :: object
    r2 :: int
    r3 :: bit
    y :: int
L0:
    r0 = x.__getitem__(2)
    r1 = CPyList_GetItemShortBorrow(r0, 0)
    r2 = unbox(int, r1)
    r3 = r2 == 4
    keep_alive r0
    if r3 goto L1 else goto L2 :: bool
L1:
    y = 2
    goto L3
L2:
    y = 4
L3:
    return 1

[case testIncompatibleDefinitionOfAttributeInSubclass]
from mypy_extensions import trait

class Base:
    x: int

class Bad1(Base):
    x: bool  # E: Type of "x" is incompatible with definition in class "Base"

class Good1(Base):
    x: int

class Good2(Base):
    x: int = 0

class Good3(Base):
    x = 0

class Good4(Base):
    def __init__(self) -> None:
        self.x = 0

class Good5(Base):
    def __init__(self) -> None:
        self.x: int = 0

class Base2(Base):
    pass

class Bad2(Base2):
    x: bool = False  # E: Type of "x" is incompatible with definition in class "Base"

class Bad3(Base):
    x = False  # E: Type of "x" is incompatible with definition in class "Base"

@trait
class T:
    y: object

class E(T):
    y: str  # E: Type of "y" is incompatible with definition in trait "T"
