Skip to content

Commit 2a264d6

Browse files
[mypyc] fix: UnboundLocalError incorrectly raised as AttributeError
fixes mypyc/mypyc#1151 I'm not entirely sure what the difference is between emit_attribute_error and the code block that I edited I'm not sure if we need to update both cases, but I know we do need to handle it in this one
1 parent 37333c7 commit 2a264d6

File tree

1 file changed

+14
-7
lines changed

1 file changed

+14
-7
lines changed

mypyc/codegen/emitfunc.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -434,14 +434,21 @@ def visit_get_attr(self, op: GetAttr) -> None:
434434
merged_branch = branch
435435
self.emitter.emit_line("}")
436436
if not merged_branch:
437-
exc_class = "PyExc_AttributeError"
438-
self.emitter.emit_line(
439-
'PyErr_SetString({}, "attribute {} of {} undefined");'.format(
440-
exc_class,
441-
repr(op.attr.removeprefix(GENERATOR_ATTRIBUTE_PREFIX)),
442-
repr(cl.name),
437+
var_name = op.attr.removeprefix(GENERATOR_ATTRIBUTE_PREFIX)
438+
if cl.is_generated:
439+
# A generated class does not "exist" to the user, this is just an unbound
440+
# variable in their code, not a missing attribute on the generated class.
441+
# NOTE We are safe to use the more specific UnboundLocalError here because
442+
# we know that NameError type cases won't compile.
443+
exc_class = "PyExc_UnboundLocalError"
444+
self.emitter.emit_line(
445+
f'PyErr_SetString({exc_class}, "local variable {var_name!r} referenced before assignment");'
446+
)
447+
else:
448+
exc_class = "PyExc_AttributeError"
449+
self.emitter.emit_line(
450+
f'PyErr_SetString({exc_class}, "attribute {var_name!r} of {cl.name!r} undefined");'
443451
)
444-
)
445452

446453
if attr_rtype.is_refcounted and not op.is_borrowed:
447454
if not merged_branch and not always_defined:

0 commit comments

Comments
 (0)