Tipragot
628be439b8
Cela permet de ne pas avoir de problèmes de compatibilité car python est dans le git.
1304 lines
25 KiB
Plaintext
1304 lines
25 KiB
Plaintext
[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"
|