diff --git a/mypyc/irbuild/builder.py b/mypyc/irbuild/builder.py index a9e1ce471953..823f1581ba2e 100644 --- a/mypyc/irbuild/builder.py +++ b/mypyc/irbuild/builder.py @@ -979,17 +979,13 @@ def _analyze_iterable_item_type(self, expr: Expression) -> Type: def is_native_module(self, module: str) -> bool: """Is the given module one compiled by mypyc?""" - return module in self.mapper.group_map + return self.mapper.is_native_module(module) def is_native_ref_expr(self, expr: RefExpr) -> bool: - if expr.node is None: - return False - if "." in expr.node.fullname: - return self.is_native_module(expr.node.fullname.rpartition(".")[0]) - return True + return self.mapper.is_native_ref_expr(expr) def is_native_module_ref_expr(self, expr: RefExpr) -> bool: - return self.is_native_ref_expr(expr) and expr.kind == GDEF + return self.mapper.is_native_module_ref_expr(expr) def is_synthetic_type(self, typ: TypeInfo) -> bool: """Is a type something other than just a class we've created?""" diff --git a/mypyc/irbuild/mapper.py b/mypyc/irbuild/mapper.py index 78e54aceed3d..9cd263c40ae4 100644 --- a/mypyc/irbuild/mapper.py +++ b/mypyc/irbuild/mapper.py @@ -62,6 +62,7 @@ def __init__(self, group_map: dict[str, str | None]) -> None: self.group_map = group_map self.type_to_ir: dict[TypeInfo, ClassIR] = {} self.func_to_decl: dict[SymbolNode, FuncDecl] = {} + self.symbol_fullnames: set[str] = set() def type_to_rtype(self, typ: Type | None) -> RType: if typ is None: @@ -217,7 +218,8 @@ def is_native_ref_expr(self, expr: RefExpr) -> bool: if expr.node is None: return False if "." in expr.node.fullname: - return self.is_native_module(expr.node.fullname.rpartition(".")[0]) + name = expr.node.fullname.rpartition(".")[0] + return self.is_native_module(name) or name in self.symbol_fullnames return True def is_native_module_ref_expr(self, expr: RefExpr) -> bool: diff --git a/mypyc/irbuild/prepare.py b/mypyc/irbuild/prepare.py index bed9a1684326..4b132bb83722 100644 --- a/mypyc/irbuild/prepare.py +++ b/mypyc/irbuild/prepare.py @@ -94,6 +94,7 @@ def build_type_map( if not options.global_opts: class_ir.children = None mapper.type_to_ir[cdef.info] = class_ir + mapper.symbol_fullnames.add(class_ir.fullname) # Populate structural information in class IR for extension classes. for module, cdef in classes: @@ -149,6 +150,7 @@ def load_type_map(mapper: Mapper, modules: list[MypyFile], deser_ctx: DeserMaps) if isinstance(node.node, TypeInfo) and is_from_module(node.node, module): ir = deser_ctx.classes[node.node.fullname] mapper.type_to_ir[node.node] = ir + mapper.symbol_fullnames.add(node.node.fullname) mapper.func_to_decl[node.node] = ir.ctor for module in modules: diff --git a/mypyc/test-data/run-classes.test b/mypyc/test-data/run-classes.test index 49eb3028c9ee..40287ab963aa 100644 --- a/mypyc/test-data/run-classes.test +++ b/mypyc/test-data/run-classes.test @@ -2594,3 +2594,15 @@ def test_class_final_attribute_inherited() -> None: assert C().b == 2 assert B().c == 3 assert C().c == 3 + +[case testClassWithFinalAttributeAccess] +from typing import Final + +class C: + a: Final = {'x': 'y'} + b: Final = C.a + +def test_final_attribute() -> None: + assert C.a['x'] == 'y' + assert C.b['x'] == 'y' + assert C.a is C.b