Merge: Fix type adaptation when there is loops
[nit.git] / src / semantize / typing.nit
index 212f43e..a46f632 100644 (file)
@@ -239,12 +239,16 @@ private class TypeVisitor
 
                if not mtype2 isa MNullType then return
 
-               if mtype isa MNullType then return
-
                # Check of useless null
                if not check_can_be_null(anode.n_expr, mtype) then return
 
-               mtype = mtype.as_notnull
+               if mtype isa MNullType then
+                       # Because of type adaptation, we cannot just stop here
+                       # so return use `null` as a bottom type that will be merged easily (cf) `merge_types`
+                       mtype = null
+               else
+                       mtype = mtype.as_notnull
+               end
 
                # Check for type adaptation
                var variable = anode.n_expr.its_variable
@@ -444,6 +448,8 @@ private class TypeVisitor
 
        fun get_variable(node: AExpr, variable: Variable): nullable MType
        do
+               if not variable.is_adapted then return variable.declared_type
+
                var flow = node.after_flow_context
                if flow == null then
                        self.error(node, "No context!")
@@ -546,6 +552,10 @@ end
 redef class Variable
        # The declared type of the variable
        var declared_type: nullable MType
+
+       # Was the variable type-adapted?
+       # This is used to speedup type retrieval while it remains `false`
+       private var is_adapted = false
 end
 
 redef class FlowContext
@@ -557,9 +567,11 @@ redef class FlowContext
        # Warning2: sub-flow may have cached a unadapted variable
        private fun set_var(v: TypeVisitor, variable: Variable, mtype: nullable MType)
        do
+               if variable.declared_type == mtype and not variable.is_adapted then return
                if vars.has_key(variable) and vars[variable] == mtype then return
                self.vars[variable] = mtype
                v.dirty = true
+               variable.is_adapted = true
                #node.debug "set {variable} to {mtype or else "X"}"
        end
 
@@ -1334,6 +1346,8 @@ redef class AArrayExpr
                        end
                end
                if mtype == null then
+                       # Ensure monotony for type adaptation on loops
+                       if self.element_mtype != null then mtypes.add self.element_mtype
                        mtype = v.merge_types(self, mtypes)
                end
                if mtype == null or mtype isa MNullType then
@@ -1861,6 +1875,7 @@ redef class ANewExpr
                end
 
                self.recvtype = recvtype
+               var kind = recvtype.mclass.kind
 
                var name: String
                var nid = self.n_id
@@ -1869,11 +1884,24 @@ redef class ANewExpr
                else
                        name = "new"
                end
+               if name == "intern" then
+                       if kind != concrete_kind then
+                               v.error(self, "Type Error: Cannot instantiate {kind} {recvtype}.")
+                               return
+                       end
+                       if n_args.n_exprs.not_empty then
+                               v.error(n_args, "Type Error: the intern constructor expects no arguments.")
+                               return
+                       end
+                       # Our job is done
+                       self.mtype = recvtype
+                       return
+               end
+
                var callsite = v.get_method(self, recvtype, name, false)
                if callsite == null then return
 
                if not callsite.mproperty.is_new then
-                       var kind = recvtype.mclass.kind
                        if kind != concrete_kind then
                                v.error(self, "Type Error: Cannot instantiate {kind} {recvtype}.")
                                return