1.1 --- a/micropython/data.py Tue Oct 27 00:23:28 2009 +0100
1.2 +++ b/micropython/data.py Mon Nov 02 01:06:38 2009 +0100
1.3 @@ -283,11 +283,15 @@
1.4 if not defs.has_key(name):
1.5 defs[name] = set()
1.6 defs[name].add(attrname)
1.7 + return defs[name]
1.8
1.9 def _reset_attributes(self, name):
1.10 defs = self.attributes_used[-1]
1.11 defs[name] = set()
1.12
1.13 + def _reset_all_attributes(self):
1.14 + self.attributes_used[-1] = {}
1.15 +
1.16 def _new_branchpoint(self):
1.17 self.attribute_shelves.append([])
1.18
1.19 @@ -309,11 +313,11 @@
1.20 for next_defs in shelved_defs[1:]:
1.21 for name, attrnames in next_defs.items():
1.22 if defs.has_key(name):
1.23 - defs[name].intersection_update(attrnames)
1.24 + defs[name] = defs[name].intersection(attrnames)
1.25
1.26 for name, attrnames in defs.items():
1.27 if active.has_key(name):
1.28 - active[name].intersection_update(attrnames)
1.29 + active[name] = active[name].intersection(attrnames)
1.30 else:
1.31 active[name] = attrnames
1.32
2.1 --- a/micropython/inspect.py Tue Oct 27 00:23:28 2009 +0100
2.2 +++ b/micropython/inspect.py Mon Nov 02 01:06:38 2009 +0100
2.3 @@ -314,8 +314,11 @@
2.4 def reset_attributes(self, name):
2.5 self.get_namespace()._reset_attributes(name)
2.6
2.7 + def reset_all_attributes(self):
2.8 + self.get_namespace()._reset_all_attributes()
2.9 +
2.10 def use_attribute(self, attr, attrname):
2.11 - self.get_namespace()._use_attribute(attr, attrname)
2.12 + return self.get_namespace()._use_attribute(attr, attrname)
2.13
2.14 # Visitor methods.
2.15
2.16 @@ -449,7 +452,7 @@
2.17 # Note usage of the attribute.
2.18
2.19 if expr.parent is self.get_namespace():
2.20 - self.use_attribute(expr, node.attrname)
2.21 + node._attrnames = self.use_attribute(expr, node.attrname)
2.22
2.23 return None
2.24
2.25 @@ -510,7 +513,8 @@
2.26
2.27 visitBitxor = _visitBinary
2.28
2.29 - visitBreak = NOP
2.30 + def visitBreak(self, node):
2.31 + self.reset_all_attributes()
2.32
2.33 visitCallFunc = OP
2.34
2.35 @@ -589,7 +593,8 @@
2.36 self.use_name(self.importer.get_constant_type_name(node.value))
2.37 return self.importer.make_constant(node.value)
2.38
2.39 - visitContinue = NOP
2.40 + def visitContinue(self, node):
2.41 + self.reset_all_attributes()
2.42
2.43 visitDecorators = NOP
2.44
2.45 @@ -619,6 +624,7 @@
2.46 self.dispatch(node.list)
2.47
2.48 # Enter the loop.
2.49 + # Propagate attribute usage to branches.
2.50
2.51 self.in_loop = 1
2.52 self.new_branch()
2.53 @@ -626,10 +632,13 @@
2.54 self.shelve_branch()
2.55 self.in_loop = 0
2.56
2.57 + # Maintain a branch for the else clause or the current retained usage
2.58 + # where execution avoids the conditional clauses.
2.59 +
2.60 + self.new_branch()
2.61 if node.else_ is not None:
2.62 - self.new_branch()
2.63 self.dispatch(node.else_)
2.64 - self.shelve_branch()
2.65 + self.shelve_branch()
2.66
2.67 self.merge_branches()
2.68 return None
2.69 @@ -691,7 +700,7 @@
2.70 # Note usage of the attribute.
2.71
2.72 if expr.parent is self.get_namespace():
2.73 - self.use_attribute(expr, attrname)
2.74 + node._attrnames = self.use_attribute(expr, attrname)
2.75
2.76 elif self.builtins is not None:
2.77 attr = self.builtins.get(attrname)
2.78 @@ -716,6 +725,8 @@
2.79 def visitIf(self, node):
2.80 self.new_branchpoint()
2.81
2.82 + # Propagate attribute usage to branches.
2.83 +
2.84 for test, body in node.tests:
2.85 self.dispatch(test)
2.86
2.87 @@ -723,10 +734,13 @@
2.88 self.dispatch(body)
2.89 self.shelve_branch()
2.90
2.91 + # Maintain a branch for the else clause or the current retained usage
2.92 + # where execution avoids the conditional clauses.
2.93 +
2.94 + self.new_branch()
2.95 if node.else_ is not None:
2.96 - self.new_branch()
2.97 self.dispatch(node.else_)
2.98 - self.shelve_branch()
2.99 + self.shelve_branch()
2.100
2.101 self.merge_branches()
2.102 return None
2.103 @@ -863,6 +877,8 @@
2.104 def visitWhile(self, node):
2.105 self.new_branchpoint()
2.106
2.107 + # Propagate attribute usage to branches.
2.108 +
2.109 self.in_loop = 1
2.110 self.dispatch(node.test)
2.111 self.new_branch()
2.112 @@ -870,10 +886,13 @@
2.113 self.shelve_branch()
2.114 self.in_loop = 0
2.115
2.116 + # Maintain a branch for the else clause or the current retained usage
2.117 + # where execution avoids the conditional clauses.
2.118 +
2.119 + self.new_branch()
2.120 if node.else_ is not None:
2.121 - self.new_branch()
2.122 self.dispatch(node.else_)
2.123 - self.shelve_branch()
2.124 + self.shelve_branch()
2.125
2.126 self.merge_branches()
2.127 return None
3.1 --- a/tests/attribute_access_type_restriction.py Tue Oct 27 00:23:28 2009 +0100
3.2 +++ b/tests/attribute_access_type_restriction.py Mon Nov 02 01:06:38 2009 +0100
3.3 @@ -11,34 +11,63 @@
3.4 def g(self):
3.5 return 3
3.6
3.7 +class E:
3.8 + def f(self):
3.9 + return 4
3.10 +
3.11 + def h(self):
3.12 + return 5
3.13 +
3.14 def test_one(obj):
3.15 - obj.f()
3.16 - return obj.g()
3.17 + obj.f() # C, D, E -> D
3.18 + return obj.g() # D
3.19 + # obj: D
3.20
3.21 -def test_neither(obj, obj2):
3.22 - if obj.f():
3.23 +def test_two(obj, obj2):
3.24 + if obj.f(): # C, D, E (f)
3.25 + obj.g() # D (f, g)
3.26 + # else:
3.27 + # ... # obj: C, D, E (f)
3.28 + # # (f, g) ^ (f)
3.29 + return 2
3.30 + # obj: C, D, E (f)
3.31 +
3.32 +def test_new(obj, obj2):
3.33 + if obj.f(): # C, D, E (f)
3.34 obj = obj2
3.35 - obj.g()
3.36 - return 2
3.37 -
3.38 -def test_either(obj, obj2):
3.39 - if obj:
3.40 - obj = obj2
3.41 - obj.g()
3.42 - return obj.f()
3.43 + obj.g() # D (g)
3.44 + # else:
3.45 + # ... # obj: C, D, E (f)
3.46 + # # (g) ^ (f)
3.47 + return obj.f() # C, D, E (f)
3.48 + # obj: C, D, E (f)
3.49
3.50 def test_neither2(obj, obj2):
3.51 - if obj:
3.52 - obj.g()
3.53 + if 0:
3.54 + obj.g() # D (g)
3.55 else:
3.56 - obj.f()
3.57 + obj.f() # C, D, E (f)
3.58 + # # (g) ^ (f)
3.59 return 4
3.60 + # obj:
3.61 +
3.62 +def test_three(obj, obj2):
3.63 + if obj.f(): # C, D, E (f)
3.64 + obj = obj2
3.65 + obj.g() # D (g)
3.66 + else:
3.67 + obj.h() # E (f, h)
3.68 + # # (g) ^ (f, h)
3.69 + return 5
3.70 + # obj:
3.71
3.72 c = C()
3.73 d = D()
3.74 +e = E()
3.75 result1_3 = test_one(d)
3.76 -result1_2 = test_neither(c, d)
3.77 -result2_2 = test_either(c, d)
3.78 +result1_2 = test_two(c, d)
3.79 +result2_2 = test_new(c, d)
3.80 result1_4 = test_neither2(c, d)
3.81 +result1_5 = test_three(e, d)
3.82
3.83 # vim: tabstop=4 expandtab shiftwidth=4