|
38 | 38 | from mypy.semanal import refers_to_fullname |
39 | 39 | from mypy.traverser import TraverserVisitor |
40 | 40 | from mypy.types import Instance, Type, get_proper_type |
41 | | -from mypyc.common import PROPSET_PREFIX, SELF_NAME, get_id_from_name |
| 41 | +from mypyc.common import FAST_PREFIX, PROPSET_PREFIX, SELF_NAME, get_id_from_name |
42 | 42 | from mypyc.crash import catch_errors |
43 | 43 | from mypyc.errors import Errors |
44 | 44 | from mypyc.ir.class_ir import ClassIR |
@@ -106,6 +106,7 @@ def build_type_map( |
106 | 106 | class_ir.children = None |
107 | 107 | mapper.type_to_ir[cdef.info] = class_ir |
108 | 108 | mapper.symbol_fullnames.add(class_ir.fullname) |
| 109 | + class_ir.is_enum = cdef.info.is_enum and len(cdef.info.enum_members) > 0 |
109 | 110 |
|
110 | 111 | # Populate structural information in class IR for extension classes. |
111 | 112 | for module, cdef in classes: |
@@ -270,6 +271,36 @@ def prepare_method_def( |
270 | 271 | ir.property_types[node.name] = decl.sig.ret_type |
271 | 272 |
|
272 | 273 |
|
| 274 | +def prepare_fast_path( |
| 275 | + ir: ClassIR, |
| 276 | + module_name: str, |
| 277 | + cdef: ClassDef, |
| 278 | + mapper: Mapper, |
| 279 | + node: SymbolNode | None, |
| 280 | + options: CompilerOptions, |
| 281 | +) -> None: |
| 282 | + """Add fast (direct) variants of methods in non-extension classes.""" |
| 283 | + if ir.is_enum: |
| 284 | + # We check that non-empty enums are implicitly final in mypy, so we |
| 285 | + # can generate direct calls to enum methods. |
| 286 | + if isinstance(node, OverloadedFuncDef): |
| 287 | + if node.is_property: |
| 288 | + return |
| 289 | + node = node.impl |
| 290 | + if not isinstance(node, FuncDef): |
| 291 | + # TODO: support decorated methods (at least @classmethod and @staticmethod). |
| 292 | + return |
| 293 | + # The simplest case is a regular or overloaded method without decorators. In this |
| 294 | + # case we can generate practically identical IR method body, but with a signature |
| 295 | + # suitable for direct calls (usual non-extension class methods are converted to |
| 296 | + # callable classes, and thus have an extra __mypyc_self__ argument). |
| 297 | + name = FAST_PREFIX + node.name |
| 298 | + sig = mapper.fdef_to_sig(node, options.strict_dunders_typing) |
| 299 | + decl = FuncDecl(name, cdef.name, module_name, sig, FUNC_NORMAL) |
| 300 | + ir.method_decls[name] = decl |
| 301 | + return |
| 302 | + |
| 303 | + |
273 | 304 | def is_valid_multipart_property_def(prop: OverloadedFuncDef) -> bool: |
274 | 305 | # Checks to ensure supported property decorator semantics |
275 | 306 | if len(prop.items) != 2: |
@@ -579,6 +610,8 @@ def prepare_non_ext_class_def( |
579 | 610 | else: |
580 | 611 | prepare_method_def(ir, module_name, cdef, mapper, get_func_def(node.node), options) |
581 | 612 |
|
| 613 | + prepare_fast_path(ir, module_name, cdef, mapper, node.node, options) |
| 614 | + |
582 | 615 | if any(cls in mapper.type_to_ir and mapper.type_to_ir[cls].is_ext_class for cls in info.mro): |
583 | 616 | errors.error( |
584 | 617 | "Non-extension classes may not inherit from extension classes", path, cdef.line |
|
0 commit comments