def prepare_func_def(module_name: str, class_name: Optional[str], fdef: FuncDef, mapper: Mapper) -> FuncDecl: kind = FUNC_STATICMETHOD if fdef.is_static else ( FUNC_CLASSMETHOD if fdef.is_class else FUNC_NORMAL) decl = FuncDecl(fdef.name, class_name, module_name, mapper.fdef_to_sig(fdef), kind) mapper.func_to_decl[fdef] = decl return decl
def compile_modules_to_c( result: BuildResult, compiler_options: CompilerOptions, errors: Errors, groups: Groups, ) -> Tuple[ModuleIRs, List[FileContents]]: """Compile Python module(s) to the source of Python C extension modules. This generates the source code for the "shared library" module for each group. The shim modules are generated in mypyc.build. Each shared library module provides, for each module in its group, a PyCapsule containing an initialization function. Additionally, it provides a capsule containing an export table of pointers to all of the group's functions and static variables. Arguments: result: The BuildResult from the mypy front-end compiler_options: The compilation options errors: Where to report any errors encountered groups: The groups that we are compiling. See documentation of Groups type above. ops: Optionally, where to dump stringified ops for debugging. Returns the IR of the modules and a list containing the generated files for each group. """ # Construct a map from modules to what group they belong to group_map = {source.module: lib_name for group, lib_name in groups for source in group} mapper = Mapper(group_map) modules = compile_modules_to_ir(result, mapper, compiler_options, errors) ctext = compile_ir_to_c(groups, modules, result, mapper, compiler_options) if errors.num_errors == 0: write_cache(modules, result, group_map, ctext) return modules, [ctext[name] for _, name in groups]
def build_ir_for_single_file(input_lines: List[str], compiler_options: Optional[CompilerOptions] = None) -> List[FuncIR]: program_text = '\n'.join(input_lines) compiler_options = compiler_options or CompilerOptions() options = Options() options.show_traceback = True options.use_builtins_fixtures = True options.strict_optional = True options.python_version = (3, 6) options.export_types = True options.preserve_asts = True options.per_module_options['__main__'] = {'mypyc': True} source = build.BuildSource('main', '__main__', program_text) # Construct input as a single single. # Parse and type check the input program. result = build.build(sources=[source], options=options, alt_lib_path=test_temp_dir) if result.errors: raise CompileError(result.errors) errors = Errors() modules = build_ir( [result.files['__main__']], result.graph, result.types, Mapper({'__main__': None}), compiler_options, errors) if errors.num_errors: errors.flush_errors() pytest.fail('Errors while building IR') module = list(modules.values())[0] return module.functions
def build_ir_for_single_file( input_lines: List[str], compiler_options: Optional[CompilerOptions] = None) -> List[FuncIR]: program_text = '\n'.join(input_lines) # By default generate IR compatible with the earliest supported Python C API. # If a test needs more recent API features, this should be overridden. compiler_options = compiler_options or CompilerOptions(capi_version=(3, 5)) options = Options() options.show_traceback = True options.use_builtins_fixtures = True options.strict_optional = True options.python_version = (3, 6) options.export_types = True options.preserve_asts = True options.per_module_options['__main__'] = {'mypyc': True} source = build.BuildSource('main', '__main__', program_text) # Construct input as a single single. # Parse and type check the input program. result = build.build(sources=[source], options=options, alt_lib_path=test_temp_dir) if result.errors: raise CompileError(result.errors) errors = Errors() modules = build_ir([result.files['__main__']], result.graph, result.types, Mapper({'__main__': None}), compiler_options, errors) if errors.num_errors: raise CompileError(errors.new_messages()) module = list(modules.values())[0] return module.functions
def prepare_class_def(path: str, module_name: str, cdef: ClassDef, errors: Errors, mapper: Mapper) -> None: ir = mapper.type_to_ir[cdef.info] info = cdef.info attrs = get_mypyc_attrs(cdef) if attrs.get("allow_interpreted_subclasses") is True: ir.allow_interpreted_subclasses = True if attrs.get("serializable") is True: # Supports copy.copy and pickle (including subclasses) ir._serializable = True # We sort the table for determinism here on Python 3.5 for name, node in sorted(info.names.items()): # Currently all plugin generated methods are dummies and not included. if node.plugin_generated: continue if isinstance(node.node, Var): assert node.node.type, "Class member %s missing type" % name if not node.node.is_classvar and name not in ('__slots__', '__deletable__'): ir.attributes[name] = mapper.type_to_rtype(node.node.type) elif isinstance(node.node, (FuncDef, Decorator)): prepare_method_def(ir, module_name, cdef, mapper, node.node) elif isinstance(node.node, OverloadedFuncDef): # Handle case for property with both a getter and a setter if node.node.is_property: if is_valid_multipart_property_def(node.node): for item in node.node.items: prepare_method_def(ir, module_name, cdef, mapper, item) else: errors.error("Unsupported property decorator semantics", path, cdef.line) # Handle case for regular function overload else: assert node.node.impl prepare_method_def(ir, module_name, cdef, mapper, node.node.impl) # Check for subclassing from builtin types for cls in info.mro: # Special case exceptions and dicts # XXX: How do we handle *other* things?? if cls.fullname == 'builtins.BaseException': ir.builtin_base = 'PyBaseExceptionObject' elif cls.fullname == 'builtins.dict': ir.builtin_base = 'PyDictObject' elif cls.fullname.startswith('builtins.'): if not can_subclass_builtin(cls.fullname): # Note that if we try to subclass a C extension class that # isn't in builtins, bad things will happen and we won't # catch it here! But this should catch a lot of the most # common pitfalls. errors.error("Inheriting from most builtin types is unimplemented", path, cdef.line) if ir.builtin_base: ir.attributes.clear() # Set up a constructor decl init_node = cdef.info['__init__'].node if not ir.is_trait and not ir.builtin_base and isinstance(init_node, FuncDef): init_sig = mapper.fdef_to_sig(init_node) defining_ir = mapper.type_to_ir.get(init_node.info) # If there is a nontrivial __init__ that wasn't defined in an # extension class, we need to make the constructor take *args, # **kwargs so it can call tp_init. if ((defining_ir is None or not defining_ir.is_ext_class or cdef.info['__init__'].plugin_generated) and init_node.info.fullname != 'builtins.object'): init_sig = FuncSignature( [init_sig.args[0], RuntimeArg("args", tuple_rprimitive, ARG_STAR), RuntimeArg("kwargs", dict_rprimitive, ARG_STAR2)], init_sig.ret_type) ctor_sig = FuncSignature(init_sig.args[1:], RInstance(ir)) ir.ctor = FuncDecl(cdef.name, None, module_name, ctor_sig) mapper.func_to_decl[cdef.info] = ir.ctor # Set up the parent class bases = [mapper.type_to_ir[base.type] for base in info.bases if base.type in mapper.type_to_ir] if not all(c.is_trait for c in bases[1:]): errors.error("Non-trait bases must appear first in parent list", path, cdef.line) ir.traits = [c for c in bases if c.is_trait] mro = [] base_mro = [] for cls in info.mro: if cls not in mapper.type_to_ir: if cls.fullname != 'builtins.object': ir.inherits_python = True continue base_ir = mapper.type_to_ir[cls] if not base_ir.is_trait: base_mro.append(base_ir) mro.append(base_ir) if cls.defn.removed_base_type_exprs or not base_ir.is_ext_class: ir.inherits_python = True base_idx = 1 if not ir.is_trait else 0 if len(base_mro) > base_idx: ir.base = base_mro[base_idx] ir.mro = mro ir.base_mro = base_mro for base in bases: if base.children is not None: base.children.append(ir) if is_dataclass(cdef): ir.is_augmented = True