1.1 --- a/TO_DO.txt Thu Oct 24 23:30:41 2013 +0200
1.2 +++ b/TO_DO.txt Fri Oct 25 00:59:37 2013 +0200
1.3 @@ -131,7 +131,8 @@
1.4 Additional Guards
1.5 -----------------
1.6
1.7 -Consider handling branches of values within namespaces in order to support more precise value usage.
1.8 +Consider handling branches of values within namespaces in order to support more precise
1.9 +value usage.
1.10
1.11 Loop entry points and other places where usage becomes more specific might be used as
1.12 places to impose guards. See tests/attribute_access_type_restriction_loop_list.py for an
1.13 @@ -187,7 +188,8 @@
1.14 Currently, this is done only for Const values in the context of attribute accesses during
1.15 inspection.
1.16
1.17 -Handling CallFunc in a similar way is more challenging. Consider the definitions in the sys module:
1.18 +Handling CallFunc in a similar way is more challenging. Consider the definitions in the
1.19 +sys module:
1.20
1.21 stderr = file()
1.22
1.23 @@ -196,6 +198,20 @@
1.24 If file can also refer to other objects, potential filtering operations are more severely
1.25 limited.
1.26
1.27 +Propagation of type information can also occur. For example:
1.28 +
1.29 + DeducedSource(module, program).deduce()
1.30 +
1.31 +The DeducedSource invocation, if yielding an instance of the DeducedSource class, can then
1.32 +supply the attribute access operation with type information.
1.33 +
1.34 +A more advanced example involves accesses then invocations:
1.35 +
1.36 + x = self.__class__()
1.37 +
1.38 +Here, the effect should be the inference that x may refer to an instance of one of a
1.39 +number of eligible types of which self is also an instance.
1.40 +
1.41 Invocation-Related Deduction
1.42 ============================
1.43
1.44 @@ -269,7 +285,8 @@
1.45 Importing Modules
1.46 =================
1.47
1.48 -Consider supporting relative imports, even though this is arguably a misfeature.
1.49 +(Explicit relative imports are now supported.) Consider supporting relative imports, even
1.50 +though this is arguably a misfeature.
1.51
1.52 Other
1.53 =====
2.1 --- a/docs/annotations.txt Thu Oct 24 23:30:41 2013 +0200
2.2 +++ b/docs/annotations.txt Fri Oct 25 00:59:37 2013 +0200
2.3 @@ -23,10 +23,14 @@
2.4 defines a common position employed by all deduced
2.5 attributes for an access operation which is relative to
2.6 the accessor evaluated at run time
2.7 -_set_context indicates the deduced effect on the context in an access
2.8 +_set_context (_access_type is "constant" or "static")
2.9 + ("set", "cond", None)
2.10 + indicates the deduced effect on the context in an access
2.11 operation, whether the context would be replaced
2.12 unconditionally or conditionally
2.13 +
2.14
2.15 +_attrs_deduced_from_specific_usage
2.16 _attrs_deduced_from_usage
2.17 _attrs_deduced
2.18 provided as additional annotations more suitable for
3.1 --- a/micropython/common.py Thu Oct 24 23:30:41 2013 +0200
3.2 +++ b/micropython/common.py Fri Oct 25 00:59:37 2013 +0200
3.3 @@ -21,7 +21,7 @@
3.4
3.5 from compiler.ast import AssAttr, Getattr, Name
3.6 import compiler.ast
3.7 -from micropython.basicdata import Const, Constant
3.8 +from micropython.basicdata import Const, Constant, TypedInstance
3.9 from micropython.data import Attr, Class, Module
3.10 from micropython.errors import *
3.11 from os.path import split
3.12 @@ -99,7 +99,7 @@
3.13 can be returned as the result where no concrete details can be provided.
3.14 """
3.15
3.16 - if isinstance(obj, Constant):
3.17 + if isinstance(obj, (Constant, TypedInstance)):
3.18 return None, obj
3.19
3.20 if isinstance(obj, Attr):
4.1 --- a/micropython/deduce.py Thu Oct 24 23:30:41 2013 +0200
4.2 +++ b/micropython/deduce.py Fri Oct 25 00:59:37 2013 +0200
4.3 @@ -36,6 +36,7 @@
4.4 self.program = program
4.5 self.objtable = program.get_object_table()
4.6 self.units = []
4.7 + self.expr = None
4.8
4.9 def get_unit(self):
4.10 return self.units[-1]
4.11 @@ -105,7 +106,9 @@
4.12 # cases.
4.13
4.14 target = node._expr
4.15 - instance_target = isinstance(target, Const)
4.16 + instance_target = isinstance(target, TypedInstance)
4.17 + typed_instance_attr = isinstance(target, Attr) and isinstance(target.get_value(), TypedInstance)
4.18 + self_access = self.provides_self_access(node, unit)
4.19
4.20 # Attempt to deduce attributes from explicit annotations.
4.21
4.22 @@ -143,14 +146,34 @@
4.23 node._access_type = "impossible"
4.24 return
4.25
4.26 - # Attributes of self, which is by definition an instance.
4.27 + # Attributes of self, which is by definition an instance, or typed
4.28 + # instances, which act somewhat like self in that their properties
4.29 + # should be known.
4.30 +
4.31 + if instance_target or typed_instance_attr or self_access:
4.32
4.33 - if self.provides_self_access(node, unit):
4.34 + if instance_target:
4.35 + value = target
4.36 + elif typed_instance_attr:
4.37 + value = target.get_value()
4.38 +
4.39 + # Find the class of the instance.
4.40 +
4.41 + if instance_target or typed_instance_attr:
4.42 + if isinstance(value, Const):
4.43 + cls = get_constant_class(value.get_class_name())
4.44 + else:
4.45 + cls = value.cls
4.46 + else:
4.47 + cls = unit.parent
4.48
4.49 # Find instance attributes.
4.50
4.51 - attr = unit.parent.instance_attributes().get(node.attrname)
4.52 - attrs = filter(None, [cls.instance_attributes().get(node.attrname) for cls in unit.parent.descendants])
4.53 + attr = cls.instance_attributes().get(node.attrname)
4.54 +
4.55 + # Where self is involved, descendants can also provide attributes.
4.56 +
4.57 + attrs = self_access and filter(None, [desc.instance_attributes().get(node.attrname) for desc in cls.descendants]) or []
4.58
4.59 # A "leaf" class whose instances provide an attribute.
4.60
4.61 @@ -185,7 +208,7 @@
4.62 # The context will be overridden for compatible class attributes
4.63 # only.
4.64
4.65 - attr = unit.parent.get(node.attrname)
4.66 + attr = cls.all_class_attributes().get(node.attrname)
4.67
4.68 if attr:
4.69
4.70 @@ -195,6 +218,7 @@
4.71 if self.provides_constant_result(attr.get_value()):
4.72 node._access_type = "constant"
4.73 node._value_deduced = attr.get_value()
4.74 + node._set_context = "set"
4.75 return
4.76
4.77 # Compatible class attributes.
4.78 @@ -287,6 +311,32 @@
4.79
4.80 visitAssAttr = visitGetattr = _visitAttr
4.81
4.82 + def visitAssign(self, node):
4.83 + self.expr = self.dispatch(node.expr)
4.84 + for n in node.nodes:
4.85 + self.dispatch(n)
4.86 +
4.87 + def visitAssName(self, node):
4.88 + if self.expr:
4.89 + if isinstance(self.expr, Attr):
4.90 + expr = self.expr.get_value()
4.91 + elif isinstance(self.expr, TypedInstance):
4.92 + expr = self.expr
4.93 + else:
4.94 + return
4.95 + else:
4.96 + return
4.97 +
4.98 + attr = node._attr
4.99 +
4.100 + if attr:
4.101 + value = attr.get_value()
4.102 +
4.103 + # Need to replace any uncertain value with a concrete value.
4.104 +
4.105 + if value and isinstance(value, Instance) and not isinstance(value, TypedInstance):
4.106 + attr.context_values = set([get_context_and_value(expr)])
4.107 +
4.108 def visitCallFunc(self, node):
4.109
4.110 "Identify any concrete types involved with instantiation."
4.111 @@ -301,7 +351,7 @@
4.112 if attr:
4.113 value = attr.get_value()
4.114 if value and isinstance(value, Class):
4.115 - return attr
4.116 + return TypedInstance(value)
4.117
4.118 # Convenience functions.
4.119