|
25 | 25 | FuncItem, |
26 | 26 | LambdaExpr, |
27 | 27 | OverloadedFuncDef, |
28 | | - SymbolNode, |
29 | 28 | TypeInfo, |
30 | 29 | Var, |
31 | 30 | ) |
|
44 | 43 | from mypyc.ir.ops import ( |
45 | 44 | BasicBlock, |
46 | 45 | GetAttr, |
47 | | - InitStatic, |
48 | 46 | Integer, |
49 | 47 | LoadAddress, |
50 | 48 | LoadLiteral, |
|
62 | 60 | int_rprimitive, |
63 | 61 | object_rprimitive, |
64 | 62 | ) |
65 | | -from mypyc.irbuild.builder import IRBuilder, SymbolTarget, gen_arg_defaults |
| 63 | +from mypyc.irbuild.builder import IRBuilder, calculate_arg_defaults, gen_arg_defaults |
66 | 64 | from mypyc.irbuild.callable_class import ( |
67 | 65 | add_call_to_callable_class, |
68 | 66 | add_get_to_callable_class, |
69 | 67 | instantiate_callable_class, |
70 | 68 | setup_callable_class, |
71 | 69 | ) |
72 | | -from mypyc.irbuild.context import FuncInfo, ImplicitClass |
| 70 | +from mypyc.irbuild.context import FuncInfo |
73 | 71 | from mypyc.irbuild.env_class import ( |
| 72 | + add_vars_to_env, |
74 | 73 | finalize_env_class, |
75 | 74 | load_env_registers, |
76 | | - load_outer_envs, |
77 | 75 | setup_env_class, |
78 | | - setup_func_for_recursive_call, |
79 | | -) |
80 | | -from mypyc.irbuild.generator import ( |
81 | | - add_methods_to_generator_class, |
82 | | - add_raise_exception_blocks_to_generator_class, |
83 | | - create_switch_for_generator_class, |
84 | | - gen_generator_func, |
85 | | - populate_switch_for_generator_class, |
86 | | - setup_env_for_generator_class, |
87 | 76 | ) |
| 77 | +from mypyc.irbuild.generator import gen_generator_func, gen_generator_func_body |
88 | 78 | from mypyc.irbuild.targets import AssignmentTarget |
89 | | -from mypyc.irbuild.util import is_constant |
90 | 79 | from mypyc.primitives.dict_ops import dict_get_method_with_none, dict_new_op, dict_set_item_op |
91 | 80 | from mypyc.primitives.generic_ops import py_setattr_op |
92 | 81 | from mypyc.primitives.misc_ops import register_function |
@@ -235,123 +224,77 @@ def c() -> None: |
235 | 224 | func_name = singledispatch_main_func_name(name) |
236 | 225 | else: |
237 | 226 | func_name = name |
238 | | - builder.enter( |
239 | | - FuncInfo( |
240 | | - fitem=fitem, |
241 | | - name=func_name, |
242 | | - class_name=class_name, |
243 | | - namespace=gen_func_ns(builder), |
244 | | - is_nested=is_nested, |
245 | | - contains_nested=contains_nested, |
246 | | - is_decorated=is_decorated, |
247 | | - in_non_ext=in_non_ext, |
248 | | - add_nested_funcs_to_env=add_nested_funcs_to_env, |
249 | | - ) |
| 227 | + |
| 228 | + fn_info = FuncInfo( |
| 229 | + fitem=fitem, |
| 230 | + name=func_name, |
| 231 | + class_name=class_name, |
| 232 | + namespace=gen_func_ns(builder), |
| 233 | + is_nested=is_nested, |
| 234 | + contains_nested=contains_nested, |
| 235 | + is_decorated=is_decorated, |
| 236 | + in_non_ext=in_non_ext, |
| 237 | + add_nested_funcs_to_env=add_nested_funcs_to_env, |
250 | 238 | ) |
| 239 | + is_generator = fn_info.is_generator |
| 240 | + builder.enter(fn_info, ret_type=sig.ret_type) |
251 | 241 |
|
252 | 242 | # Functions that contain nested functions need an environment class to store variables that |
253 | 243 | # are free in their nested functions. Generator functions need an environment class to |
254 | 244 | # store a variable denoting the next instruction to be executed when the __next__ function |
255 | 245 | # is called, along with all the variables inside the function itself. |
256 | | - if builder.fn_info.contains_nested or builder.fn_info.is_generator: |
| 246 | + if contains_nested or is_generator: |
257 | 247 | setup_env_class(builder) |
258 | 248 |
|
259 | | - if builder.fn_info.is_nested or builder.fn_info.in_non_ext: |
| 249 | + if is_nested or in_non_ext: |
260 | 250 | setup_callable_class(builder) |
261 | 251 |
|
262 | | - if builder.fn_info.is_generator: |
263 | | - # Do a first-pass and generate a function that just returns a generator object. |
264 | | - gen_generator_func(builder) |
265 | | - args, _, blocks, ret_type, fn_info = builder.leave() |
266 | | - func_ir, func_reg = gen_func_ir( |
267 | | - builder, args, blocks, sig, fn_info, cdef, is_singledispatch |
| 252 | + if is_generator: |
| 253 | + # First generate a function that just constructs and returns a generator object. |
| 254 | + func_ir, func_reg = gen_generator_func( |
| 255 | + builder, |
| 256 | + lambda args, blocks, fn_info: gen_func_ir( |
| 257 | + builder, args, blocks, sig, fn_info, cdef, is_singledispatch |
| 258 | + ), |
268 | 259 | ) |
269 | 260 |
|
270 | 261 | # Re-enter the FuncItem and visit the body of the function this time. |
271 | | - builder.enter(fn_info) |
272 | | - setup_env_for_generator_class(builder) |
273 | | - |
274 | | - load_outer_envs(builder, builder.fn_info.generator_class) |
275 | | - top_level = builder.top_level_fn_info() |
276 | | - if ( |
277 | | - builder.fn_info.is_nested |
278 | | - and isinstance(fitem, FuncDef) |
279 | | - and top_level |
280 | | - and top_level.add_nested_funcs_to_env |
281 | | - ): |
282 | | - setup_func_for_recursive_call(builder, fitem, builder.fn_info.generator_class) |
283 | | - create_switch_for_generator_class(builder) |
284 | | - add_raise_exception_blocks_to_generator_class(builder, fitem.line) |
| 262 | + gen_generator_func_body(builder, fn_info, sig, func_reg) |
285 | 263 | else: |
286 | | - load_env_registers(builder) |
287 | | - gen_arg_defaults(builder) |
| 264 | + func_ir, func_reg = gen_func_body(builder, sig, cdef, is_singledispatch) |
288 | 265 |
|
289 | | - if builder.fn_info.contains_nested and not builder.fn_info.is_generator: |
290 | | - finalize_env_class(builder) |
| 266 | + if is_singledispatch: |
| 267 | + # add the generated main singledispatch function |
| 268 | + builder.functions.append(func_ir) |
| 269 | + # create the dispatch function |
| 270 | + assert isinstance(fitem, FuncDef) |
| 271 | + return gen_dispatch_func_ir(builder, fitem, fn_info.name, name, sig) |
291 | 272 |
|
292 | | - builder.ret_types[-1] = sig.ret_type |
| 273 | + return func_ir, func_reg |
293 | 274 |
|
294 | | - # Add all variables and functions that are declared/defined within this |
295 | | - # function and are referenced in functions nested within this one to this |
296 | | - # function's environment class so the nested functions can reference |
297 | | - # them even if they are declared after the nested function's definition. |
298 | | - # Note that this is done before visiting the body of this function. |
299 | | - |
300 | | - env_for_func: FuncInfo | ImplicitClass = builder.fn_info |
301 | | - if builder.fn_info.is_generator: |
302 | | - env_for_func = builder.fn_info.generator_class |
303 | | - elif builder.fn_info.is_nested or builder.fn_info.in_non_ext: |
304 | | - env_for_func = builder.fn_info.callable_class |
305 | | - |
306 | | - if builder.fn_info.fitem in builder.free_variables: |
307 | | - # Sort the variables to keep things deterministic |
308 | | - for var in sorted(builder.free_variables[builder.fn_info.fitem], key=lambda x: x.name): |
309 | | - if isinstance(var, Var): |
310 | | - rtype = builder.type_to_rtype(var.type) |
311 | | - builder.add_var_to_env_class(var, rtype, env_for_func, reassign=False) |
312 | | - |
313 | | - if builder.fn_info.fitem in builder.encapsulating_funcs: |
314 | | - for nested_fn in builder.encapsulating_funcs[builder.fn_info.fitem]: |
315 | | - if isinstance(nested_fn, FuncDef): |
316 | | - # The return type is 'object' instead of an RInstance of the |
317 | | - # callable class because differently defined functions with |
318 | | - # the same name and signature across conditional blocks |
319 | | - # will generate different callable classes, so the callable |
320 | | - # class that gets instantiated must be generic. |
321 | | - builder.add_var_to_env_class( |
322 | | - nested_fn, object_rprimitive, env_for_func, reassign=False |
323 | | - ) |
324 | 275 |
|
325 | | - builder.accept(fitem.body) |
| 276 | +def gen_func_body( |
| 277 | + builder: IRBuilder, sig: FuncSignature, cdef: ClassDef | None, is_singledispatch: bool |
| 278 | +) -> tuple[FuncIR, Value | None]: |
| 279 | + load_env_registers(builder) |
| 280 | + gen_arg_defaults(builder) |
| 281 | + if builder.fn_info.contains_nested: |
| 282 | + finalize_env_class(builder) |
| 283 | + add_vars_to_env(builder) |
| 284 | + builder.accept(builder.fn_info.fitem.body) |
326 | 285 | builder.maybe_add_implicit_return() |
327 | 286 |
|
328 | | - if builder.fn_info.is_generator: |
329 | | - populate_switch_for_generator_class(builder) |
330 | | - |
331 | 287 | # Hang on to the local symbol table for a while, since we use it |
332 | 288 | # to calculate argument defaults below. |
333 | 289 | symtable = builder.symtables[-1] |
334 | 290 |
|
335 | 291 | args, _, blocks, ret_type, fn_info = builder.leave() |
336 | 292 |
|
337 | | - if fn_info.is_generator: |
338 | | - add_methods_to_generator_class(builder, fn_info, sig, args, blocks, fitem.is_coroutine) |
339 | | - else: |
340 | | - func_ir, func_reg = gen_func_ir( |
341 | | - builder, args, blocks, sig, fn_info, cdef, is_singledispatch |
342 | | - ) |
| 293 | + func_ir, func_reg = gen_func_ir(builder, args, blocks, sig, fn_info, cdef, is_singledispatch) |
343 | 294 |
|
344 | 295 | # Evaluate argument defaults in the surrounding scope, since we |
345 | 296 | # calculate them *once* when the function definition is evaluated. |
346 | 297 | calculate_arg_defaults(builder, fn_info, func_reg, symtable) |
347 | | - |
348 | | - if is_singledispatch: |
349 | | - # add the generated main singledispatch function |
350 | | - builder.functions.append(func_ir) |
351 | | - # create the dispatch function |
352 | | - assert isinstance(fitem, FuncDef) |
353 | | - return gen_dispatch_func_ir(builder, fitem, fn_info.name, name, sig) |
354 | | - |
355 | 298 | return func_ir, func_reg |
356 | 299 |
|
357 | 300 |
|
@@ -512,33 +455,6 @@ def handle_non_ext_method( |
512 | 455 | builder.add_to_non_ext_dict(non_ext, name, func_reg, fdef.line) |
513 | 456 |
|
514 | 457 |
|
515 | | -def calculate_arg_defaults( |
516 | | - builder: IRBuilder, |
517 | | - fn_info: FuncInfo, |
518 | | - func_reg: Value | None, |
519 | | - symtable: dict[SymbolNode, SymbolTarget], |
520 | | -) -> None: |
521 | | - """Calculate default argument values and store them. |
522 | | -
|
523 | | - They are stored in statics for top level functions and in |
524 | | - the function objects for nested functions (while constants are |
525 | | - still stored computed on demand). |
526 | | - """ |
527 | | - fitem = fn_info.fitem |
528 | | - for arg in fitem.arguments: |
529 | | - # Constant values don't get stored but just recomputed |
530 | | - if arg.initializer and not is_constant(arg.initializer): |
531 | | - value = builder.coerce( |
532 | | - builder.accept(arg.initializer), symtable[arg.variable].type, arg.line |
533 | | - ) |
534 | | - if not fn_info.is_nested: |
535 | | - name = fitem.fullname + "." + arg.variable.name |
536 | | - builder.add(InitStatic(value, name, builder.module_name)) |
537 | | - else: |
538 | | - assert func_reg is not None |
539 | | - builder.add(SetAttr(func_reg, arg.variable.name, value, arg.line)) |
540 | | - |
541 | | - |
542 | 458 | def gen_func_ns(builder: IRBuilder) -> str: |
543 | 459 | """Generate a namespace for a nested function using its outer function names.""" |
544 | 460 | return "_".join( |
|
0 commit comments