[case testNestedFunctions] from typing import Callable def a() -> Callable[[], object]: def inner() -> object: return None return inner def b() -> Callable[[], Callable[[], str]]: def first() -> Callable[[], str]: def second() -> str: return 'b.first.second: nested function' return second return first def c(num: float) -> Callable[[str], str]: def inner(s: str) -> str: return s + '!' return inner def d(num: float) -> str: def inner(s: str) -> str: return s + '?' a = inner('one') b = inner('two') return a def inner() -> str: return 'inner: normal function' def first() -> str: return 'first: normal function' def second() -> str: return 'second: normal function' [out] def inner_a_obj.__get__(__mypyc_self__, instance, owner): __mypyc_self__, instance, owner, r0 :: object r1 :: bit r2 :: object L0: r0 = load_address _Py_NoneStruct r1 = instance == r0 if r1 goto L1 else goto L2 :: bool L1: return __mypyc_self__ L2: r2 = PyMethod_New(__mypyc_self__, instance) return r2 def inner_a_obj.__call__(__mypyc_self__): __mypyc_self__ :: __main__.inner_a_obj r0 :: __main__.a_env r1 :: object L0: r0 = __mypyc_self__.__mypyc_env__ r1 = box(None, 1) return r1 def a(): r0 :: __main__.a_env r1 :: __main__.inner_a_obj r2 :: bool inner :: object L0: r0 = a_env() r1 = inner_a_obj() r1.__mypyc_env__ = r0; r2 = is_error inner = r1 return inner def second_b_first_obj.__get__(__mypyc_self__, instance, owner): __mypyc_self__, instance, owner, r0 :: object r1 :: bit r2 :: object L0: r0 = load_address _Py_NoneStruct r1 = instance == r0 if r1 goto L1 else goto L2 :: bool L1: return __mypyc_self__ L2: r2 = PyMethod_New(__mypyc_self__, instance) return r2 def second_b_first_obj.__call__(__mypyc_self__): __mypyc_self__ :: __main__.second_b_first_obj r0 :: __main__.first_b_env r1 :: __main__.b_env r2 :: str L0: r0 = __mypyc_self__.__mypyc_env__ r1 = r0.__mypyc_env__ r2 = 'b.first.second: nested function' return r2 def first_b_obj.__get__(__mypyc_self__, instance, owner): __mypyc_self__, instance, owner, r0 :: object r1 :: bit r2 :: object L0: r0 = load_address _Py_NoneStruct r1 = instance == r0 if r1 goto L1 else goto L2 :: bool L1: return __mypyc_self__ L2: r2 = PyMethod_New(__mypyc_self__, instance) return r2 def first_b_obj.__call__(__mypyc_self__): __mypyc_self__ :: __main__.first_b_obj r0 :: __main__.b_env r1 :: __main__.first_b_env r2 :: bool r3 :: __main__.second_b_first_obj r4 :: bool second :: object L0: r0 = __mypyc_self__.__mypyc_env__ r1 = first_b_env() r1.__mypyc_env__ = r0; r2 = is_error r3 = second_b_first_obj() r3.__mypyc_env__ = r1; r4 = is_error second = r3 return second def b(): r0 :: __main__.b_env r1 :: __main__.first_b_obj r2 :: bool first :: object L0: r0 = b_env() r1 = first_b_obj() r1.__mypyc_env__ = r0; r2 = is_error first = r1 return first def inner_c_obj.__get__(__mypyc_self__, instance, owner): __mypyc_self__, instance, owner, r0 :: object r1 :: bit r2 :: object L0: r0 = load_address _Py_NoneStruct r1 = instance == r0 if r1 goto L1 else goto L2 :: bool L1: return __mypyc_self__ L2: r2 = PyMethod_New(__mypyc_self__, instance) return r2 def inner_c_obj.__call__(__mypyc_self__, s): __mypyc_self__ :: __main__.inner_c_obj s :: str r0 :: __main__.c_env r1, r2 :: str L0: r0 = __mypyc_self__.__mypyc_env__ r1 = '!' r2 = PyUnicode_Concat(s, r1) return r2 def c(num): num :: float r0 :: __main__.c_env r1 :: __main__.inner_c_obj r2 :: bool inner :: object L0: r0 = c_env() r1 = inner_c_obj() r1.__mypyc_env__ = r0; r2 = is_error inner = r1 return inner def inner_d_obj.__get__(__mypyc_self__, instance, owner): __mypyc_self__, instance, owner, r0 :: object r1 :: bit r2 :: object L0: r0 = load_address _Py_NoneStruct r1 = instance == r0 if r1 goto L1 else goto L2 :: bool L1: return __mypyc_self__ L2: r2 = PyMethod_New(__mypyc_self__, instance) return r2 def inner_d_obj.__call__(__mypyc_self__, s): __mypyc_self__ :: __main__.inner_d_obj s :: str r0 :: __main__.d_env r1, r2 :: str L0: r0 = __mypyc_self__.__mypyc_env__ r1 = '?' r2 = PyUnicode_Concat(s, r1) return r2 def d(num): num :: float r0 :: __main__.d_env r1 :: __main__.inner_d_obj r2 :: bool inner :: object r3 :: str r4 :: object[1] r5 :: object_ptr r6 :: object r7, a, r8 :: str r9 :: object[1] r10 :: object_ptr r11 :: object r12, b :: str L0: r0 = d_env() r1 = inner_d_obj() r1.__mypyc_env__ = r0; r2 = is_error inner = r1 r3 = 'one' r4 = [r3] r5 = load_address r4 r6 = PyObject_Vectorcall(inner, r5, 1, 0) keep_alive r3 r7 = cast(str, r6) a = r7 r8 = 'two' r9 = [r8] r10 = load_address r9 r11 = PyObject_Vectorcall(inner, r10, 1, 0) keep_alive r8 r12 = cast(str, r11) b = r12 return a def inner(): r0 :: str L0: r0 = 'inner: normal function' return r0 def first(): r0 :: str L0: r0 = 'first: normal function' return r0 def second(): r0 :: str L0: r0 = 'second: normal function' return r0 [case testFreeVars] from typing import Callable def a(num: int) -> int: def inner() -> int: return num return inner() def b() -> int: num = 3 def inner() -> int: nonlocal num num = 4 foo = 6 return num return inner() + num def c(flag: bool) -> str: if flag: def inner() -> str: return 'f.inner: first definition' else: def inner() -> str: return 'f.inner: second definition' return inner() [out] def inner_a_obj.__get__(__mypyc_self__, instance, owner): __mypyc_self__, instance, owner, r0 :: object r1 :: bit r2 :: object L0: r0 = load_address _Py_NoneStruct r1 = instance == r0 if r1 goto L1 else goto L2 :: bool L1: return __mypyc_self__ L2: r2 = PyMethod_New(__mypyc_self__, instance) return r2 def inner_a_obj.__call__(__mypyc_self__): __mypyc_self__ :: __main__.inner_a_obj r0 :: __main__.a_env r1 :: int L0: r0 = __mypyc_self__.__mypyc_env__ r1 = r0.num return r1 def a(num): num :: int r0 :: __main__.a_env r1 :: bool r2 :: __main__.inner_a_obj r3 :: bool inner, r4 :: object r5 :: int L0: r0 = a_env() r0.num = num; r1 = is_error r2 = inner_a_obj() r2.__mypyc_env__ = r0; r3 = is_error inner = r2 r4 = PyObject_Vectorcall(inner, 0, 0, 0) r5 = unbox(int, r4) return r5 def inner_b_obj.__get__(__mypyc_self__, instance, owner): __mypyc_self__, instance, owner, r0 :: object r1 :: bit r2 :: object L0: r0 = load_address _Py_NoneStruct r1 = instance == r0 if r1 goto L1 else goto L2 :: bool L1: return __mypyc_self__ L2: r2 = PyMethod_New(__mypyc_self__, instance) return r2 def inner_b_obj.__call__(__mypyc_self__): __mypyc_self__ :: __main__.inner_b_obj r0 :: __main__.b_env r1 :: bool foo, r2 :: int L0: r0 = __mypyc_self__.__mypyc_env__ r0.num = 8; r1 = is_error foo = 12 r2 = r0.num return r2 def b(): r0 :: __main__.b_env r1 :: bool r2 :: __main__.inner_b_obj r3 :: bool inner, r4 :: object r5, r6, r7 :: int L0: r0 = b_env() r0.num = 6; r1 = is_error r2 = inner_b_obj() r2.__mypyc_env__ = r0; r3 = is_error inner = r2 r4 = PyObject_Vectorcall(inner, 0, 0, 0) r5 = unbox(int, r4) r6 = r0.num r7 = CPyTagged_Add(r5, r6) return r7 def inner_c_obj.__get__(__mypyc_self__, instance, owner): __mypyc_self__, instance, owner, r0 :: object r1 :: bit r2 :: object L0: r0 = load_address _Py_NoneStruct r1 = instance == r0 if r1 goto L1 else goto L2 :: bool L1: return __mypyc_self__ L2: r2 = PyMethod_New(__mypyc_self__, instance) return r2 def inner_c_obj.__call__(__mypyc_self__): __mypyc_self__ :: __main__.inner_c_obj r0 :: __main__.c_env r1 :: str L0: r0 = __mypyc_self__.__mypyc_env__ r1 = 'f.inner: first definition' return r1 def inner_c_obj_0.__get__(__mypyc_self__, instance, owner): __mypyc_self__, instance, owner, r0 :: object r1 :: bit r2 :: object L0: r0 = load_address _Py_NoneStruct r1 = instance == r0 if r1 goto L1 else goto L2 :: bool L1: return __mypyc_self__ L2: r2 = PyMethod_New(__mypyc_self__, instance) return r2 def inner_c_obj_0.__call__(__mypyc_self__): __mypyc_self__ :: __main__.inner_c_obj_0 r0 :: __main__.c_env r1 :: str L0: r0 = __mypyc_self__.__mypyc_env__ r1 = 'f.inner: second definition' return r1 def c(flag): flag :: bool r0 :: __main__.c_env r1 :: __main__.inner_c_obj r2 :: bool inner :: object r3 :: __main__.inner_c_obj_0 r4 :: bool r5 :: object r6 :: str L0: r0 = c_env() if flag goto L1 else goto L2 :: bool L1: r1 = inner_c_obj() r1.__mypyc_env__ = r0; r2 = is_error inner = r1 goto L3 L2: r3 = inner_c_obj_0() r3.__mypyc_env__ = r0; r4 = is_error inner = r3 L3: r5 = PyObject_Vectorcall(inner, 0, 0, 0) r6 = cast(str, r5) return r6 [case testSpecialNested] def a() -> int: x = 1 def b() -> int: x += 1 def c() -> int: return x return c() return b() [out] def c_a_b_obj.__get__(__mypyc_self__, instance, owner): __mypyc_self__, instance, owner, r0 :: object r1 :: bit r2 :: object L0: r0 = load_address _Py_NoneStruct r1 = instance == r0 if r1 goto L1 else goto L2 :: bool L1: return __mypyc_self__ L2: r2 = PyMethod_New(__mypyc_self__, instance) return r2 def c_a_b_obj.__call__(__mypyc_self__): __mypyc_self__ :: __main__.c_a_b_obj r0 :: __main__.b_a_env r1 :: __main__.a_env r2 :: int L0: r0 = __mypyc_self__.__mypyc_env__ r1 = r0.__mypyc_env__ r2 = r1.x return r2 def b_a_obj.__get__(__mypyc_self__, instance, owner): __mypyc_self__, instance, owner, r0 :: object r1 :: bit r2 :: object L0: r0 = load_address _Py_NoneStruct r1 = instance == r0 if r1 goto L1 else goto L2 :: bool L1: return __mypyc_self__ L2: r2 = PyMethod_New(__mypyc_self__, instance) return r2 def b_a_obj.__call__(__mypyc_self__): __mypyc_self__ :: __main__.b_a_obj r0 :: __main__.a_env r1 :: __main__.b_a_env r2 :: bool r3, r4 :: int r5 :: bool r6 :: __main__.c_a_b_obj r7 :: bool c, r8 :: object r9 :: int L0: r0 = __mypyc_self__.__mypyc_env__ r1 = b_a_env() r1.__mypyc_env__ = r0; r2 = is_error r3 = r0.x r4 = CPyTagged_Add(r3, 2) r0.x = r4; r5 = is_error r6 = c_a_b_obj() r6.__mypyc_env__ = r1; r7 = is_error c = r6 r8 = PyObject_Vectorcall(c, 0, 0, 0) r9 = unbox(int, r8) return r9 def a(): r0 :: __main__.a_env r1 :: bool r2 :: __main__.b_a_obj r3 :: bool b, r4 :: object r5 :: int L0: r0 = a_env() r0.x = 2; r1 = is_error r2 = b_a_obj() r2.__mypyc_env__ = r0; r3 = is_error b = r2 r4 = PyObject_Vectorcall(b, 0, 0, 0) r5 = unbox(int, r4) return r5 [case testNestedFunctionInsideStatements] def f(flag: bool) -> str: if flag: def inner() -> str: return 'f.inner: first definition' else: def inner() -> str: return 'f.inner: second definition' return inner() [out] def inner_f_obj.__get__(__mypyc_self__, instance, owner): __mypyc_self__, instance, owner, r0 :: object r1 :: bit r2 :: object L0: r0 = load_address _Py_NoneStruct r1 = instance == r0 if r1 goto L1 else goto L2 :: bool L1: return __mypyc_self__ L2: r2 = PyMethod_New(__mypyc_self__, instance) return r2 def inner_f_obj.__call__(__mypyc_self__): __mypyc_self__ :: __main__.inner_f_obj r0 :: __main__.f_env r1 :: str L0: r0 = __mypyc_self__.__mypyc_env__ r1 = 'f.inner: first definition' return r1 def inner_f_obj_0.__get__(__mypyc_self__, instance, owner): __mypyc_self__, instance, owner, r0 :: object r1 :: bit r2 :: object L0: r0 = load_address _Py_NoneStruct r1 = instance == r0 if r1 goto L1 else goto L2 :: bool L1: return __mypyc_self__ L2: r2 = PyMethod_New(__mypyc_self__, instance) return r2 def inner_f_obj_0.__call__(__mypyc_self__): __mypyc_self__ :: __main__.inner_f_obj_0 r0 :: __main__.f_env r1 :: str L0: r0 = __mypyc_self__.__mypyc_env__ r1 = 'f.inner: second definition' return r1 def f(flag): flag :: bool r0 :: __main__.f_env r1 :: __main__.inner_f_obj r2 :: bool inner :: object r3 :: __main__.inner_f_obj_0 r4 :: bool r5 :: object r6 :: str L0: r0 = f_env() if flag goto L1 else goto L2 :: bool L1: r1 = inner_f_obj() r1.__mypyc_env__ = r0; r2 = is_error inner = r1 goto L3 L2: r3 = inner_f_obj_0() r3.__mypyc_env__ = r0; r4 = is_error inner = r3 L3: r5 = PyObject_Vectorcall(inner, 0, 0, 0) r6 = cast(str, r5) return r6 [case testNestedFunctionsCallEachOther] from typing import Callable, List def f(a: int) -> int: def foo() -> int: return a + 1 def bar() -> int: return foo() def baz(n: int) -> int: if n == 0: return 0 return n + baz(n - 1) return bar() + baz(a) [out] def foo_f_obj.__get__(__mypyc_self__, instance, owner): __mypyc_self__, instance, owner, r0 :: object r1 :: bit r2 :: object L0: r0 = load_address _Py_NoneStruct r1 = instance == r0 if r1 goto L1 else goto L2 :: bool L1: return __mypyc_self__ L2: r2 = PyMethod_New(__mypyc_self__, instance) return r2 def foo_f_obj.__call__(__mypyc_self__): __mypyc_self__ :: __main__.foo_f_obj r0 :: __main__.f_env r1, r2 :: int L0: r0 = __mypyc_self__.__mypyc_env__ r1 = r0.a r2 = CPyTagged_Add(r1, 2) return r2 def bar_f_obj.__get__(__mypyc_self__, instance, owner): __mypyc_self__, instance, owner, r0 :: object r1 :: bit r2 :: object L0: r0 = load_address _Py_NoneStruct r1 = instance == r0 if r1 goto L1 else goto L2 :: bool L1: return __mypyc_self__ L2: r2 = PyMethod_New(__mypyc_self__, instance) return r2 def bar_f_obj.__call__(__mypyc_self__): __mypyc_self__ :: __main__.bar_f_obj r0 :: __main__.f_env r1, r2 :: object r3 :: int L0: r0 = __mypyc_self__.__mypyc_env__ r1 = r0.foo r2 = PyObject_Vectorcall(r1, 0, 0, 0) r3 = unbox(int, r2) return r3 def baz_f_obj.__get__(__mypyc_self__, instance, owner): __mypyc_self__, instance, owner, r0 :: object r1 :: bit r2 :: object L0: r0 = load_address _Py_NoneStruct r1 = instance == r0 if r1 goto L1 else goto L2 :: bool L1: return __mypyc_self__ L2: r2 = PyMethod_New(__mypyc_self__, instance) return r2 def baz_f_obj.__call__(__mypyc_self__, n): __mypyc_self__ :: __main__.baz_f_obj n :: int r0 :: __main__.f_env r1 :: bit r2 :: int r3, r4 :: object r5 :: object[1] r6 :: object_ptr r7 :: object r8, r9 :: int L0: r0 = __mypyc_self__.__mypyc_env__ r1 = int_eq n, 0 if r1 goto L1 else goto L2 :: bool L1: return 0 L2: r2 = CPyTagged_Subtract(n, 2) r3 = r0.baz r4 = box(int, r2) r5 = [r4] r6 = load_address r5 r7 = PyObject_Vectorcall(r3, r6, 1, 0) keep_alive r4 r8 = unbox(int, r7) r9 = CPyTagged_Add(n, r8) return r9 def f(a): a :: int r0 :: __main__.f_env r1 :: bool r2 :: __main__.foo_f_obj r3, r4 :: bool r5 :: __main__.bar_f_obj r6, r7 :: bool r8 :: __main__.baz_f_obj r9, r10 :: bool r11, r12 :: object r13, r14 :: int r15, r16 :: object r17 :: object[1] r18 :: object_ptr r19 :: object r20, r21 :: int L0: r0 = f_env() r0.a = a; r1 = is_error r2 = foo_f_obj() r2.__mypyc_env__ = r0; r3 = is_error r0.foo = r2; r4 = is_error r5 = bar_f_obj() r5.__mypyc_env__ = r0; r6 = is_error r0.bar = r5; r7 = is_error r8 = baz_f_obj() r8.__mypyc_env__ = r0; r9 = is_error r0.baz = r8; r10 = is_error r11 = r0.bar r12 = PyObject_Vectorcall(r11, 0, 0, 0) r13 = unbox(int, r12) r14 = r0.a r15 = r0.baz r16 = box(int, r14) r17 = [r16] r18 = load_address r17 r19 = PyObject_Vectorcall(r15, r18, 1, 0) keep_alive r16 r20 = unbox(int, r19) r21 = CPyTagged_Add(r13, r20) return r21 [case testLambdas] def f(x: int, y: int) -> None: s = lambda a, b: a + b t = lambda a, b: s(a, b) return t(x, y) [out] def __mypyc_lambda__0_f_obj.__get__(__mypyc_self__, instance, owner): __mypyc_self__, instance, owner, r0 :: object r1 :: bit r2 :: object L0: r0 = load_address _Py_NoneStruct r1 = instance == r0 if r1 goto L1 else goto L2 :: bool L1: return __mypyc_self__ L2: r2 = PyMethod_New(__mypyc_self__, instance) return r2 def __mypyc_lambda__0_f_obj.__call__(__mypyc_self__, a, b): __mypyc_self__ :: __main__.__mypyc_lambda__0_f_obj a, b :: object r0 :: __main__.f_env r1 :: object L0: r0 = __mypyc_self__.__mypyc_env__ r1 = PyNumber_Add(a, b) return r1 def __mypyc_lambda__1_f_obj.__get__(__mypyc_self__, instance, owner): __mypyc_self__, instance, owner, r0 :: object r1 :: bit r2 :: object L0: r0 = load_address _Py_NoneStruct r1 = instance == r0 if r1 goto L1 else goto L2 :: bool L1: return __mypyc_self__ L2: r2 = PyMethod_New(__mypyc_self__, instance) return r2 def __mypyc_lambda__1_f_obj.__call__(__mypyc_self__, a, b): __mypyc_self__ :: __main__.__mypyc_lambda__1_f_obj a, b :: object r0 :: __main__.f_env r1 :: object r2 :: object[2] r3 :: object_ptr r4 :: object L0: r0 = __mypyc_self__.__mypyc_env__ r1 = r0.s r2 = [a, b] r3 = load_address r2 r4 = PyObject_Vectorcall(r1, r3, 2, 0) keep_alive a, b return r4 def f(x, y): x, y :: int r0 :: __main__.f_env r1 :: __main__.__mypyc_lambda__0_f_obj r2, r3 :: bool r4 :: __main__.__mypyc_lambda__1_f_obj r5 :: bool t, r6, r7 :: object r8 :: object[2] r9 :: object_ptr r10 :: object r11 :: None L0: r0 = f_env() r1 = __mypyc_lambda__0_f_obj() r1.__mypyc_env__ = r0; r2 = is_error r0.s = r1; r3 = is_error r4 = __mypyc_lambda__1_f_obj() r4.__mypyc_env__ = r0; r5 = is_error t = r4 r6 = box(int, x) r7 = box(int, y) r8 = [r6, r7] r9 = load_address r8 r10 = PyObject_Vectorcall(t, r9, 2, 0) keep_alive r6, r7 r11 = unbox(None, r10) return r11 [case testRecursiveFunction] from typing import Callable def baz(n: int) -> int: if n == 0: return 0 return n + baz(n - 1) [out] def baz(n): n :: int r0 :: bit r1, r2, r3 :: int L0: r0 = int_eq n, 0 if r0 goto L1 else goto L2 :: bool L1: return 0 L2: r1 = CPyTagged_Subtract(n, 2) r2 = baz(r1) r3 = CPyTagged_Add(n, r2) return r3