diff --git a/mypyc/irbuild/builder.py b/mypyc/irbuild/builder.py index 8c68f91bf633..0757415f6753 100644 --- a/mypyc/irbuild/builder.py +++ b/mypyc/irbuild/builder.py @@ -502,6 +502,11 @@ def non_function_scope(self) -> bool: # Currently the stack always has at least two items: dummy and top-level. return len(self.fn_infos) <= 2 + def top_level_fn_info(self) -> FuncInfo | None: + if self.non_function_scope(): + return None + return self.fn_infos[2] + def init_final_static( self, lvalue: Lvalue, diff --git a/mypyc/irbuild/context.py b/mypyc/irbuild/context.py index 676afb507504..a740f0b821d9 100644 --- a/mypyc/irbuild/context.py +++ b/mypyc/irbuild/context.py @@ -22,6 +22,7 @@ def __init__( contains_nested: bool = False, is_decorated: bool = False, in_non_ext: bool = False, + add_nested_funcs_to_env: bool = False, ) -> None: self.fitem = fitem self.name = name @@ -47,6 +48,7 @@ def __init__( self.contains_nested = contains_nested self.is_decorated = is_decorated self.in_non_ext = in_non_ext + self.add_nested_funcs_to_env = add_nested_funcs_to_env # TODO: add field for ret_type: RType = none_rprimitive diff --git a/mypyc/irbuild/env_class.py b/mypyc/irbuild/env_class.py index ded8072deb63..aa223fe20176 100644 --- a/mypyc/irbuild/env_class.py +++ b/mypyc/irbuild/env_class.py @@ -107,7 +107,7 @@ def load_env_registers(builder: IRBuilder) -> None: load_outer_envs(builder, fn_info.callable_class) # If this is a FuncDef, then make sure to load the FuncDef into its own environment # class so that the function can be called recursively. - if isinstance(fitem, FuncDef): + if isinstance(fitem, FuncDef) and fn_info.add_nested_funcs_to_env: setup_func_for_recursive_call(builder, fitem, fn_info.callable_class) diff --git a/mypyc/irbuild/function.py b/mypyc/irbuild/function.py index 822350ea829b..ebf7fa9a54de 100644 --- a/mypyc/irbuild/function.py +++ b/mypyc/irbuild/function.py @@ -19,6 +19,7 @@ ArgKind, ClassDef, Decorator, + FuncBase, FuncDef, FuncItem, LambdaExpr, @@ -222,6 +223,7 @@ def c() -> None: is_decorated = fitem in builder.fdefs_to_decorators is_singledispatch = fitem in builder.singledispatch_impls in_non_ext = False + add_nested_funcs_to_env = has_nested_func_self_reference(builder, fitem) class_name = None if cdef: ir = builder.mapper.type_to_ir[cdef.info] @@ -234,14 +236,15 @@ def c() -> None: func_name = name builder.enter( FuncInfo( - fitem, - func_name, - class_name, - gen_func_ns(builder), - is_nested, - contains_nested, - is_decorated, - in_non_ext, + fitem=fitem, + name=func_name, + class_name=class_name, + namespace=gen_func_ns(builder), + is_nested=is_nested, + contains_nested=contains_nested, + is_decorated=is_decorated, + in_non_ext=in_non_ext, + add_nested_funcs_to_env=add_nested_funcs_to_env, ) ) @@ -267,7 +270,13 @@ def c() -> None: builder.enter(fn_info) setup_env_for_generator_class(builder) load_outer_envs(builder, builder.fn_info.generator_class) - if builder.fn_info.is_nested and isinstance(fitem, FuncDef): + top_level = builder.top_level_fn_info() + if ( + builder.fn_info.is_nested + and isinstance(fitem, FuncDef) + and top_level + and top_level.add_nested_funcs_to_env + ): setup_func_for_recursive_call(builder, fitem, builder.fn_info.generator_class) create_switch_for_generator_class(builder) add_raise_exception_blocks_to_generator_class(builder, fitem.line) @@ -344,6 +353,20 @@ def c() -> None: return func_ir, func_reg +def has_nested_func_self_reference(builder: IRBuilder, fitem: FuncItem) -> bool: + """Does a nested function contain a self-reference in its body? + + If a nested function only has references in the surrounding function, + we don't need to add it to the environment. + """ + if any(isinstance(sym, FuncBase) for sym in builder.free_variables.get(fitem, set())): + return True + return any( + has_nested_func_self_reference(builder, nested) + for nested in builder.encapsulating_funcs.get(fitem, []) + ) + + def gen_func_ir( builder: IRBuilder, args: list[Register], @@ -768,7 +791,7 @@ def get_func_target(builder: IRBuilder, fdef: FuncDef) -> AssignmentTarget: # Get the target associated with the previously defined FuncDef. return builder.lookup(fdef.original_def) - if builder.fn_info.is_generator or builder.fn_info.contains_nested: + if builder.fn_info.is_generator or builder.fn_info.add_nested_funcs_to_env: return builder.lookup(fdef) return builder.add_local_reg(fdef, object_rprimitive) diff --git a/mypyc/test-data/irbuild-basic.test b/mypyc/test-data/irbuild-basic.test index 33fc8cfaa83b..bf608abb87ad 100644 --- a/mypyc/test-data/irbuild-basic.test +++ b/mypyc/test-data/irbuild-basic.test @@ -2694,47 +2694,43 @@ L2: def g_a_obj.__call__(__mypyc_self__): __mypyc_self__ :: __main__.g_a_obj r0 :: __main__.a_env - r1, g :: object - r2 :: str - r3 :: object - r4 :: str - r5, r6, r7, r8 :: object - r9 :: str - r10 :: object - r11 :: str - r12, r13 :: object + r1 :: str + r2 :: object + r3 :: str + r4, r5, r6, r7 :: object + r8 :: str + r9 :: object + r10 :: str + r11, r12 :: object L0: r0 = __mypyc_self__.__mypyc_env__ - r1 = r0.g - g = r1 - r2 = 'Entering' - r3 = builtins :: module - r4 = 'print' - r5 = CPyObject_GetAttr(r3, r4) - r6 = PyObject_CallFunctionObjArgs(r5, r2, 0) - r7 = r0.f - r8 = PyObject_CallFunctionObjArgs(r7, 0) - r9 = 'Exited' - r10 = builtins :: module - r11 = 'print' - r12 = CPyObject_GetAttr(r10, r11) - r13 = PyObject_CallFunctionObjArgs(r12, r9, 0) + r1 = 'Entering' + r2 = builtins :: module + r3 = 'print' + r4 = CPyObject_GetAttr(r2, r3) + r5 = PyObject_CallFunctionObjArgs(r4, r1, 0) + r6 = r0.f + r7 = PyObject_CallFunctionObjArgs(r6, 0) + r8 = 'Exited' + r9 = builtins :: module + r10 = 'print' + r11 = CPyObject_GetAttr(r9, r10) + r12 = PyObject_CallFunctionObjArgs(r11, r8, 0) return 1 def a(f): f :: object r0 :: __main__.a_env r1 :: bool r2 :: __main__.g_a_obj - r3, r4 :: bool - r5 :: object + r3 :: bool + g :: object L0: r0 = a_env() r0.f = f; r1 = is_error r2 = g_a_obj() r2.__mypyc_env__ = r0; r3 = is_error - r0.g = r2; r4 = is_error - r5 = r0.g - return r5 + g = r2 + return g def g_b_obj.__get__(__mypyc_self__, instance, owner): __mypyc_self__, instance, owner, r0 :: object r1 :: bit @@ -2751,47 +2747,43 @@ L2: def g_b_obj.__call__(__mypyc_self__): __mypyc_self__ :: __main__.g_b_obj r0 :: __main__.b_env - r1, g :: object - r2 :: str - r3 :: object - r4 :: str - r5, r6, r7, r8 :: object - r9 :: str - r10 :: object - r11 :: str - r12, r13 :: object + r1 :: str + r2 :: object + r3 :: str + r4, r5, r6, r7 :: object + r8 :: str + r9 :: object + r10 :: str + r11, r12 :: object L0: r0 = __mypyc_self__.__mypyc_env__ - r1 = r0.g - g = r1 - r2 = '---' - r3 = builtins :: module - r4 = 'print' - r5 = CPyObject_GetAttr(r3, r4) - r6 = PyObject_CallFunctionObjArgs(r5, r2, 0) - r7 = r0.f - r8 = PyObject_CallFunctionObjArgs(r7, 0) - r9 = '---' - r10 = builtins :: module - r11 = 'print' - r12 = CPyObject_GetAttr(r10, r11) - r13 = PyObject_CallFunctionObjArgs(r12, r9, 0) + r1 = '---' + r2 = builtins :: module + r3 = 'print' + r4 = CPyObject_GetAttr(r2, r3) + r5 = PyObject_CallFunctionObjArgs(r4, r1, 0) + r6 = r0.f + r7 = PyObject_CallFunctionObjArgs(r6, 0) + r8 = '---' + r9 = builtins :: module + r10 = 'print' + r11 = CPyObject_GetAttr(r9, r10) + r12 = PyObject_CallFunctionObjArgs(r11, r8, 0) return 1 def b(f): f :: object r0 :: __main__.b_env r1 :: bool r2 :: __main__.g_b_obj - r3, r4 :: bool - r5 :: object + r3 :: bool + g :: object L0: r0 = b_env() r0.f = f; r1 = is_error r2 = g_b_obj() r2.__mypyc_env__ = r0; r3 = is_error - r0.g = r2; r4 = is_error - r5 = r0.g - return r5 + g = r2 + return g def d_c_obj.__get__(__mypyc_self__, instance, owner): __mypyc_self__, instance, owner, r0 :: object r1 :: bit @@ -2808,20 +2800,17 @@ L2: def d_c_obj.__call__(__mypyc_self__): __mypyc_self__ :: __main__.d_c_obj r0 :: __main__.c_env - r1, d :: object - r2 :: str - r3 :: object - r4 :: str - r5, r6 :: object + r1 :: str + r2 :: object + r3 :: str + r4, r5 :: object L0: r0 = __mypyc_self__.__mypyc_env__ - r1 = r0.d - d = r1 - r2 = 'd' - r3 = builtins :: module - r4 = 'print' - r5 = CPyObject_GetAttr(r3, r4) - r6 = PyObject_CallFunctionObjArgs(r5, r2, 0) + r1 = 'd' + r2 = builtins :: module + r3 = 'print' + r4 = CPyObject_GetAttr(r2, r3) + r5 = PyObject_CallFunctionObjArgs(r4, r1, 0) return 1 def c(): r0 :: __main__.c_env @@ -2832,16 +2821,15 @@ def c(): r5, r6 :: object r7 :: dict r8 :: str - r9, r10 :: object - r11 :: bool - r12 :: dict - r13 :: str - r14 :: i32 - r15 :: bit - r16 :: str - r17 :: object - r18 :: str - r19, r20, r21, r22 :: object + r9, r10, d :: object + r11 :: dict + r12 :: str + r13 :: i32 + r14 :: bit + r15 :: str + r16 :: object + r17 :: str + r18, r19, r20 :: object L0: r0 = c_env() r1 = d_c_obj() @@ -2854,18 +2842,17 @@ L0: r8 = 'a' r9 = CPyDict_GetItem(r7, r8) r10 = PyObject_CallFunctionObjArgs(r9, r6, 0) - r0.d = r10; r11 = is_error - r12 = __main__.globals :: static - r13 = 'd' - r14 = CPyDict_SetItem(r12, r13, r10) - r15 = r14 >= 0 :: signed - r16 = 'c' - r17 = builtins :: module - r18 = 'print' - r19 = CPyObject_GetAttr(r17, r18) - r20 = PyObject_CallFunctionObjArgs(r19, r16, 0) - r21 = r0.d - r22 = PyObject_CallFunctionObjArgs(r21, 0) + d = r10 + r11 = __main__.globals :: static + r12 = 'd' + r13 = CPyDict_SetItem(r11, r12, r10) + r14 = r13 >= 0 :: signed + r15 = 'c' + r16 = builtins :: module + r17 = 'print' + r18 = CPyObject_GetAttr(r16, r17) + r19 = PyObject_CallFunctionObjArgs(r18, r15, 0) + r20 = PyObject_CallFunctionObjArgs(d, 0) return 1 def __top_level__(): r0, r1 :: object @@ -2947,47 +2934,43 @@ L2: def g_a_obj.__call__(__mypyc_self__): __mypyc_self__ :: __main__.g_a_obj r0 :: __main__.a_env - r1, g :: object - r2 :: str - r3 :: object - r4 :: str - r5, r6, r7, r8 :: object - r9 :: str - r10 :: object - r11 :: str - r12, r13 :: object + r1 :: str + r2 :: object + r3 :: str + r4, r5, r6, r7 :: object + r8 :: str + r9 :: object + r10 :: str + r11, r12 :: object L0: r0 = __mypyc_self__.__mypyc_env__ - r1 = r0.g - g = r1 - r2 = 'Entering' - r3 = builtins :: module - r4 = 'print' - r5 = CPyObject_GetAttr(r3, r4) - r6 = PyObject_CallFunctionObjArgs(r5, r2, 0) - r7 = r0.f - r8 = PyObject_CallFunctionObjArgs(r7, 0) - r9 = 'Exited' - r10 = builtins :: module - r11 = 'print' - r12 = CPyObject_GetAttr(r10, r11) - r13 = PyObject_CallFunctionObjArgs(r12, r9, 0) + r1 = 'Entering' + r2 = builtins :: module + r3 = 'print' + r4 = CPyObject_GetAttr(r2, r3) + r5 = PyObject_CallFunctionObjArgs(r4, r1, 0) + r6 = r0.f + r7 = PyObject_CallFunctionObjArgs(r6, 0) + r8 = 'Exited' + r9 = builtins :: module + r10 = 'print' + r11 = CPyObject_GetAttr(r9, r10) + r12 = PyObject_CallFunctionObjArgs(r11, r8, 0) return 1 def a(f): f :: object r0 :: __main__.a_env r1 :: bool r2 :: __main__.g_a_obj - r3, r4 :: bool - r5 :: object + r3 :: bool + g :: object L0: r0 = a_env() r0.f = f; r1 = is_error r2 = g_a_obj() r2.__mypyc_env__ = r0; r3 = is_error - r0.g = r2; r4 = is_error - r5 = r0.g - return r5 + g = r2 + return g def __top_level__(): r0, r1 :: object r2 :: bit diff --git a/mypyc/test-data/irbuild-nested.test b/mypyc/test-data/irbuild-nested.test index adef80263533..b2b884705366 100644 --- a/mypyc/test-data/irbuild-nested.test +++ b/mypyc/test-data/irbuild-nested.test @@ -50,25 +50,22 @@ L2: def inner_a_obj.__call__(__mypyc_self__): __mypyc_self__ :: __main__.inner_a_obj r0 :: __main__.a_env - r1, inner, r2 :: object + r1 :: object L0: r0 = __mypyc_self__.__mypyc_env__ - r1 = r0.inner - inner = r1 - r2 = box(None, 1) - return r2 + r1 = box(None, 1) + return r1 def a(): r0 :: __main__.a_env r1 :: __main__.inner_a_obj - r2, r3 :: bool - r4 :: object + r2 :: bool + inner :: 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 + inner = r1 + return inner def second_b_first_obj.__get__(__mypyc_self__, instance, owner): __mypyc_self__, instance, owner, r0 :: object r1 :: bit @@ -86,15 +83,12 @@ 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 + r2 :: str L0: r0 = __mypyc_self__.__mypyc_env__ r1 = r0.__mypyc_env__ - r2 = r0.second - second = r2 - r3 = 'b.first.second: nested function' - return r3 + 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 @@ -111,35 +105,30 @@ L2: 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 + r1 :: __main__.first_b_env + r2 :: bool + r3 :: __main__.second_b_first_obj + r4 :: bool + second :: 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 + 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, r3 :: bool - r4 :: object + r2 :: bool + first :: 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 + first = r1 + return first def inner_c_obj.__get__(__mypyc_self__, instance, owner): __mypyc_self__, instance, owner, r0 :: object r1 :: bit @@ -157,28 +146,24 @@ 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 + r1, r2 :: str L0: r0 = __mypyc_self__.__mypyc_env__ - r1 = r0.inner - inner = r1 - r2 = '!' - r3 = PyUnicode_Concat(s, r2) - return r3 + r1 = '!' + r2 = PyUnicode_Concat(s, r1) + return r2 def c(num): num :: float r0 :: __main__.c_env r1 :: __main__.inner_c_obj - r2, r3 :: bool - r4 :: object + r2 :: bool + inner :: 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 + inner = r1 + return inner def inner_d_obj.__get__(__mypyc_self__, instance, owner): __mypyc_self__, instance, owner, r0 :: object r1 :: bit @@ -196,40 +181,36 @@ 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 + r1, r2 :: str L0: r0 = __mypyc_self__.__mypyc_env__ - r1 = r0.inner - inner = r1 - r2 = '?' - r3 = PyUnicode_Concat(s, r2) - return r3 + r1 = '?' + r2 = PyUnicode_Concat(s, r1) + return r2 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 + r2 :: bool + inner :: object + r3 :: str + r4 :: object + r5, a, r6 :: str + r7 :: object + r8, 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 + inner = r1 + r3 = 'one' + r4 = PyObject_CallFunctionObjArgs(inner, r3, 0) + r5 = cast(str, r4) + a = r5 + r6 = 'two' + r7 = PyObject_CallFunctionObjArgs(inner, r6, 0) + r8 = cast(str, r7) + b = r8 return a def inner(): r0 :: str @@ -290,32 +271,28 @@ L2: def inner_a_obj.__call__(__mypyc_self__): __mypyc_self__ :: __main__.inner_a_obj r0 :: __main__.a_env - r1, inner :: object - r2 :: int + r1 :: int L0: r0 = __mypyc_self__.__mypyc_env__ - r1 = r0.inner - inner = r1 - r2 = r0.num - return r2 + r1 = r0.num + return r1 def a(num): num :: int r0 :: __main__.a_env r1 :: bool r2 :: __main__.inner_a_obj - r3, r4 :: bool - r5, r6 :: object - r7 :: int + 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 - r0.inner = r2; r4 = is_error - r5 = r0.inner - r6 = PyObject_CallFunctionObjArgs(r5, 0) - r7 = unbox(int, r6) - return r7 + inner = r2 + r4 = PyObject_CallFunctionObjArgs(inner, 0) + r5 = unbox(int, r4) + return r5 def inner_b_obj.__get__(__mypyc_self__, instance, owner): __mypyc_self__, instance, owner, r0 :: object r1 :: bit @@ -332,36 +309,32 @@ L2: 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 + r1 :: bool + foo, r2 :: int L0: r0 = __mypyc_self__.__mypyc_env__ - r1 = r0.inner - inner = r1 - r0.num = 8; r2 = is_error + r0.num = 8; r1 = is_error foo = 12 - r3 = r0.num - return r3 + r2 = r0.num + return r2 def b(): r0 :: __main__.b_env r1 :: bool r2 :: __main__.inner_b_obj - r3, r4 :: bool - r5, r6 :: object - r7, r8, r9 :: int + 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 - 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 + inner = r2 + r4 = PyObject_CallFunctionObjArgs(inner, 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 @@ -378,14 +351,11 @@ L2: def inner_c_obj.__call__(__mypyc_self__): __mypyc_self__ :: __main__.inner_c_obj r0 :: __main__.c_env - r1, inner :: object - r2 :: str + r1 :: str L0: r0 = __mypyc_self__.__mypyc_env__ - r1 = r0.inner - inner = r1 - r2 = 'f.inner: first definition' - return r2 + 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 @@ -402,40 +372,37 @@ L2: def inner_c_obj_0.__call__(__mypyc_self__): __mypyc_self__ :: __main__.inner_c_obj_0 r0 :: __main__.c_env - r1, inner :: object - r2 :: str + r1 :: str L0: r0 = __mypyc_self__.__mypyc_env__ - r1 = r0.inner - inner = r1 - r2 = 'f.inner: second definition' - return r2 + r1 = 'f.inner: second definition' + return r1 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 + 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 - r0.inner = r1; r3 = is_error + inner = r1 goto L3 L2: - r4 = inner_c_obj_0() - r4.__mypyc_env__ = r0; r5 = is_error - r0.inner = r4; r6 = is_error + r3 = inner_c_obj_0() + r3.__mypyc_env__ = r0; r4 = is_error + inner = r3 L3: - r7 = r0.inner - r8 = PyObject_CallFunctionObjArgs(r7, 0) - r9 = cast(str, r8) - return r9 + r5 = PyObject_CallFunctionObjArgs(inner, 0) + r6 = cast(str, r5) + return r6 [case testSpecialNested] def a() -> int: @@ -465,15 +432,12 @@ 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 + r2 :: int L0: r0 = __mypyc_self__.__mypyc_env__ r1 = r0.__mypyc_env__ - r2 = r0.c - c = r2 - r3 = r1.x - return r3 + r2 = r1.x + return r2 def b_a_obj.__get__(__mypyc_self__, instance, owner): __mypyc_self__, instance, owner, r0 :: object r1 :: bit @@ -490,48 +454,43 @@ L2: 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 + 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 = 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 + 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_CallFunctionObjArgs(c, 0) + r9 = unbox(int, r8) + return r9 def a(): r0 :: __main__.a_env r1 :: bool r2 :: __main__.b_a_obj - r3, r4 :: bool - r5, r6 :: object - r7 :: int + 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 - r0.b = r2; r4 = is_error - r5 = r0.b - r6 = PyObject_CallFunctionObjArgs(r5, 0) - r7 = unbox(int, r6) - return r7 + b = r2 + r4 = PyObject_CallFunctionObjArgs(b, 0) + r5 = unbox(int, r4) + return r5 [case testNestedFunctionInsideStatements] def f(flag: bool) -> str: @@ -559,14 +518,11 @@ L2: def inner_f_obj.__call__(__mypyc_self__): __mypyc_self__ :: __main__.inner_f_obj r0 :: __main__.f_env - r1, inner :: object - r2 :: str + r1 :: str L0: r0 = __mypyc_self__.__mypyc_env__ - r1 = r0.inner - inner = r1 - r2 = 'f.inner: first definition' - return r2 + 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 @@ -583,40 +539,37 @@ L2: def inner_f_obj_0.__call__(__mypyc_self__): __mypyc_self__ :: __main__.inner_f_obj_0 r0 :: __main__.f_env - r1, inner :: object - r2 :: str + r1 :: str L0: r0 = __mypyc_self__.__mypyc_env__ - r1 = r0.inner - inner = r1 - r2 = 'f.inner: second definition' - return r2 + r1 = 'f.inner: second definition' + return r1 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 + 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 - r0.inner = r1; r3 = is_error + inner = r1 goto L3 L2: - r4 = inner_f_obj_0() - r4.__mypyc_env__ = r0; r5 = is_error - r0.inner = r4; r6 = is_error + r3 = inner_f_obj_0() + r3.__mypyc_env__ = r0; r4 = is_error + inner = r3 L3: - r7 = r0.inner - r8 = PyObject_CallFunctionObjArgs(r7, 0) - r9 = cast(str, r8) - return r9 + r5 = PyObject_CallFunctionObjArgs(inner, 0) + r6 = cast(str, r5) + return r6 [case testNestedFunctionsCallEachOther] from typing import Callable, List @@ -652,15 +605,12 @@ L2: def foo_f_obj.__call__(__mypyc_self__): __mypyc_self__ :: __main__.foo_f_obj r0 :: __main__.f_env - r1, foo :: object - r2, r3 :: int + r1, r2 :: int L0: r0 = __mypyc_self__.__mypyc_env__ - r1 = r0.foo - foo = r1 - r2 = r0.a - r3 = CPyTagged_Add(r2, 2) - return r3 + 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 @@ -677,16 +627,14 @@ L2: def bar_f_obj.__call__(__mypyc_self__): __mypyc_self__ :: __main__.bar_f_obj r0 :: __main__.f_env - r1, bar, r2, r3 :: object - r4 :: int + r1, r2 :: object + r3 :: 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 + r1 = r0.foo + r2 = PyObject_CallFunctionObjArgs(r1, 0) + r3 = unbox(int, r2) + return r3 def baz_f_obj.__get__(__mypyc_self__, instance, owner): __mypyc_self__, instance, owner, r0 :: object r1 :: bit @@ -704,23 +652,21 @@ 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 + r1 :: bit + r2 :: int + r3, 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 + r1 = n == 0 + if r1 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) + r2 = CPyTagged_Subtract(n, 2) + r3 = r0.baz + r4 = box(int, r2) + r5 = PyObject_CallFunctionObjArgs(r3, r4, 0) r6 = unbox(int, r5) r7 = CPyTagged_Add(n, r6) return r7