From 46ca92ec241738ea3279191b67c98dc8fcc7825e Mon Sep 17 00:00:00 2001 From: Piotr Sawicki Date: Tue, 15 Sep 2026 21:09:26 +0200 Subject: [PATCH 1/2] [mypyc] Fix name conflict when creating CPyFunction variable --- mypyc/codegen/emit.py | 2 +- mypyc/test-data/run-async.test | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/mypyc/codegen/emit.py b/mypyc/codegen/emit.py index a882dc3800049..b20fde7faefa4 100644 --- a/mypyc/codegen/emit.py +++ b/mypyc/codegen/emit.py @@ -1442,7 +1442,7 @@ def emit_cpyfunction_instance( ) -> str: module = self.static_name(fn.decl.module_name, None, prefix=MODULE_PREFIX) cname = f"{PREFIX}{fn.cname(self.names)}" - wrapper_name = f"{cname}_wrapper" + wrapper_name = f"wrapper_{cname}" cfunc = f"(PyCFunction){cname}" func_flags = ["METH_FASTCALL", "METH_KEYWORDS"] if fn.class_name and fn.decl.kind == FUNC_STATICMETHOD: diff --git a/mypyc/test-data/run-async.test b/mypyc/test-data/run-async.test index 5eebb7348cf35..b63a12abefbdd 100644 --- a/mypyc/test-data/run-async.test +++ b/mypyc/test-data/run-async.test @@ -2135,6 +2135,37 @@ from typing import Any, Generator def run(x: object) -> object: ... +[case testCPyFunctionVariableNameConflict] +class C: + async def operation(self) -> int: + return 42 + + async def operation_wrapper(self) -> int: + return await self.operation() + + async def wrapper_operation(self) -> int: + return await self.operation() + +async def test_variable_name_conflict() -> None: + c = C() + assert await c.operation() == 42 + assert await c.operation_wrapper() == 42 + assert await c.wrapper_operation() == 42 + +[file driver.py] +import asyncio + +from native import C, test_variable_name_conflict + +async def test_variable_name_conflict_interpreted() -> None: + c = C() + assert await c.operation() == 42 + assert await c.operation_wrapper() == 42 + assert await c.wrapper_operation() == 42 + +asyncio.run(test_variable_name_conflict()) +asyncio.run(test_variable_name_conflict_interpreted()) + [case testNestedCoroutineCallsAnotherNestedFunction] import asyncio import functools From c350381f130d151f18d503854eb3f8321267645a Mon Sep 17 00:00:00 2001 From: Piotr Sawicki Date: Tue, 15 Sep 2026 21:29:37 +0200 Subject: [PATCH 2/2] Avoid conflicts with name objects --- mypyc/codegen/emitclass.py | 2 +- mypyc/codegen/emitmodule.py | 2 +- mypyc/test-data/run-async.test | 10 ++++++++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/mypyc/codegen/emitclass.py b/mypyc/codegen/emitclass.py index 1a73d5426b851..2d8a0f30b064e 100644 --- a/mypyc/codegen/emitclass.py +++ b/mypyc/codegen/emitclass.py @@ -1506,7 +1506,7 @@ def success() -> None: name = short_id_from_name(fn.name, fn.decl.shortname, fn.line) wrapper_name = emit_instance(fn, name) - name_obj = f"{wrapper_name}_name" + name_obj = f"name_{wrapper_name}" emitter.emit_line(f'PyObject *{name_obj} = PyUnicode_FromString("{fn.name}");') emitter.emit_line(f"if (unlikely(!{name_obj}))") emitter.emit_line(error_stmt) diff --git a/mypyc/codegen/emitmodule.py b/mypyc/codegen/emitmodule.py index b8039dcca823c..34adecbe93e55 100644 --- a/mypyc/codegen/emitmodule.py +++ b/mypyc/codegen/emitmodule.py @@ -1249,7 +1249,7 @@ def emit_coroutine_wrappers(self, emitter: Emitter, module: ModuleIR, globals: s error_stmt = " goto fail;" name = short_id_from_name(fn.name, fn.decl.shortname, fn.line) wrapper_name = emitter.emit_cpyfunction_instance(fn, name, filepath, error_stmt) - name_obj = f"{wrapper_name}_name" + name_obj = f"name_{wrapper_name}" emitter.emit_line(f'PyObject *{name_obj} = PyUnicode_FromString("{fn.name}");') emitter.emit_line(f"if (unlikely(!{name_obj}))") emitter.emit_line(error_stmt) diff --git a/mypyc/test-data/run-async.test b/mypyc/test-data/run-async.test index b63a12abefbdd..fa38e923a8b16 100644 --- a/mypyc/test-data/run-async.test +++ b/mypyc/test-data/run-async.test @@ -2140,6 +2140,12 @@ class C: async def operation(self) -> int: return 42 + async def operation_name(self) -> str: + return "name" + + async def name_operation(self) -> str: + return await self.operation_name() + async def operation_wrapper(self) -> int: return await self.operation() @@ -2151,6 +2157,8 @@ async def test_variable_name_conflict() -> None: assert await c.operation() == 42 assert await c.operation_wrapper() == 42 assert await c.wrapper_operation() == 42 + assert await c.operation_name() == "name" + assert await c.name_operation() == "name" [file driver.py] import asyncio @@ -2162,6 +2170,8 @@ async def test_variable_name_conflict_interpreted() -> None: assert await c.operation() == 42 assert await c.operation_wrapper() == 42 assert await c.wrapper_operation() == 42 + assert await c.operation_name() == "name" + assert await c.name_operation() == "name" asyncio.run(test_variable_name_conflict()) asyncio.run(test_variable_name_conflict_interpreted())