# HG changeset patch # User Paul Boddie # Date 1284414721 -7200 # Node ID a44d9073aae7dd0f139b92dc05bb0ec52c8f61e5 # Parent 5c1afd2b8d158dc0222ccedf2abae6b92643bdb6 Added a special class for abandoned branch users dictionaries, preventing any usage being recorded after a branch is abandoned. Moved any else clauses for "for" and "while" loops into the loop branch during inspection, thus combining loop usage with the termination clause of each loop. Added various tests and notes. diff -r 5c1afd2b8d15 -r a44d9073aae7 TO_DO.txt --- a/TO_DO.txt Mon Sep 13 01:44:37 2010 +0200 +++ b/TO_DO.txt Mon Sep 13 23:52:01 2010 +0200 @@ -1,6 +1,3 @@ -Make use of the _attrcombined annotation instead of _attrnames when deducing types and -defining guards. - Support slicing. This is difficult because __getitem__ has to handle integers and slice objects differently. One could either just try and iterate over the argument and then catch the AttributeError for integers, or one could test the instances first. @@ -23,8 +20,6 @@ the compilation to fail. Alternatively, just supply the methods since something has to do so in the builtins. -Support tuple parameters. - Consider type deduction and its consequences where types belong to the same hierarchy and where a guard could be generated for the most general type. diff -r 5c1afd2b8d15 -r a44d9073aae7 docs/rationale.txt --- a/docs/rationale.txt Mon Sep 13 01:44:37 2010 +0200 +++ b/docs/rationale.txt Mon Sep 13 23:52:01 2010 +0200 @@ -161,29 +161,33 @@ * Control-flow can make attribute tracking awkward: obj.x # obj must have x - if ...: # (branch) + if obj.p: # obj must have x, p + # (branch) obj = ... # obj reset obj.attr # obj must have attr + # (end of branch) else: # (branch) - obj.name # obj must have x, name - # (merge) - # obj must have + obj.name # obj must have x, p, name + # (end of branch) + # (merge branch ends) + # obj must have either attr or x, p, name Attributes on locals with loops * Loops complicate matters still further: obj.x # obj must have x - while ...: # (branch) - obj.y # obj must have x, y + while obj.p: # obj must have x, p + # (branch) + obj.y # obj must have x, p, y obj = ... # obj reset obj.z # obj must have z - # (re-branch) - # obj must have z, y (obj.y) - # obj reset (obj = ...) - # obj must have z, y (obj.z) - # (merge) - # obj must have + # (re-test) + # obj must have z, p + # (end of branch) + # (null branch - no else) + # (merge branch ends) + # obj must have either z, p (from loop) or x, p (from null branch) Attributes on attributes diff -r 5c1afd2b8d15 -r a44d9073aae7 micropython/data.py --- a/micropython/data.py Mon Sep 13 01:44:37 2010 +0200 +++ b/micropython/data.py Mon Sep 13 23:52:01 2010 +0200 @@ -638,7 +638,7 @@ provided these cannot "escape" from the branch. """ - self.attribute_users[-1] = {} + self.attribute_users[-1] = AbandonedBranchUsers() self.scope_usage[-1] = AbandonedBranchScope() def _shelve_branch(self): @@ -772,14 +772,11 @@ scope_usage = self.scope_usage[-1] return scope_usage.get(name) == scope -# Special helper classes for scope resolution. - -class AbandonedBranchScope: - - """ - A class providing a value or state for an abandoned branch distinct from an - empty scope dictionary. - """ +# Special helper classes for usage and scope resolution. + +class EmptyDict: + + "A class providing dictionaries which retain no information." def has_key(self, name): return 0 @@ -798,6 +795,24 @@ values = items = keys +class AbandonedBranchUsers(EmptyDict): + + """ + A class providing a value or state for an abandoned branch distinct from an + empty usage dictionary. + """ + + pass + +class AbandonedBranchScope(EmptyDict): + + """ + A class providing a value or state for an abandoned branch distinct from an + empty scope dictionary. + """ + + pass + class ScopeConflict: """ diff -r 5c1afd2b8d15 -r a44d9073aae7 micropython/inspect.py --- a/micropython/inspect.py Mon Sep 13 01:44:37 2010 +0200 +++ b/micropython/inspect.py Mon Sep 13 23:52:01 2010 +0200 @@ -800,11 +800,17 @@ self.new_branch(node) self.dispatch(node.body) + + # Incorporate the else clause in the branch, if present. + + if node.else_ is not None: + self.dispatch(node.else_) + self.shelve_branch() self.in_loop = in_loop - # Maintain a branch for the else clause. + # Maintain a separate branch for the else clause. self.new_branch(node.else_ or NullBranch()) if node.else_ is not None: @@ -1055,12 +1061,17 @@ # The test is evaluated again within the loop. self.dispatch(node.test) + + # Incorporate the else clause in the branch, if present. + + if node.else_ is not None: + self.dispatch(node.else_) + self.shelve_branch() self.in_loop = in_loop # Maintain a branch for the else clause. - # NOTE: Consider merging here before the else clause. self.new_branch(node.else_ or NullBranch()) if node.else_ is not None: diff -r 5c1afd2b8d15 -r a44d9073aae7 tests/attribute_access_type_restriction_for_else.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/attribute_access_type_restriction_for_else.py Mon Sep 13 23:52:01 2010 +0200 @@ -0,0 +1,28 @@ +#!/usr/bin/env python + +class C: + def f(self): + return 1 + +class D: + def f(self): + return 2 + + def g(self): + return 3 + +def test_loop(d): # d: f, g; g + for j in xrange(0, 10): + k = d.f() # d: f + # d: f, g (from else) + else: + k = d.g() # d: g + + return k + +c = C() +d = D() + +result_3 = test_loop(d) + +# vim: tabstop=4 expandtab shiftwidth=4 diff -r 5c1afd2b8d15 -r a44d9073aae7 tests/attribute_access_type_restriction_loop_else.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/attribute_access_type_restriction_loop_else.py Mon Sep 13 23:52:01 2010 +0200 @@ -0,0 +1,40 @@ +#!/usr/bin/env python + +class C: + def e(self): + return 2 + + def f(self): + return 1 + +class D: + def e(self): + return 6 + + def f(self): + return 0 # stops the test loop + + def g(self): + return 3 + +class E: + def f(self): + return 4 + + def h(self): # unused + return 5 + +def test_loop(obj, obj2): + while obj.f(): + obj = obj2 + obj.g() + else: + obj.e() + return obj.f() + +c = C() +d = D() +e = E() +result1_0 = test_loop(c, d) + +# vim: tabstop=4 expandtab shiftwidth=4