1.1 --- a/TO_DO.txt Mon Sep 13 01:44:37 2010 +0200
1.2 +++ b/TO_DO.txt Mon Sep 13 23:52:01 2010 +0200
1.3 @@ -1,6 +1,3 @@
1.4 -Make use of the _attrcombined annotation instead of _attrnames when deducing types and
1.5 -defining guards.
1.6 -
1.7 Support slicing. This is difficult because __getitem__ has to handle integers and slice
1.8 objects differently. One could either just try and iterate over the argument and then
1.9 catch the AttributeError for integers, or one could test the instances first.
1.10 @@ -23,8 +20,6 @@
1.11 the compilation to fail. Alternatively, just supply the methods since something has to do
1.12 so in the builtins.
1.13
1.14 -Support tuple parameters.
1.15 -
1.16 Consider type deduction and its consequences where types belong to the same hierarchy
1.17 and where a guard could be generated for the most general type.
1.18
2.1 --- a/docs/rationale.txt Mon Sep 13 01:44:37 2010 +0200
2.2 +++ b/docs/rationale.txt Mon Sep 13 23:52:01 2010 +0200
2.3 @@ -161,29 +161,33 @@
2.4 * Control-flow can make attribute tracking awkward:
2.5
2.6 obj.x # obj must have x
2.7 - if ...: # (branch)
2.8 + if obj.p: # obj must have x, p
2.9 + # (branch)
2.10 obj = ... # obj reset
2.11 obj.attr # obj must have attr
2.12 + # (end of branch)
2.13 else: # (branch)
2.14 - obj.name # obj must have x, name
2.15 - # (merge)
2.16 - # obj must have <nothing>
2.17 + obj.name # obj must have x, p, name
2.18 + # (end of branch)
2.19 + # (merge branch ends)
2.20 + # obj must have either attr or x, p, name
2.21
2.22 Attributes on locals with loops
2.23
2.24 * Loops complicate matters still further:
2.25
2.26 obj.x # obj must have x
2.27 - while ...: # (branch)
2.28 - obj.y # obj must have x, y
2.29 + while obj.p: # obj must have x, p
2.30 + # (branch)
2.31 + obj.y # obj must have x, p, y
2.32 obj = ... # obj reset
2.33 obj.z # obj must have z
2.34 - # (re-branch)
2.35 - # obj must have z, y (obj.y)
2.36 - # obj reset (obj = ...)
2.37 - # obj must have z, y (obj.z)
2.38 - # (merge)
2.39 - # obj must have <nothing>
2.40 + # (re-test)
2.41 + # obj must have z, p
2.42 + # (end of branch)
2.43 + # (null branch - no else)
2.44 + # (merge branch ends)
2.45 + # obj must have either z, p (from loop) or x, p (from null branch)
2.46
2.47 Attributes on attributes
2.48
3.1 --- a/micropython/data.py Mon Sep 13 01:44:37 2010 +0200
3.2 +++ b/micropython/data.py Mon Sep 13 23:52:01 2010 +0200
3.3 @@ -638,7 +638,7 @@
3.4 provided these cannot "escape" from the branch.
3.5 """
3.6
3.7 - self.attribute_users[-1] = {}
3.8 + self.attribute_users[-1] = AbandonedBranchUsers()
3.9 self.scope_usage[-1] = AbandonedBranchScope()
3.10
3.11 def _shelve_branch(self):
3.12 @@ -772,14 +772,11 @@
3.13 scope_usage = self.scope_usage[-1]
3.14 return scope_usage.get(name) == scope
3.15
3.16 -# Special helper classes for scope resolution.
3.17 -
3.18 -class AbandonedBranchScope:
3.19 -
3.20 - """
3.21 - A class providing a value or state for an abandoned branch distinct from an
3.22 - empty scope dictionary.
3.23 - """
3.24 +# Special helper classes for usage and scope resolution.
3.25 +
3.26 +class EmptyDict:
3.27 +
3.28 + "A class providing dictionaries which retain no information."
3.29
3.30 def has_key(self, name):
3.31 return 0
3.32 @@ -798,6 +795,24 @@
3.33
3.34 values = items = keys
3.35
3.36 +class AbandonedBranchUsers(EmptyDict):
3.37 +
3.38 + """
3.39 + A class providing a value or state for an abandoned branch distinct from an
3.40 + empty usage dictionary.
3.41 + """
3.42 +
3.43 + pass
3.44 +
3.45 +class AbandonedBranchScope(EmptyDict):
3.46 +
3.47 + """
3.48 + A class providing a value or state for an abandoned branch distinct from an
3.49 + empty scope dictionary.
3.50 + """
3.51 +
3.52 + pass
3.53 +
3.54 class ScopeConflict:
3.55
3.56 """
4.1 --- a/micropython/inspect.py Mon Sep 13 01:44:37 2010 +0200
4.2 +++ b/micropython/inspect.py Mon Sep 13 23:52:01 2010 +0200
4.3 @@ -800,11 +800,17 @@
4.4
4.5 self.new_branch(node)
4.6 self.dispatch(node.body)
4.7 +
4.8 + # Incorporate the else clause in the branch, if present.
4.9 +
4.10 + if node.else_ is not None:
4.11 + self.dispatch(node.else_)
4.12 +
4.13 self.shelve_branch()
4.14
4.15 self.in_loop = in_loop
4.16
4.17 - # Maintain a branch for the else clause.
4.18 + # Maintain a separate branch for the else clause.
4.19
4.20 self.new_branch(node.else_ or NullBranch())
4.21 if node.else_ is not None:
4.22 @@ -1055,12 +1061,17 @@
4.23 # The test is evaluated again within the loop.
4.24
4.25 self.dispatch(node.test)
4.26 +
4.27 + # Incorporate the else clause in the branch, if present.
4.28 +
4.29 + if node.else_ is not None:
4.30 + self.dispatch(node.else_)
4.31 +
4.32 self.shelve_branch()
4.33
4.34 self.in_loop = in_loop
4.35
4.36 # Maintain a branch for the else clause.
4.37 - # NOTE: Consider merging here before the else clause.
4.38
4.39 self.new_branch(node.else_ or NullBranch())
4.40 if node.else_ is not None:
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/tests/attribute_access_type_restriction_for_else.py Mon Sep 13 23:52:01 2010 +0200
5.3 @@ -0,0 +1,28 @@
5.4 +#!/usr/bin/env python
5.5 +
5.6 +class C:
5.7 + def f(self):
5.8 + return 1
5.9 +
5.10 +class D:
5.11 + def f(self):
5.12 + return 2
5.13 +
5.14 + def g(self):
5.15 + return 3
5.16 +
5.17 +def test_loop(d): # d: f, g; g
5.18 + for j in xrange(0, 10):
5.19 + k = d.f() # d: f
5.20 + # d: f, g (from else)
5.21 + else:
5.22 + k = d.g() # d: g
5.23 +
5.24 + return k
5.25 +
5.26 +c = C()
5.27 +d = D()
5.28 +
5.29 +result_3 = test_loop(d)
5.30 +
5.31 +# vim: tabstop=4 expandtab shiftwidth=4
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
6.2 +++ b/tests/attribute_access_type_restriction_loop_else.py Mon Sep 13 23:52:01 2010 +0200
6.3 @@ -0,0 +1,40 @@
6.4 +#!/usr/bin/env python
6.5 +
6.6 +class C:
6.7 + def e(self):
6.8 + return 2
6.9 +
6.10 + def f(self):
6.11 + return 1
6.12 +
6.13 +class D:
6.14 + def e(self):
6.15 + return 6
6.16 +
6.17 + def f(self):
6.18 + return 0 # stops the test loop
6.19 +
6.20 + def g(self):
6.21 + return 3
6.22 +
6.23 +class E:
6.24 + def f(self):
6.25 + return 4
6.26 +
6.27 + def h(self): # unused
6.28 + return 5
6.29 +
6.30 +def test_loop(obj, obj2):
6.31 + while obj.f():
6.32 + obj = obj2
6.33 + obj.g()
6.34 + else:
6.35 + obj.e()
6.36 + return obj.f()
6.37 +
6.38 +c = C()
6.39 +d = D()
6.40 +e = E()
6.41 +result1_0 = test_loop(c, d)
6.42 +
6.43 +# vim: tabstop=4 expandtab shiftwidth=4