# HG changeset patch # User Paul Boddie # Date 1265934868 -3600 # Node ID 0b86019411616eb4f8035d2aa8b241070b34015a # Parent 5e5eb65e8d5b42c79559b8fa1dd07bd1563e012b Added attribute user node shelving and merging in order to affect nodes which define names where such definitions remain active after a control-flow merge. Added a test of multiple type candidates for a guard, although the work required to support this properly is yet to be done. Added a to-do list. diff -r 5e5eb65e8d5b -r 0b8601941161 TO_DO.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/TO_DO.txt Fri Feb 12 01:34:28 2010 +0100 @@ -0,0 +1,19 @@ +Abandoned branches: should alternative type candidates be proposed by abandoned usage? +(This involves using both _attrnames and _attrnames_abandoned on user nodes to decide on whether guards are appropriate.) + +Usage should not be instantly fed back to users. +Branches should have an empty set of users and usage should only feed back to users defined on a branch or merged from sub-branches. + +Attribute users should be merged so that many users can be maintained for a name: + + def f(x): + if ...: + x = ... + x.a() # affects assignment node + x.b() # affects assignment and parameter nodes + +Constant attribute users need not maintain usage since they are already resolved. + +Consider handling CallFunc in micropython.inspect in order to produce instances of specific classes. +Then, consider adding support for guard removal/verification where known instances are involved. +Consider handling branches of values within namespaces in order to support more precise value usage. diff -r 5e5eb65e8d5b -r 0b8601941161 micropython/data.py --- a/micropython/data.py Wed Feb 10 01:25:48 2010 +0100 +++ b/micropython/data.py Fri Feb 12 01:34:28 2010 +0100 @@ -125,10 +125,10 @@ self.attributes_used = [{}] # stack of usage self.attribute_shelves = [] # stack of unmerged definitions + self.abandon_attributes = 0 # used when a block will never contribute + self.abandoned_shelves = [] self.attribute_users = [{}] # stack of assignments - self.abandon_attributes = 0 # used when a block will never contribute - self.attributes_abandoned = [{}] - self.abandoned_shelves = [] + self.user_shelves = [] self.all_attributes_used = [] # Attribute/name definition and access. @@ -310,7 +310,7 @@ def _use_attribute(self, name, attrname): """ - Indicate the use on the given 'name' in this namespace of an attribute + Indicate the use of the given 'name' in this namespace of an attribute with the given 'attrname'. """ @@ -325,6 +325,13 @@ defs[name] = set() defs[name].add(attrname) + + # Add the usage to all current users. + + if users.has_key(name): + for user in users[name]: + user._attrnames[name].add(attrname) + return defs[name] def _define_attribute_user(self, node): @@ -342,21 +349,20 @@ "Define 'node' as the user of attributes for the given 'name'." defs = self.attributes_used[-1] - abandoned_defs = self.attributes_abandoned[-1] users = self.attribute_users[-1] - users[name] = node + users[name] = set([node]) defs[name] = set() - abandoned_defs[name] = set() # Record the attribute combinations for the name. if not hasattr(node, "_attrnames"): node._attrnames = {} - node._attrnames_abandoned = {} - node._attrnames[name] = defs[name] - node._attrnames_abandoned[name] = abandoned_defs[name] + # Copy the current usage for the user since this may eventually become + # independent from the current usage. + + node._attrnames[name] = set(defs[name]) # Remember all attribute combinations. @@ -365,12 +371,16 @@ def _new_branchpoint(self): self.attribute_shelves.append([]) self.abandoned_shelves.append([]) + self.user_shelves.append([]) def _new_branch(self): d = {} for name, attrnames in self.attributes_used[-1].items(): d[name] = set(attrnames) self.attributes_used.append(d) + + # The users apply also to the new branch. + self.attribute_users.append({}) def _abandon_branch(self): @@ -393,9 +403,13 @@ collector.append(self.attributes_used.pop()) # Forget about any nodes which defined names employing attributes in - # this branch. + # this branch if the branch is abandoned. + + users = self.attribute_users.pop() - self.attribute_users.pop() + if not self.abandon_attributes: + self.user_shelves[-1].append(users) + self.abandon_attributes = 0 def _merge_branches(self): @@ -414,7 +428,6 @@ # branches. The abandoned dictionary collects abandoned usage. active = self.attributes_used[-1] - abandoned = self.attributes_abandoned[-1] # Take each alternative branch, currently shelved, and find the # intersection of their contributions for each name. @@ -441,16 +454,13 @@ else: active[name] = attrnames - # Where abandoned branches exist, record their contributions for the - # attribute users only. + # Combine the attribute users. + + users = self.attribute_users[-1] - if abandoned_defs: - for defs in abandoned_defs: - for name, attrnames in defs.items(): - if abandoned.has_key(name): - abandoned[name].add(tuple(attrnames)) - else: - abandoned[name] = attrnames + for shelved_users in self.user_shelves.pop(): + for name, nodes in shelved_users.items(): + users[name].update(nodes) # Where each shelved set of definitions is a superset of the eventual # definitions for a name, record these specialised sets of usage. diff -r 5e5eb65e8d5b -r 0b8601941161 tests/abandoned_attribute_usage_multiple_candidates.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/abandoned_attribute_usage_multiple_candidates.py Fri Feb 12 01:34:28 2010 +0100 @@ -0,0 +1,32 @@ +#!/usr/bin/env python + +""" +This test attempts to cause the recording of the usage of 'C' in the function +'f', alongside the expectation that 'D' might be used instead. A guard +stipulating constraints for all of 'f' cannot therefore be generated. Meanwhile, +the method 'E.h' should be eliminated. +""" + +class C: + def f(self): + return 1 + +class D: + def g(self): + return 2 + +class E: + def h(self): # unused + return 3 + +def f(c): + if 1: + return c.f() + return c.g() + +c = C() +d = D() +e = E() +result1_1 = f(c) + +# vim: tabstop=4 expandtab shiftwidth=4