Skip to content

Commit e01469d

Browse files
committed
Add prefix also to local vars in generator functions
1 parent b849bc4 commit e01469d

File tree

6 files changed

+41
-8
lines changed

6 files changed

+41
-8
lines changed

mypyc/codegen/emitfunc.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from mypyc.codegen.cstring import c_string_initializer
99
from mypyc.codegen.emit import DEBUG_ERRORS, Emitter, TracebackAndGotoHandler, c_array_initializer
1010
from mypyc.common import (
11+
GENERATOR_ATTRIBUTE_PREFIX,
1112
HAVE_IMMORTAL,
1213
MODULE_PREFIX,
1314
NATIVE_PREFIX,
@@ -436,7 +437,9 @@ def visit_get_attr(self, op: GetAttr) -> None:
436437
exc_class = "PyExc_AttributeError"
437438
self.emitter.emit_line(
438439
'PyErr_SetString({}, "attribute {} of {} undefined");'.format(
439-
exc_class, repr(op.attr), repr(cl.name)
440+
exc_class,
441+
repr(op.attr.removeprefix(GENERATOR_ATTRIBUTE_PREFIX)),
442+
repr(cl.name),
440443
)
441444
)
442445

@@ -938,7 +941,7 @@ def emit_attribute_error(self, op: Branch, class_name: str, attr: str) -> None:
938941
self.source_path.replace("\\", "\\\\"),
939942
op.traceback_entry[0],
940943
class_name,
941-
attr,
944+
attr.removeprefix(GENERATOR_ATTRIBUTE_PREFIX),
942945
op.traceback_entry[1],
943946
globals_static,
944947
)

mypyc/common.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
LAMBDA_NAME: Final = "__mypyc_lambda__"
2323
PROPSET_PREFIX: Final = "__mypyc_setter__"
2424
SELF_NAME: Final = "__mypyc_self__"
25+
GENERATOR_ATTRIBUTE_PREFIX: Final = "__mypyc_generator_attribute__"
2526

2627
# Max short int we accept as a literal is based on 32-bit platforms,
2728
# so that we can just always emit the same code.

mypyc/irbuild/builder.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
)
6060
from mypy.util import module_prefix, split_target
6161
from mypy.visitor import ExpressionVisitor, StatementVisitor
62-
from mypyc.common import BITMAP_BITS, SELF_NAME, TEMP_ATTR_NAME
62+
from mypyc.common import BITMAP_BITS, GENERATOR_ATTRIBUTE_PREFIX, SELF_NAME, TEMP_ATTR_NAME
6363
from mypyc.crash import catch_errors
6464
from mypyc.errors import Errors
6565
from mypyc.ir.class_ir import ClassIR, NonExtClassInfo
@@ -643,7 +643,11 @@ def get_assignment_target(
643643
# current environment.
644644
if self.fn_info.is_generator:
645645
return self.add_var_to_env_class(
646-
symbol, reg_type, self.fn_info.generator_class, reassign=False
646+
symbol,
647+
reg_type,
648+
self.fn_info.generator_class,
649+
reassign=False,
650+
prefix=GENERATOR_ATTRIBUTE_PREFIX,
647651
)
648652

649653
# Otherwise define a new local variable.

mypyc/irbuild/env_class.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ def add_vars_to_env(builder: IRBuilder, prefix: str = "") -> None:
235235
# will generate different callable classes, so the callable
236236
# class that gets instantiated must be generic.
237237
builder.add_var_to_env_class(
238-
nested_fn, object_rprimitive, env_for_func, reassign=False
238+
nested_fn, object_rprimitive, env_for_func, reassign=False, prefix=prefix
239239
)
240240

241241

mypyc/irbuild/generator.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from typing import Callable
1414

1515
from mypy.nodes import ARG_OPT, FuncDef, Var
16-
from mypyc.common import ENV_ATTR_NAME, NEXT_LABEL_ATTR_NAME
16+
from mypyc.common import ENV_ATTR_NAME, GENERATOR_ATTRIBUTE_PREFIX, NEXT_LABEL_ATTR_NAME
1717
from mypyc.ir.class_ir import ClassIR
1818
from mypyc.ir.func_ir import FuncDecl, FuncIR
1919
from mypyc.ir.ops import (
@@ -59,8 +59,6 @@
5959
restore_exc_info_op,
6060
)
6161

62-
GENERATOR_ATTRIBUTE_PREFIX = "__mypyc_generator_attribute__"
63-
6462

6563
def gen_generator_func(
6664
builder: IRBuilder,

mypyc/test-data/run-generators.test

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -871,3 +871,30 @@ def test_undefined_int_in_environment() -> None:
871871

872872
with assertRaises(AttributeError): # TODO: Should be UnboundLocalError
873873
list(gen2(False))
874+
875+
[case testVariableWithSameNameAsHelperMethod]
876+
from testutil import assertRaises
877+
from typing import Iterator
878+
879+
def gen_send() -> Iterator[int]:
880+
send = 1
881+
yield send + 1
882+
883+
def gen_throw() -> Iterator[int]:
884+
throw = 42
885+
yield throw * 2
886+
887+
def undefined() -> Iterator[int]:
888+
if int():
889+
send = 1
890+
yield send + 1
891+
892+
def test_same_names() -> None:
893+
assert list(gen_send()) == [2]
894+
assert list(gen_throw()) == [84]
895+
896+
with assertRaises(AttributeError, "attribute 'send' of 'undefined_gen' undefined"):
897+
# TODO: Should be UnboundLocalError, this test verifies that the attribute name
898+
# matches the variable name in the input code, since internally it's generated
899+
# with a prefix.
900+
list(undefined())

0 commit comments

Comments
 (0)