|
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