Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 15 additions & 5 deletions pytype/tests/test_typing1.py
Original file line number Diff line number Diff line change
Expand Up @@ -686,16 +686,26 @@ def test_supported_construct_in_supported_version(self):
(3, 12),
"This only happens with 3.12 where it puts LOAD_FAST_AND_CLEAR op",
)
def test_not_deleted(self):
# TODO(b/414069834): This shouldn't be an error.
errors = self.CheckWithErrors("""
def test_re_not_deleted_with_load_fast_and_clear(self):
self.Check("""
import re

class Foo():
A = [re.compile(r) for r in (r'___', )]
B = re.compile(r"dummy") # name-error[e]
B = re.compile(r"dummy")
""")

def test_deleted_x_normally(self):
errors = self.CheckWithErrors("""
x = 1
def f():
x = 2
del x
print(x) # name-error[e]
""")
self.assertErrorRegexes(errors, {"e": r"Name 're' is not defined"})
self.assertErrorRegexes(
errors, {"e": r"Name 'x' is not defined"}
)


if __name__ == "__main__":
Expand Down
22 changes: 19 additions & 3 deletions pytype/vm.py
Original file line number Diff line number Diff line change
Expand Up @@ -1681,19 +1681,35 @@ def _name_error_or_late_annotation(self, state, name):
def byte_LOAD_NAME(self, state, op):
"""Load a name. Can be a local, global, or builtin."""
name = op.argval
deleted_var = None
try:
state, val = self.load_local(state, name)
except KeyError:
if vm_utils.is_deleted_name(state, val):
deleted_var = val
raise KeyError()
except KeyError as e_local:
try:
state, val = self.load_global(state, name)
except KeyError as e:
if vm_utils.is_deleted_name(state, val):
deleted_var = val
raise e_local
except KeyError as e_global:
try:
if self._is_private(name):
# Private names must be explicitly imported.
self.trace_opcode(op, name, None)
raise KeyError(name) from e
raise KeyError(name) from e_global
state, val = self.load_builtin(state, name)
if vm_utils.is_deleted_name(state, val):
deleted_var = val
raise e_global
except KeyError:

if deleted_var is not None:
vm_utils.check_for_deleted(state, name, deleted_var, self.ctx)
self.trace_opcode(op, name, deleted_var)
return state.push(deleted_var)

if self._is_private(name) or not self.has_unknown_wildcard_imports:
one_val = self._name_error_or_late_annotation(state, name)
else:
Expand Down
4 changes: 4 additions & 0 deletions pytype/vm_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -930,6 +930,10 @@ def call_inplace_operator(state, iname, x, y, ctx):
return state, ret


def is_deleted_name(state, var):
return any(isinstance(x, abstract.Deleted) for x in var.Data(state.node))


def check_for_deleted(state, name, var, ctx):
for x in var.Data(state.node):
if isinstance(x, abstract.Deleted):
Expand Down
Loading