# Is `self` use restricted?
# * no explicit `self`
# * method called on the implicit self must be top-level
+ # Currently only used for `new` factory since there is no valid receiver inside
var is_toplevel_context = false
init
selfvariable.declared_type = mclass.mclass_type
var mprop = mpropdef.mproperty
- if mprop isa MMethod and (mprop.is_toplevel or mprop.is_new) then
+ if mprop isa MMethod and mprop.is_new then
is_toplevel_context = true
end
end
#node.debug("*** START Collected for {variable}")
var mtypes = flow.collect_types(variable)
#node.debug("**** END Collected for {variable}")
- if mtypes == null or mtypes.length == 0 then
+ if mtypes.length == 0 then
return variable.declared_type
else if mtypes.length == 1 then
return mtypes.first
redef class FlowContext
# Store changes of types because of type evolution
private var vars = new HashMap[Variable, nullable MType]
- private var cache = new HashMap[Variable, nullable Array[nullable MType]]
# Adapt the variable to a static type
# Warning1: do not modify vars directly.
private fun set_var(variable: Variable, mtype: nullable MType)
do
self.vars[variable] = mtype
- self.cache.keys.remove(variable)
end
- private fun collect_types(variable: Variable): nullable Array[nullable MType]
+ # Look in the flow and previous flow and collect all first reachable type adaptation of a local variable
+ private fun collect_types(variable: Variable): Array[nullable MType]
do
- if cache.has_key(variable) then
- return cache[variable]
- end
- var res: nullable Array[nullable MType] = null
- if vars.has_key(variable) then
- var mtype = vars[variable]
- res = [mtype]
- else if self.previous.is_empty then
- # Root flow
- res = [variable.declared_type]
- else
- for flow in self.previous do
- if flow.is_unreachable then continue
- var r2 = flow.collect_types(variable)
- if r2 == null then continue
- if res == null then
- res = r2.to_a
- else
- for t in r2 do
- if not res.has(t) then res.add(t)
- end
+ #node.debug "flow for {variable}"
+ var res = new Array[nullable MType]
+
+ var todo = [self]
+ var seen = new HashSet[FlowContext]
+ while not todo.is_empty do
+ var f = todo.pop
+ if f.is_unreachable then continue
+ if seen.has(f) then continue
+ seen.add f
+
+ if f.vars.has_key(variable) then
+ # Found something. Collect it and do not process further on this path
+ res.add f.vars[variable]
+ #f.node.debug "process {variable}: got {f.vars[variable] or else "X"}"
+ else
+ todo.add_all f.previous
+ todo.add_all f.loops
+ if f.previous.is_empty then
+ # Root flowcontext mean a parameter or something related
+ res.add variable.declared_type
+ #f.node.debug "root process {variable}: got {variable.declared_type or else "X"}"
end
end
end
- cache[variable] = res
+ #self.node.debug "##### end flow for {variable}: {res.join(" ")}"
return res
end
end
#debug("var {variable}: {mtype}")
+ self.mtype = mtype
self.is_typed = true
end
end
end
end
+redef class AWithExpr
+ var method_start: nullable CallSite
+ var method_finish: nullable CallSite
+
+ redef fun accept_typing(v: TypeVisitor)
+ do
+ var mtype = v.visit_expr(n_expr)
+ if mtype == null then return
+
+ method_start = v.get_method(self, mtype, "start", n_expr isa ASelfExpr)
+ method_finish = v.get_method(self, mtype, "finish", n_expr isa ASelfExpr)
+
+ v.visit_stmt(n_block)
+ self.mtype = n_block.mtype
+ self.is_typed = true
+ end
+end
+
redef class AAssertExpr
redef fun accept_typing(v)
do