Rewrite del
to treat undefinedness in a consistent manner.
PiperOrigin-RevId: 312947175 Change-Id: Ida4cb8c97ff280cb1011e33edc20a5c524fb8f8a
This commit is contained in:
parent
144b3dc790
commit
c76a8d14b1
@ -60,6 +60,31 @@ class VariableAccessTransformer(converter.Base):
|
|||||||
node = templates.replace_as_expression('ag__.ld(var_)', var_=node)
|
node = templates.replace_as_expression('ag__.ld(var_)', var_=node)
|
||||||
return node
|
return node
|
||||||
|
|
||||||
|
def visit_Delete(self, node):
|
||||||
|
node = self.generic_visit(node)
|
||||||
|
|
||||||
|
rewrite_targets = []
|
||||||
|
for tgt in node.targets:
|
||||||
|
# Don't rewrite composites like `del a[0]`.
|
||||||
|
if isinstance(tgt, gast.Name):
|
||||||
|
rewrite_targets.append(tgt)
|
||||||
|
|
||||||
|
if not rewrite_targets:
|
||||||
|
return node
|
||||||
|
|
||||||
|
results = []
|
||||||
|
for tgt in rewrite_targets:
|
||||||
|
template = """
|
||||||
|
var_ = ag__.Undefined(var_name)
|
||||||
|
"""
|
||||||
|
results.extend(templates.replace(
|
||||||
|
template, var_=tgt, var_name=gast.Constant(tgt.id, kind=None)))
|
||||||
|
remaining_targets = [n for n in node.targets if n not in rewrite_targets]
|
||||||
|
if remaining_targets:
|
||||||
|
results.append(gast.Delete(targets=remaining_targets))
|
||||||
|
|
||||||
|
return results
|
||||||
|
|
||||||
def visit_AugAssign(self, node):
|
def visit_AugAssign(self, node):
|
||||||
if isinstance(node.target, gast.Name):
|
if isinstance(node.target, gast.Name):
|
||||||
template = """
|
template = """
|
||||||
|
@ -51,6 +51,90 @@ class VariablesTest(converter_testing.TestCase):
|
|||||||
with self.apply_add_one_conversion(test_fn) as result:
|
with self.apply_add_one_conversion(test_fn) as result:
|
||||||
self.assertEqual(result.test_fn(1), (1 + 1) * 10 + 1) # two reads
|
self.assertEqual(result.test_fn(1), (1 + 1) * 10 + 1) # two reads
|
||||||
|
|
||||||
|
def test_del(self):
|
||||||
|
|
||||||
|
def test_fn(l):
|
||||||
|
del l
|
||||||
|
return l
|
||||||
|
|
||||||
|
with self.converted(test_fn, variables, {}) as result:
|
||||||
|
with self.assertRaisesRegex(
|
||||||
|
NameError, "'l' is used before assignment"):
|
||||||
|
result.test_fn(1)
|
||||||
|
|
||||||
|
def test_del_getitem_ignored(self):
|
||||||
|
|
||||||
|
def basic_slice(l):
|
||||||
|
del l[0]
|
||||||
|
return l
|
||||||
|
|
||||||
|
with self.converted(basic_slice, variables, {}) as result:
|
||||||
|
self.assertListEqual([2], result.basic_slice([1, 2]))
|
||||||
|
|
||||||
|
def range_slice(l):
|
||||||
|
del l[0:2]
|
||||||
|
return l
|
||||||
|
|
||||||
|
with self.converted(range_slice, variables, {}) as result:
|
||||||
|
self.assertListEqual([], result.range_slice([1, 2]))
|
||||||
|
|
||||||
|
def test_del_getattr_ignored(self):
|
||||||
|
|
||||||
|
def test_fn(l):
|
||||||
|
del l.a
|
||||||
|
return l
|
||||||
|
|
||||||
|
class TestClass(object):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.a = 1
|
||||||
|
self.b = 2
|
||||||
|
|
||||||
|
with self.converted(test_fn, variables, {}) as result:
|
||||||
|
self.assertFalse(hasattr(result.test_fn(TestClass()), 'a'))
|
||||||
|
self.assertEqual(result.test_fn(TestClass()).b, 2)
|
||||||
|
|
||||||
|
def test_del_packing_ignored(self):
|
||||||
|
# Note: test for UnboundLocalError, not NameError because in this case we
|
||||||
|
# don't rewrite the del.
|
||||||
|
|
||||||
|
def list_(a, b):
|
||||||
|
del [a, b]
|
||||||
|
return a
|
||||||
|
|
||||||
|
with self.converted(list_, variables, {}) as result:
|
||||||
|
with self.assertRaises(UnboundLocalError):
|
||||||
|
result.list_(1, 2)
|
||||||
|
|
||||||
|
def nested(a, b, c):
|
||||||
|
del [a, (b, c)]
|
||||||
|
return c
|
||||||
|
|
||||||
|
with self.converted(nested, variables, {}) as result:
|
||||||
|
with self.assertRaises(UnboundLocalError):
|
||||||
|
result.nested(1, 2, 3)
|
||||||
|
|
||||||
|
def test_del_item_multiple_mixed(self):
|
||||||
|
|
||||||
|
def test_fn_failing(a, b, c):
|
||||||
|
del a, b, c[0]
|
||||||
|
a = 1
|
||||||
|
return a, b, c
|
||||||
|
|
||||||
|
with self.converted(test_fn_failing, variables, {}) as result:
|
||||||
|
with self.assertRaisesRegex(
|
||||||
|
NameError, "'b' is used before assignment"):
|
||||||
|
result.test_fn_failing(1, 2, [1, 2])
|
||||||
|
|
||||||
|
def test_fn_passing(a, b, c):
|
||||||
|
del a, b, c[0]
|
||||||
|
a = 1
|
||||||
|
b = 2
|
||||||
|
return c
|
||||||
|
|
||||||
|
with self.converted(test_fn_passing, variables, {}) as result:
|
||||||
|
self.assertListEqual([2], result.test_fn_passing(1, 2, [1, 2]))
|
||||||
|
|
||||||
def test_attribute(self):
|
def test_attribute(self):
|
||||||
|
|
||||||
class TestClass(object):
|
class TestClass(object):
|
||||||
|
Loading…
Reference in New Issue
Block a user