|
29 | 29 | TypeInfo,
|
30 | 30 | Var,
|
31 | 31 | )
|
32 |
| -from mypy.types import CallableType, get_proper_type |
| 32 | +from mypy.types import CallableType, Type, UnboundType, get_proper_type |
33 | 33 | from mypyc.common import LAMBDA_NAME, PROPSET_PREFIX, SELF_NAME
|
34 | 34 | from mypyc.ir.class_ir import ClassIR, NonExtClassInfo
|
35 | 35 | from mypyc.ir.func_ir import (
|
@@ -802,15 +802,49 @@ def get_func_target(builder: IRBuilder, fdef: FuncDef) -> AssignmentTarget:
|
802 | 802 | return builder.add_local_reg(fdef, object_rprimitive)
|
803 | 803 |
|
804 | 804 |
|
805 |
| -def load_type(builder: IRBuilder, typ: TypeInfo, line: int) -> Value: |
| 805 | +# This function still does not support the following imports. |
| 806 | +# import json as _json |
| 807 | +# from json import decoder |
| 808 | +# Using either _json.JSONDecoder or decoder.JSONDecoder as a type hint for a dataclass field will fail. |
| 809 | +# See issue mypyc/mypyc#1099. |
| 810 | +def load_type(builder: IRBuilder, typ: TypeInfo, unbounded_type: Type | None, line: int) -> Value: |
| 811 | + # typ.fullname contains the module where the class object was defined. However, it is possible |
| 812 | + # that the class object's module was not imported in the file currently being compiled. So, we |
| 813 | + # use unbounded_type.name (if provided by caller) to load the class object through one of the |
| 814 | + # imported modules. |
| 815 | + # Example: for `json.JSONDecoder`, typ.fullname is `json.decoder.JSONDecoder` but the Python |
| 816 | + # file may import `json` not `json.decoder`. |
| 817 | + # Another corner case: The Python file being compiled imports mod1 and has a type hint |
| 818 | + # `mod1.OuterClass.InnerClass`. But, mod1/__init__.py might import OuterClass like this: |
| 819 | + # `from mod2.mod3 import OuterClass`. In this case, typ.fullname is |
| 820 | + # `mod2.mod3.OuterClass.InnerClass` and `unbounded_type.name` is `mod1.OuterClass.InnerClass`. |
| 821 | + # So, we must use unbounded_type.name to load the class object. |
| 822 | + # See issue mypyc/mypyc#1087. |
| 823 | + load_attr_path = ( |
| 824 | + unbounded_type.name if isinstance(unbounded_type, UnboundType) else typ.fullname |
| 825 | + ).removesuffix(f".{typ.name}") |
806 | 826 | if typ in builder.mapper.type_to_ir:
|
807 | 827 | class_ir = builder.mapper.type_to_ir[typ]
|
808 | 828 | class_obj = builder.builder.get_native_type(class_ir)
|
809 | 829 | elif typ.fullname in builtin_names:
|
810 | 830 | builtin_addr_type, src = builtin_names[typ.fullname]
|
811 | 831 | class_obj = builder.add(LoadAddress(builtin_addr_type, src, line))
|
812 |
| - elif typ.module_name in builder.imports: |
813 |
| - loaded_module = builder.load_module(typ.module_name) |
| 832 | + # This elif-condition finds the longest import that matches the load_attr_path. |
| 833 | + elif module_name := max( |
| 834 | + (i for i in builder.imports if load_attr_path == i or load_attr_path.startswith(f"{i}.")), |
| 835 | + default="", |
| 836 | + key=len, |
| 837 | + ): |
| 838 | + # Load the imported module. |
| 839 | + loaded_module = builder.load_module(module_name) |
| 840 | + # Recursively load attributes of the imported module. These may be submodules, classes or |
| 841 | + # any other object. |
| 842 | + for attr in ( |
| 843 | + load_attr_path.removeprefix(f"{module_name}.").split(".") |
| 844 | + if load_attr_path != module_name |
| 845 | + else [] |
| 846 | + ): |
| 847 | + loaded_module = builder.py_get_attr(loaded_module, attr, line) |
814 | 848 | class_obj = builder.builder.get_attr(
|
815 | 849 | loaded_module, typ.name, object_rprimitive, line, borrow=False
|
816 | 850 | )
|
@@ -1039,7 +1073,7 @@ def maybe_insert_into_registry_dict(builder: IRBuilder, fitem: FuncDef) -> None:
|
1039 | 1073 | )
|
1040 | 1074 | registry = load_singledispatch_registry(builder, dispatch_func_obj, line)
|
1041 | 1075 | for typ in types:
|
1042 |
| - loaded_type = load_type(builder, typ, line) |
| 1076 | + loaded_type = load_type(builder, typ, None, line) |
1043 | 1077 | builder.primitive_op(dict_set_item_op, [registry, loaded_type, to_insert], line)
|
1044 | 1078 | dispatch_cache = builder.builder.get_attr(
|
1045 | 1079 | dispatch_func_obj, "dispatch_cache", dict_rprimitive, line
|
|
0 commit comments