abstract class VariableContext
# Look for the variable from its name
# Return null if nothing found
- meth [](s: Symbol): Variable
+ meth [](s: Symbol): nullable Variable
do
if _dico.has_key(s) then
return _dico[s]
# The effective static type of a given variable
# May be different from the declaration static type
- meth stype(v: Variable): MMType
+ meth stype(v: Variable): nullable MMType
do
- return v.stype
+ if _stypes.has_key(v) then
+ return _stypes[v]
+ else
+ return v.stype
+ end
+ end
+
+ # Set effective static type of a given variable
+ # May be different from the declaration static type
+ meth stype=(v: Variable, t: nullable MMType)
+ do
+ _stypes[v] = t
end
# Variables by name (in the current context only)
# All variables in all contextes
attr _all_variables: Set[Variable]
+ # Updated static type of variables
+ attr _stypes: Map[Variable, nullable MMType] = new HashMap[Variable, nullable MMType]
+
# Build a new VariableContext
meth sub(node: PNode): SubVariableContext
do
# Build a nested VariableContext with new variable information
meth sub_with(node: PNode, v: Variable, t: MMType): SubVariableContext
do
- return new CastVariableContext.with_prev(self, node, v, t)
+ var ctx = sub(node)
+ ctx.stype(v) = t
+ return ctx
end
# The visitor of the context (used to display error)
if not is_set(v) and ctx.is_set(v) then
mark_is_set(v)
end
+ var s = stype(v)
+ var s1 = ctx.stype(v)
+ if s1 != s then stype(v) = s1
end
end
# Merge back two alternative flow context informations
- meth merge2(ctx1, ctx2: VariableContext)
+ meth merge2(ctx1, ctx2, basectx: VariableContext)
do
if ctx1.unreash then
merge(ctx2)
if not is_set(v) and ctx1.is_set(v) and ctx2.is_set(v) then
mark_is_set(v)
end
+
+ var s = stype(v)
+ var s1 = ctx1.stype(v)
+ var s2 = ctx2.stype(v)
+ if s1 == s and s2 == s then
+ # NOP
+ else if s1 == s2 then
+ stype(v) = s1
+ else if s2 == null or s1 < s2 then
+ stype(v) = s2
+ else if s1 == null or s2 < s1 then
+ stype(v) = s1
+ else
+ stype(v) = basectx.stype(v)
+ end
+ end
+ end
+
+ redef meth to_s
+ do
+ var s = new Buffer
+ s.append(node.locate)
+ for v in _all_variables do
+ var t = stype(v)
+ if t == null then continue
+ s.append(" {v}:{t}")
end
+ return s.to_s
end
end
redef meth stype(v)
do
- return prev.stype(v)
+ if _stypes.has_key(v) then
+ return _stypes[v]
+ else
+ return prev.stype(v)
+ end
end
init with_prev(p: VariableContext, node: PNode)
end
end
-class CastVariableContext
-special SubVariableContext
- attr _variable: Variable
- attr _var_type: MMType
-
- redef meth stype(v)
- do
- if _variable == v then
- return _var_type
- end
- return prev.stype(v)
- end
-
- init with_prev(p: VariableContext, node: PNode, v: Variable, t: MMType)
- do
- super(p, node)
- _variable = v
- _var_type =t
- end
-end
-
redef class Variable
# Is the variable must be set before being used ?
meth must_be_set: Bool do return false