1.1 --- a/micropython/deduce.py Mon Mar 10 23:12:41 2014 +0100
1.2 +++ b/micropython/deduce.py Mon Mar 10 23:14:26 2014 +0100
1.3 @@ -214,16 +214,35 @@
1.4 self.dispatch(node.node)
1.5 self.units.pop()
1.6
1.7 - def _visitOptionalUnit(self, node):
1.8 + visitModule = _visitUnit
1.9
1.10 - "Optionally visit a unit, depending on whether it is used."
1.11 + def visitClass(self, node):
1.12 +
1.13 + "Optionally visit a class, depending on whether it is used."
1.14
1.15 if not used_by_unit(node):
1.16 return
1.17 self._visitUnit(node)
1.18
1.19 - visitModule = _visitUnit
1.20 - visitClass = visitFunction = _visitOptionalUnit
1.21 + def visitFunction(self, node):
1.22 +
1.23 + "Optionally visit a function, depending on whether it is used."
1.24 +
1.25 + if not used_by_unit(node):
1.26 + return
1.27 +
1.28 + self.units.append(node.unit)
1.29 + self.dispatch(node.code)
1.30 + self.units.pop()
1.31 +
1.32 + node._guard_types = {}
1.33 + node._guards = {}
1.34 +
1.35 + for name in node.unit.positional_names:
1.36 + # NOTE: Test for tuple parameters (see micropython.report.Report._parameters).
1.37 + # NOTE: No _values usage here because it is mostly useless information, except perhaps for defaults.
1.38 + attrtypes = node._attrtypes.get(name)
1.39 + self._visitGuardForNameDeduced(node, name, attrtypes)
1.40
1.41 def _visitAttr(self, node):
1.42
1.43 @@ -481,8 +500,10 @@
1.44 elif isinstance(self.expr, TypedInstance):
1.45 expr = self.expr
1.46 else:
1.47 + self._visitGuard(node)
1.48 return
1.49 else:
1.50 + self._visitGuard(node)
1.51 return
1.52
1.53 attr = node._values and node._values.get(node.name) or None
1.54 @@ -498,6 +519,48 @@
1.55 if value and isinstance(value, Instance) and not isinstance(value, TypedInstance):
1.56 node._values[node.name] = expr
1.57
1.58 + self._visitGuard(node)
1.59 +
1.60 + def _visitGuard(self, node):
1.61 + node._guard_types = {}
1.62 + node._guards = {}
1.63 + self._visitGuardForName(node, node.name)
1.64 +
1.65 + def _visitGuardForName(self, node, name):
1.66 +
1.67 + "Make an annotation stating the acceptable types for a name."
1.68 +
1.69 + # Need to check any concrete value against deductions.
1.70 +
1.71 + attrtypes = node._attrtypes.get(name)
1.72 + value = node._values.get(name)
1.73 +
1.74 + # Where a concrete type conflicts with deductions, the usage of
1.75 + # attributes cannot be supported and is thus impossible.
1.76 +
1.77 + if value:
1.78 + if attrtypes and value not in attrtypes:
1.79 + node._guard_types[name] = "impossible"
1.80 + else:
1.81 + node._guard_types[name] = "single"
1.82 + node._guards[name] = set([value])
1.83 +
1.84 + # Where no concrete type is known, usage must be checked.
1.85 +
1.86 + elif attrtypes:
1.87 + self._visitGuardForNameDeduced(node, name, attrtypes)
1.88 +
1.89 + # Where no deductions are made, no guards are needed.
1.90 +
1.91 + def _visitGuardForNameDeduced(self, node, name, attrtypes):
1.92 + if not attrtypes:
1.93 + return
1.94 + if len(attrtypes) == 1:
1.95 + node._guard_types[name] = "single"
1.96 + else:
1.97 + node._guard_types[name] = "multiple"
1.98 + node._guards[name] = attrtypes
1.99 +
1.100 def visitCallFunc(self, node):
1.101
1.102 "Identify any concrete types involved with instantiation."
1.103 @@ -509,7 +572,7 @@
1.104
1.105 attr = node.node._attr
1.106
1.107 - if attr:
1.108 + if attr and not isinstance(attr, Instance):
1.109 value = attr.get_value()
1.110 if value and isinstance(value, Class):
1.111 return TypedInstance(value)