[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, inner, r2 :: object L0: r0 = __mypyc_self__.__mypyc_env__ r1 = r0.inner inner = r1 r2 = box(None, 1) return r2 def a(): r0 :: __main__.a_env r1 :: __main__.inner_a_obj r2, r3 :: bool r4 :: object L0: r0 = a_env() r1 = inner_a_obj() r1.__mypyc_env__ = r0; r2 = is_error r0.inner = r1; r3 = is_error r4 = r0.inner return r4 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, second :: object r3 :: str L0: r0 = __mypyc_self__.__mypyc_env__ r1 = r0.__mypyc_env__ r2 = r0.second second = r2 r3 = 'b.first.second: nested function' return r3 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, first :: object r2 :: __main__.first_b_env r3 :: bool r4 :: __main__.second_b_first_obj r5, r6 :: bool r7 :: object L0: r0 = __mypyc_self__.__mypyc_env__ r1 = r0.first first = r1 r2 = first_b_env() r2.__mypyc_env__ = r0; r3 = is_error r4 = second_b_first_obj() r4.__mypyc_env__ = r2; r5 = is_error r2.second = r4; r6 = is_error r7 = r2.second return r7 def b(): r0 :: __main__.b_env r1 :: __main__.first_b_obj r2, r3 :: bool r4 :: object L0: r0 = b_env() r1 = first_b_obj() r1.__mypyc_env__ = r0; r2 = is_error r0.first = r1; r3 = is_error r4 = r0.first return r4 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, inner :: object r2, r3 :: str L0: r0 = __mypyc_self__.__mypyc_env__ r1 = r0.inner inner = r1 r2 = '!' r3 = PyUnicode_Concat(s, r2) return r3 def c(num): num :: float r0 :: __main__.c_env r1 :: __main__.inner_c_obj r2, r3 :: bool r4 :: object L0: r0 = c_env() r1 = inner_c_obj() r1.__mypyc_env__ = r0; r2 = is_error r0.inner = r1; r3 = is_error r4 = r0.inner return r4 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, inner :: object r2, r3 :: str L0: r0 = __mypyc_self__.__mypyc_env__ r1 = r0.inner inner = r1 r2 = '?' r3 = PyUnicode_Concat(s, r2) return r3 def d(num): num :: float r0 :: __main__.d_env r1 :: __main__.inner_d_obj r2, r3 :: bool r4 :: str r5, r6 :: object r7, a, r8 :: str r9, r10 :: object r11, b :: str L0: r0 = d_env() r1 = inner_d_obj() r1.__mypyc_env__ = r0; r2 = is_error r0.inner = r1; r3 = is_error r4 = 'one' r5 = r0.inner r6 = PyObject_CallFunctionObjArgs(r5, r4, 0) r7 = cast(str, r6) a = r7 r8 = 'two' r9 = r0.inner r10 = PyObject_CallFunctionObjArgs(r9, r8, 0) r11 = cast(str, r10) b = r11 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, inner :: object r2 :: int L0: r0 = __mypyc_self__.__mypyc_env__ r1 = r0.inner inner = r1 r2 = r0.num return r2 def a(num): num :: int r0 :: __main__.a_env r1 :: bool r2 :: __main__.inner_a_obj r3, r4 :: bool r5, r6 :: object r7 :: int L0: r0 = a_env() r0.num = num; r1 = is_error r2 = inner_a_obj() r2.__mypyc_env__ = r0; r3 = is_error r0.inner = r2; r4 = is_error r5 = r0.inner r6 = PyObject_CallFunctionObjArgs(r5, 0) r7 = unbox(int, r6) return r7 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, inner :: object r2 :: bool foo, r3 :: int L0: r0 = __mypyc_self__.__mypyc_env__ r1 = r0.inner inner = r1 r0.num = 8; r2 = is_error foo = 12 r3 = r0.num return r3 def b(): r0 :: __main__.b_env r1 :: bool r2 :: __main__.inner_b_obj r3, r4 :: bool r5, r6 :: object r7, r8, r9 :: int L0: r0 = b_env() r0.num = 6; r1 = is_error r2 = inner_b_obj() r2.__mypyc_env__ = r0; r3 = is_error r0.inner = r2; r4 = is_error r5 = r0.inner r6 = PyObject_CallFunctionObjArgs(r5, 0) r7 = unbox(int, r6) r8 = r0.num r9 = CPyTagged_Add(r7, r8) return r9 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, inner :: object r2 :: str L0: r0 = __mypyc_self__.__mypyc_env__ r1 = r0.inner inner = r1 r2 = 'f.inner: first definition' return r2 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, inner :: object r2 :: str L0: r0 = __mypyc_self__.__mypyc_env__ r1 = r0.inner inner = r1 r2 = 'f.inner: second definition' return r2 def c(flag): flag :: bool r0 :: __main__.c_env r1 :: __main__.inner_c_obj r2, r3 :: bool r4 :: __main__.inner_c_obj_0 r5, r6 :: bool r7, r8 :: object r9 :: 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 r0.inner = r1; r3 = is_error goto L3 L2: r4 = inner_c_obj_0() r4.__mypyc_env__ = r0; r5 = is_error r0.inner = r4; r6 = is_error L3: r7 = r0.inner r8 = PyObject_CallFunctionObjArgs(r7, 0) r9 = cast(str, r8) return r9 [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, c :: object r3 :: int L0: r0 = __mypyc_self__.__mypyc_env__ r1 = r0.__mypyc_env__ r2 = r0.c c = r2 r3 = r1.x return r3 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, b :: object r2 :: __main__.b_a_env r3 :: bool r4, r5 :: int r6 :: bool r7 :: __main__.c_a_b_obj r8, r9 :: bool r10, r11 :: object r12 :: int L0: r0 = __mypyc_self__.__mypyc_env__ r1 = r0.b b = r1 r2 = b_a_env() r2.__mypyc_env__ = r0; r3 = is_error r4 = r0.x r5 = CPyTagged_Add(r4, 2) r0.x = r5; r6 = is_error r7 = c_a_b_obj() r7.__mypyc_env__ = r2; r8 = is_error r2.c = r7; r9 = is_error r10 = r2.c r11 = PyObject_CallFunctionObjArgs(r10, 0) r12 = unbox(int, r11) return r12 def a(): r0 :: __main__.a_env r1 :: bool r2 :: __main__.b_a_obj r3, r4 :: bool r5, r6 :: object r7 :: int L0: r0 = a_env() r0.x = 2; r1 = is_error r2 = b_a_obj() r2.__mypyc_env__ = r0; r3 = is_error r0.b = r2; r4 = is_error r5 = r0.b r6 = PyObject_CallFunctionObjArgs(r5, 0) r7 = unbox(int, r6) return r7 [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, inner :: object r2 :: str L0: r0 = __mypyc_self__.__mypyc_env__ r1 = r0.inner inner = r1 r2 = 'f.inner: first definition' return r2 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, inner :: object r2 :: str L0: r0 = __mypyc_self__.__mypyc_env__ r1 = r0.inner inner = r1 r2 = 'f.inner: second definition' return r2 def f(flag): flag :: bool r0 :: __main__.f_env r1 :: __main__.inner_f_obj r2, r3 :: bool r4 :: __main__.inner_f_obj_0 r5, r6 :: bool r7, r8 :: object r9 :: 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 r0.inner = r1; r3 = is_error goto L3 L2: r4 = inner_f_obj_0() r4.__mypyc_env__ = r0; r5 = is_error r0.inner = r4; r6 = is_error L3: r7 = r0.inner r8 = PyObject_CallFunctionObjArgs(r7, 0) r9 = cast(str, r8) return r9 [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, foo :: object r2, r3 :: int L0: r0 = __mypyc_self__.__mypyc_env__ r1 = r0.foo foo = r1 r2 = r0.a r3 = CPyTagged_Add(r2, 2) return r3 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, bar, r2, r3 :: object r4 :: int L0: r0 = __mypyc_self__.__mypyc_env__ r1 = r0.bar bar = r1 r2 = r0.foo r3 = PyObject_CallFunctionObjArgs(r2, 0) r4 = unbox(int, r3) return r4 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, baz :: object r2 :: bit r3 :: int r4, r5 :: object r6, r7 :: int L0: r0 = __mypyc_self__.__mypyc_env__ r1 = r0.baz baz = r1 r2 = n == 0 if r2 goto L1 else goto L2 :: bool L1: return 0 L2: r3 = CPyTagged_Subtract(n, 2) r4 = box(int, r3) r5 = PyObject_CallFunctionObjArgs(baz, r4, 0) r6 = unbox(int, r5) r7 = CPyTagged_Add(n, r6) return r7 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, r17 :: object r18, r19 :: 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_CallFunctionObjArgs(r11, 0) r13 = unbox(int, r12) r14 = r0.a r15 = r0.baz r16 = box(int, r14) r17 = PyObject_CallFunctionObjArgs(r15, r16, 0) r18 = unbox(int, r17) r19 = CPyTagged_Add(r13, r18) return r19 [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, r2 :: object L0: r0 = __mypyc_self__.__mypyc_env__ r1 = r0.s r2 = PyObject_CallFunctionObjArgs(r1, a, b, 0) return r2 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, r8 :: object r9 :: 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 = PyObject_CallFunctionObjArgs(t, r6, r7, 0) r9 = unbox(None, r8) return r9 [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 = 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