From 4eb6535edba2683dc4ed25e38f340940ca713d7d Mon Sep 17 00:00:00 2001 From: Piotr Sawicki Date: Tue, 8 Jul 2025 21:25:56 +0200 Subject: [PATCH] Report error on reserved method name --- mypyc/irbuild/classdef.py | 9 +++++++++ mypyc/irbuild/generator.py | 5 +++-- mypyc/irbuild/prepare.py | 4 +++- mypyc/irbuild/statement.py | 3 ++- mypyc/test-data/irbuild-classes.test | 25 +++++++++++++++++++++++++ 5 files changed, 42 insertions(+), 4 deletions(-) diff --git a/mypyc/irbuild/classdef.py b/mypyc/irbuild/classdef.py index 13121707773a..30020aabb310 100644 --- a/mypyc/irbuild/classdef.py +++ b/mypyc/irbuild/classdef.py @@ -64,6 +64,7 @@ handle_non_ext_method, load_type, ) +from mypyc.irbuild.prepare import GENERATOR_HELPER_NAME from mypyc.irbuild.util import dataclass_type, get_func_def, is_constant, is_dataclass_decorator from mypyc.primitives.dict_ops import dict_new_op, dict_set_item_op from mypyc.primitives.generic_ops import ( @@ -135,6 +136,14 @@ def transform_class_def(builder: IRBuilder, cdef: ClassDef) -> None: cls_builder = NonExtClassBuilder(builder, cdef) for stmt in cdef.defs.body: + if ( + isinstance(stmt, (FuncDef, Decorator, OverloadedFuncDef)) + and stmt.name == GENERATOR_HELPER_NAME + ): + builder.error( + f'Method name "{stmt.name}" is reserved for mypyc internal use', stmt.line + ) + if isinstance(stmt, OverloadedFuncDef) and stmt.is_property: if isinstance(cls_builder, NonExtClassBuilder): # properties with both getters and setters in non_extension diff --git a/mypyc/irbuild/generator.py b/mypyc/irbuild/generator.py index eec27e1cfb84..a8928cd314fc 100644 --- a/mypyc/irbuild/generator.py +++ b/mypyc/irbuild/generator.py @@ -45,6 +45,7 @@ setup_func_for_recursive_call, ) from mypyc.irbuild.nonlocalcontrol import ExceptNonlocalControl +from mypyc.irbuild.prepare import GENERATOR_HELPER_NAME from mypyc.primitives.exc_ops import ( error_catch_op, exc_matches_op, @@ -231,11 +232,11 @@ def add_helper_to_generator_class( builder: IRBuilder, arg_regs: list[Register], blocks: list[BasicBlock], fn_info: FuncInfo ) -> FuncDecl: """Generates a helper method for a generator class, called by '__next__' and 'throw'.""" - helper_fn_decl = fn_info.generator_class.ir.method_decls["__mypyc_generator_helper__"] + helper_fn_decl = fn_info.generator_class.ir.method_decls[GENERATOR_HELPER_NAME] helper_fn_ir = FuncIR( helper_fn_decl, arg_regs, blocks, fn_info.fitem.line, traceback_name=fn_info.fitem.name ) - fn_info.generator_class.ir.methods["__mypyc_generator_helper__"] = helper_fn_ir + fn_info.generator_class.ir.methods[GENERATOR_HELPER_NAME] = helper_fn_ir builder.functions.append(helper_fn_ir) fn_info.env_class.env_user_function = helper_fn_ir diff --git a/mypyc/irbuild/prepare.py b/mypyc/irbuild/prepare.py index 147392585b25..3da38567cab3 100644 --- a/mypyc/irbuild/prepare.py +++ b/mypyc/irbuild/prepare.py @@ -70,6 +70,8 @@ from mypyc.options import CompilerOptions from mypyc.sametype import is_same_type +GENERATOR_HELPER_NAME = "__mypyc_generator_helper__" + def build_type_map( mapper: Mapper, @@ -226,7 +228,7 @@ def create_generator_class_if_needed( # The implementation of most generator functionality is behind this magic method. helper_fn_decl = FuncDecl( - "__mypyc_generator_helper__", name, module_name, helper_sig, internal=True + GENERATOR_HELPER_NAME, name, module_name, helper_sig, internal=True ) cir.method_decls[helper_fn_decl.name] = helper_fn_decl diff --git a/mypyc/irbuild/statement.py b/mypyc/irbuild/statement.py index 9c7ffb6a3adf..cbece2414709 100644 --- a/mypyc/irbuild/statement.py +++ b/mypyc/irbuild/statement.py @@ -90,6 +90,7 @@ FinallyNonlocalControl, TryFinallyNonlocalControl, ) +from mypyc.irbuild.prepare import GENERATOR_HELPER_NAME from mypyc.irbuild.targets import ( AssignmentTarget, AssignmentTargetAttr, @@ -932,7 +933,7 @@ def emit_yield_from_or_await( to_yield_reg = Register(object_rprimitive) received_reg = Register(object_rprimitive) - helper_method = "__mypyc_generator_helper__" + helper_method = GENERATOR_HELPER_NAME if ( isinstance(val, (Call, MethodCall)) and isinstance(val.type, RInstance) diff --git a/mypyc/test-data/irbuild-classes.test b/mypyc/test-data/irbuild-classes.test index fa4708f02e0b..1543568fccad 100644 --- a/mypyc/test-data/irbuild-classes.test +++ b/mypyc/test-data/irbuild-classes.test @@ -1383,3 +1383,28 @@ class M(type): # E: Inheriting from most builtin types is unimplemented \ @mypyc_attr(native_class=True) class A(metaclass=M): # E: Class is marked as native_class=True but it can't be a native class. Classes with a metaclass other than ABCMeta, TypingMeta or GenericMeta can't be native classes. pass + +[case testReservedName] +from typing import Any, overload + +def decorator(cls): + return cls + +class TestMethod: + def __mypyc_generator_helper__(self) -> None: # E: Method name "__mypyc_generator_helper__" is reserved for mypyc internal use + pass + +class TestDecorator: + @decorator # E: Method name "__mypyc_generator_helper__" is reserved for mypyc internal use + def __mypyc_generator_helper__(self) -> None: + pass + +class TestOverload: + @overload # E: Method name "__mypyc_generator_helper__" is reserved for mypyc internal use + def __mypyc_generator_helper__(self, x: int) -> int: ... + + @overload + def __mypyc_generator_helper__(self, x: str) -> str: ... + + def __mypyc_generator_helper__(self, x: Any) -> Any: + return x