|
7 | 7 | from typing import Callable, Final |
8 | 8 |
|
9 | 9 | from mypy.nodes import ( |
| 10 | + PARAM_SPEC_KIND, |
| 11 | + TYPE_VAR_KIND, |
| 12 | + TYPE_VAR_TUPLE_KIND, |
10 | 13 | AssignmentStmt, |
11 | 14 | CallExpr, |
12 | 15 | ClassDef, |
|
22 | 25 | StrExpr, |
23 | 26 | TempNode, |
24 | 27 | TypeInfo, |
| 28 | + TypeParam, |
25 | 29 | is_class_var, |
26 | 30 | ) |
27 | 31 | from mypy.types import ENUM_REMOVED_PROPS, Instance, RawExpressionType, get_proper_type |
|
63 | 67 | ) |
64 | 68 | from mypyc.irbuild.util import dataclass_type, get_func_def, is_constant, is_dataclass_decorator |
65 | 69 | from mypyc.primitives.dict_ops import dict_new_op, dict_set_item_op |
66 | | -from mypyc.primitives.generic_ops import py_hasattr_op, py_setattr_op |
| 70 | +from mypyc.primitives.generic_ops import ( |
| 71 | + iter_op, |
| 72 | + next_op, |
| 73 | + py_get_item_op, |
| 74 | + py_hasattr_op, |
| 75 | + py_setattr_op, |
| 76 | +) |
67 | 77 | from mypyc.primitives.misc_ops import ( |
68 | 78 | dataclass_sleight_of_hand, |
| 79 | + import_op, |
69 | 80 | not_implemented_op, |
70 | 81 | py_calc_meta_op, |
71 | 82 | pytype_from_template_op, |
@@ -405,8 +416,14 @@ def get_type_annotation(self, stmt: AssignmentStmt) -> TypeInfo | None: |
405 | 416 | def allocate_class(builder: IRBuilder, cdef: ClassDef) -> Value: |
406 | 417 | # OK AND NOW THE FUN PART |
407 | 418 | base_exprs = cdef.base_type_exprs + cdef.removed_base_type_exprs |
408 | | - if base_exprs: |
409 | | - bases = [builder.accept(x) for x in base_exprs] |
| 419 | + new_style_type_args = cdef.type_args |
| 420 | + if new_style_type_args: |
| 421 | + bases = [make_generic_base_class(builder, cdef.fullname, new_style_type_args, cdef.line)] |
| 422 | + else: |
| 423 | + bases = [] |
| 424 | + |
| 425 | + if base_exprs or new_style_type_args: |
| 426 | + bases.extend([builder.accept(x) for x in base_exprs]) |
410 | 427 | tp_bases = builder.new_tuple(bases, cdef.line) |
411 | 428 | else: |
412 | 429 | tp_bases = builder.add(LoadErrorValue(object_rprimitive, is_borrowed=True)) |
@@ -453,6 +470,45 @@ def allocate_class(builder: IRBuilder, cdef: ClassDef) -> Value: |
453 | 470 | return tp |
454 | 471 |
|
455 | 472 |
|
| 473 | +def make_generic_base_class( |
| 474 | + builder: IRBuilder, fullname: str, type_args: list[TypeParam], line: int |
| 475 | +) -> Value: |
| 476 | + """Construct Generic[...] base class object for a new-style generic class (Python 3.12).""" |
| 477 | + mod = builder.call_c(import_op, [builder.load_str("_typing")], line) |
| 478 | + tvs = [] |
| 479 | + type_var_imported: Value | None = None |
| 480 | + for type_param in type_args: |
| 481 | + unpack = False |
| 482 | + if type_param.kind == TYPE_VAR_KIND: |
| 483 | + if type_var_imported: |
| 484 | + # Reuse previously imported value as a minor optimization |
| 485 | + tvt = type_var_imported |
| 486 | + else: |
| 487 | + tvt = builder.py_get_attr(mod, "TypeVar", line) |
| 488 | + type_var_imported = tvt |
| 489 | + elif type_param.kind == TYPE_VAR_TUPLE_KIND: |
| 490 | + tvt = builder.py_get_attr(mod, "TypeVarTuple", line) |
| 491 | + unpack = True |
| 492 | + else: |
| 493 | + assert type_param.kind == PARAM_SPEC_KIND |
| 494 | + tvt = builder.py_get_attr(mod, "ParamSpec", line) |
| 495 | + tv = builder.py_call(tvt, [builder.load_str(type_param.name)], line) |
| 496 | + builder.init_type_var(tv, type_param.name, line) |
| 497 | + if unpack: |
| 498 | + # Evaluate *Ts for a TypeVarTuple |
| 499 | + it = builder.call_c(iter_op, [tv], line) |
| 500 | + tv = builder.call_c(next_op, [it], line) |
| 501 | + tvs.append(tv) |
| 502 | + gent = builder.py_get_attr(mod, "Generic", line) |
| 503 | + if len(tvs) == 1: |
| 504 | + arg = tvs[0] |
| 505 | + else: |
| 506 | + arg = builder.new_tuple(tvs, line) |
| 507 | + |
| 508 | + base = builder.call_c(py_get_item_op, [gent, arg], line) |
| 509 | + return base |
| 510 | + |
| 511 | + |
456 | 512 | # Mypy uses these internally as base classes of TypedDict classes. These are |
457 | 513 | # lies and don't have any runtime equivalent. |
458 | 514 | MAGIC_TYPED_DICT_CLASSES: Final[tuple[str, ...]] = ( |
|
0 commit comments