nitg-sep: autobox self before call on self->type
[nit.git] / src / typing.nit
index e73cb9e..7a699d2 100644 (file)
@@ -68,9 +68,14 @@ private class TypeVisitor
                return res
        end
 
-       fun resolve_signature_for(msignature: MSignature, recv: MType, for_self: Bool): MSignature
+       # Retrieve the signature of a MMethodDef resolved for a specific call.
+       # This method is an helper to symplify the query on the model.
+       #
+       # Note: `for_self` indicates if the reciever is self or not.
+       # If yes, virtual types are not resolved.
+       fun resolve_signature_for(mmethoddef: MMethodDef, recv: MType, for_self: Bool): MSignature
        do
-               return self.resolve_for(msignature, recv, for_self).as(MSignature)
+               return self.resolve_for(mmethoddef.msignature.as(not null), recv, for_self).as(MSignature)
        end
 
        fun check_subtype(node: ANode, sub, sup: MType): Bool
@@ -171,6 +176,13 @@ private class TypeVisitor
                return self.modelbuilder.resolve_mtype(self.nclassdef, node)
        end
 
+       fun try_get_mclass(node: ANode, name: String): nullable MClass
+       do
+               var mmodule = self.nclassdef.mclassdef.mmodule
+               var mclass = modelbuilder.try_get_mclass_by_name(node, mmodule, name)
+               return mclass
+       end
+
        fun get_mclass(node: ANode, name: String): nullable MClass
        do
                var mmodule = self.nclassdef.mclassdef.mmodule
@@ -205,6 +217,11 @@ private class TypeVisitor
                        return null
                end
 
+               if mproperty.visibility == protected_visibility and not recv_is_self and self.mmodule.visibility_for(mproperty.intro_mclassdef.mmodule) < intrude_visibility then
+                       self.modelbuilder.error(node, "Error: Method '{name}' is protected and can only acceded by self. {mproperty.intro_mclassdef.mmodule.visibility_for(self.mmodule)}")
+                       return null
+               end
+
                var propdefs = mproperty.lookup_definitions(self.mmodule, unsafe_type)
                if propdefs.length == 0 then
                        self.modelbuilder.error(node, "Type error: no definition found for property {name} in {unsafe_type}")
@@ -245,12 +262,12 @@ private class TypeVisitor
                        if i > vararg_rank then
                                j = i + vararg_decl
                        end
-                       var paramtype = msignature.parameter_mtypes[i]
+                       var paramtype = msignature.mparameters[i].mtype
                        self.visit_expr_subtype(args[j], paramtype)
                end
                if vararg_rank >= 0 then
                        var varargs = new Array[AExpr]
-                       var paramtype = msignature.parameter_mtypes[vararg_rank]
+                       var paramtype = msignature.mparameters[vararg_rank].mtype
                        for j in [vararg_rank..vararg_rank+vararg_decl] do
                                varargs.add(args[j])
                                self.visit_expr_subtype(args[j], paramtype)
@@ -377,6 +394,9 @@ redef class APropdef
        fun do_typing(modelbuilder: ModelBuilder)
        do
        end
+
+       # The variable associated to the reciever (if any)
+       var selfvariable: nullable Variable
 end
 
 redef class AConcreteMethPropdef
@@ -385,13 +405,14 @@ redef class AConcreteMethPropdef
                var nclassdef = self.parent.as(AClassdef)
                var mpropdef = self.mpropdef.as(not null)
                var v = new TypeVisitor(modelbuilder, nclassdef, mpropdef)
+               self.selfvariable = v.selfvariable
 
                var nblock = self.n_block
                if nblock == null then return
 
                var mmethoddef = self.mpropdef.as(not null)
                for i in [0..mmethoddef.msignature.arity[ do
-                       var mtype = mmethoddef.msignature.parameter_mtypes[i]
+                       var mtype = mmethoddef.msignature.mparameters[i].mtype
                        if mmethoddef.msignature.vararg_rank == i then
                                var arrayclass = v.get_mclass(self.n_signature.n_params[i], "Array")
                                if arrayclass == null then return # Skip error
@@ -401,6 +422,12 @@ redef class AConcreteMethPropdef
                        assert variable != null
                        variable.declared_type = mtype
                end
+               for i in [0..mmethoddef.msignature.mclosures.length[ do
+                       var mclosure = mmethoddef.msignature.mclosures[i]
+                       var variable = self.n_signature.n_closure_decls[i].variable
+                       assert variable != null
+                       variable.declared_type = mclosure.mtype
+               end
                v.visit_stmt(nblock)
 
                if not nblock.after_flow_context.is_unreachable and mmethoddef.msignature.return_mtype != null then
@@ -415,6 +442,7 @@ redef class AAttrPropdef
        do
                var nclassdef = self.parent.as(AClassdef)
                var v = new TypeVisitor(modelbuilder, nclassdef, self.mpropdef.as(not null))
+               self.selfvariable = v.selfvariable
 
                var nexpr = self.n_expr
                if nexpr != null then
@@ -479,7 +507,7 @@ redef class AVardeclExpr
                end
 
                if mtype == null then
-                       mtype = v.get_mclass(self, "Object").mclass_type
+                       mtype = v.get_mclass(self, "Object").mclass_type.as_nullable
                end
 
                variable.declared_type = mtype
@@ -557,14 +585,12 @@ redef class AReassignFormExpr
 
                self.reassign_property = mpropdef
 
-               var msignature = mpropdef.msignature
-               assert msignature!= null
-               msignature = v.resolve_signature_for(msignature, readtype, false)
+               var msignature = v.resolve_signature_for(mpropdef, readtype, false)
 
                var rettype = msignature.return_mtype
                assert msignature.arity == 1 and rettype != null
 
-               var value_type = v.visit_expr_subtype(self.n_value, msignature.parameter_mtypes.first)
+               var value_type = v.visit_expr_subtype(self.n_value, msignature.mparameters.first.mtype)
                if value_type == null then return null # Skip error
 
                v.check_subtype(self, rettype, writetype)
@@ -699,28 +725,109 @@ redef class ALoopExpr
 end
 
 redef class AForExpr
-       redef fun accept_typing(v)
-       do
-               var mtype = v.visit_expr(n_expr)
-               if mtype == null then return
+       var coltype: nullable MClassType
+
+       var method_iterator: nullable MMethod
+       var method_is_ok: nullable MMethod
+       var method_item: nullable MMethod
+       var method_next: nullable MMethod
+       var method_key: nullable MMethod
 
-               var colcla = v.get_mclass(self, "Collection")
-               if colcla == null then return
+       private fun do_type_iterator(v: TypeVisitor, mtype: MType)
+       do
                var objcla = v.get_mclass(self, "Object")
                if objcla == null then return
-               if v.is_subtype(mtype, colcla.get_mtype([objcla.mclass_type.as_nullable])) then
+
+               var is_col = false
+               var is_map = false
+
+               var colcla = v.try_get_mclass(self, "Collection")
+               if colcla != null and v.is_subtype(mtype, colcla.get_mtype([objcla.mclass_type.as_nullable])) then
                        var coltype = mtype.supertype_to(v.mmodule, v.anchor, colcla)
-                       assert coltype isa MGenericType
+                       self.coltype = coltype
                        var variables =  self.variables
                        if variables.length != 1 then
                                v.error(self, "Type Error: Expected one variable")
                        else
                                variables.first.declared_type = coltype.arguments.first
                        end
-               else
-                       v.modelbuilder.error(self, "TODO: Do 'for' on {mtype}")
+                       is_col = true
+               end
+
+               var mapcla = v.try_get_mclass(self, "Map")
+               if mapcla != null and v.is_subtype(mtype, mapcla.get_mtype([objcla.mclass_type.as_nullable, objcla.mclass_type.as_nullable])) then
+                       var coltype = mtype.supertype_to(v.mmodule, v.anchor, mapcla)
+                       self.coltype = coltype
+                       var variables = self.variables
+                       if variables.length != 2 then
+                               v.error(self, "Type Error: Expected two variables")
+                       else
+                               variables[0].declared_type = coltype.arguments[0]
+                               variables[1].declared_type = coltype.arguments[1]
+                       end
+                       is_map = true
+               end
+
+               if is_col or is_map then
+                       # get iterator method
+                       var coltype = self.coltype.as(not null)
+                       var itdef = v.get_method(self, coltype, "iterator", true)
+                       if itdef == null then
+                               v.error(self, "Type Error: Expected method 'iterator' in type {coltype}")
+                               return
+                       end
+                       self.method_iterator = itdef.mproperty
+
+                       # get iterator type
+                       var ittype = v.resolve_signature_for(itdef, mtype, false).return_mtype
+                       if ittype == null then
+                               v.error(self, "Type Error: Expected method 'iterator' to return an Iterator type")
+                               return
+                       end
+
+                       # get methods is_ok, next, item
+                       var ikdef = v.get_method(self, ittype, "is_ok", false)
+                       if ikdef == null then
+                               v.error(self, "Type Error: Expected method 'is_ok' in Iterator type {ittype}")
+                               return
+                       end
+                       self.method_is_ok = ikdef.mproperty
+
+                       var itemdef = v.get_method(self, ittype, "item", false)
+                       if itemdef == null then
+                               v.error(self, "Type Error: Expected method 'item' in Iterator type {ittype}")
+                               return
+                       end
+                       self.method_item = itemdef.mproperty
+
+                       var nextdef = v.get_method(self, ittype, "next", false)
+                       if nextdef == null then
+                               v.error(self, "Type Error: Expected method 'next' in Iterator type {ittype}")
+                               return
+                       end
+                       self.method_next = nextdef.mproperty
+
+                       if is_map then
+                               var keydef = v.get_method(self, ittype, "key", false)
+                               if keydef == null then
+                                       v.error(self, "Type Error: Expected method 'key' in Iterator type {ittype}")
+                                       return
+                               end
+                               self.method_key = keydef.mproperty
+                       end
+                       return
                end
 
+               v.modelbuilder.error(self, "NOT YET IMPLEMENTED: Do 'for' on {mtype}")
+       end
+
+       redef fun accept_typing(v)
+       do
+               var mtype = v.visit_expr(n_expr)
+               if mtype == null then return
+
+               self.do_type_iterator(v, mtype)
+
                v.visit_stmt(n_block)
                self.is_typed = true
        end
@@ -881,8 +988,11 @@ end
 redef class ARangeExpr
        redef fun accept_typing(v)
        do
-               var t1 = v.visit_expr(self.n_expr)
-               var t2 = v.visit_expr(self.n_expr2)
+               var discrete_class = v.get_mclass(self, "Discrete")
+               if discrete_class == null then return # Forward error
+               var discrete_type = discrete_class.intro.bound_mtype
+               var t1 = v.visit_expr_subtype(self.n_expr, discrete_type)
+               var t2 = v.visit_expr_subtype(self.n_expr2, discrete_type)
                if t1 == null or t2 == null then return
                var mclass = v.get_mclass(self, "Range")
                if mclass == null then return # Forward error
@@ -983,17 +1093,14 @@ redef class ASendExpr
                        return
                end
 
-               var propdef = v.get_method(self, recvtype, name, self.n_expr isa ASelfExpr)
-               if propdef == null then return
-               var mproperty = propdef.mproperty
+               var mpropdef = v.get_method(self, recvtype, name, self.n_expr isa ASelfExpr)
+               if mpropdef == null then return
+               var mproperty = mpropdef.mproperty
                self.mproperty = mproperty
-               var msignature = propdef.msignature
-               if msignature == null then abort # Forward error
-
-               var for_self = self.n_expr isa ASelfExpr
-               msignature = v.resolve_signature_for(msignature, recvtype, for_self)
+               var msignature = v.resolve_signature_for(mpropdef, recvtype, self.n_expr isa ASelfExpr)
 
                var args = compute_raw_arguments
+               self.raw_arguments = args
 
                v.check_signature(self, args, name, msignature)
 
@@ -1010,6 +1117,14 @@ redef class ASendExpr
                else
                        self.is_typed = true
                end
+
+               if self.n_closure_defs.length == msignature.mclosures.length then
+                       for i in [0..self.n_closure_defs.length[ do
+                               self.n_closure_defs[i].accept_typing(v, msignature.mclosures[i])
+                       end
+               else
+                       debug("closure: got {self.n_closure_defs.length}, want {msignature.mclosures.length}")
+               end
        end
 
        # The name of the property
@@ -1017,7 +1132,9 @@ redef class ASendExpr
        private fun property_name: String is abstract
 
        # An array of all arguments (excluding self)
-       fun compute_raw_arguments: Array[AExpr] is abstract
+       var raw_arguments: nullable Array[AExpr]
+
+       private fun compute_raw_arguments: Array[AExpr] is abstract
 end
 
 redef class ABinopExpr
@@ -1145,16 +1262,16 @@ redef class ASendReassignFormExpr
                        return
                end
 
-               var propdef = v.get_method(self, recvtype, name, self.n_expr isa ASelfExpr)
-               if propdef == null then return
-               var mproperty = propdef.mproperty
-               self.mproperty = mproperty
-               var msignature = propdef.msignature
-               if msignature == null then abort # Forward error
                var for_self = self.n_expr isa ASelfExpr
-               msignature = v.resolve_signature_for(msignature, recvtype, for_self)
+               var mpropdef = v.get_method(self, recvtype, name, for_self)
+
+               if mpropdef == null then return
+               var mproperty = mpropdef.mproperty
+               self.mproperty = mproperty
+               var msignature = v.resolve_signature_for(mpropdef, recvtype, for_self)
 
                var args = compute_raw_arguments
+               self.raw_arguments = args
 
                v.check_signature(self, args, name, msignature)
 
@@ -1168,13 +1285,12 @@ redef class ASendReassignFormExpr
                if wpropdef == null then return
                var wmproperty = wpropdef.mproperty
                self.write_mproperty = wmproperty
-               var wmsignature = wpropdef.msignature
-               if wmsignature == null then abort # Forward error
-               wmsignature = v.resolve_signature_for(wmsignature, recvtype, for_self)
+               var wmsignature = v.resolve_signature_for(wpropdef, recvtype, for_self)
 
-               var wtype = self.resolve_reassignment(v, readtype, wmsignature.parameter_mtypes.last)
+               var wtype = self.resolve_reassignment(v, readtype, wmsignature.mparameters.last.mtype)
                if wtype == null then return
 
+               args = args.to_a # duplicate so raw_arguments keeps only the getter args
                args.add(self.n_value)
                v.check_signature(self, args, name + "=", wmsignature)
 
@@ -1225,14 +1341,13 @@ redef class ASuperExpr
                        v.error(self, "Error: No super method to call for {mproperty}.")
                        return
                else if superprops.length > 1 then
-                       v.modelbuilder.warning(self, "Error: Conflicting super method to call for {mproperty}: {superprops.join(", ")}.")
+                       v.modelbuilder.warning(self, "Warning: NOT YET IMPLEMENTED: Conflicting super method to call for {mproperty}: {superprops.join(", ")}.")
                        return
                end
                var superprop = superprops.first
                assert superprop isa MMethodDef
 
-               var msignature = superprop.msignature.as(not null)
-               msignature = v.resolve_signature_for(msignature, recvtype, true)
+               var msignature = v.resolve_signature_for(superprop, recvtype, true)
                var args = self.n_args.to_a
                if args.length > 0 then
                        v.check_signature(self, args, mproperty.name, msignature)
@@ -1275,8 +1390,7 @@ redef class ASuperExpr
                self.mproperty = superprop.mproperty
 
                var args = self.n_args.to_a
-               var msignature = superprop.msignature.as(not null)
-               msignature = v.resolve_signature_for(msignature, recvtype, true)
+               var msignature = v.resolve_signature_for(superprop, recvtype, true)
                if args.length > 0 then
                        v.check_signature(self, args, mproperty.name, msignature)
                else
@@ -1326,8 +1440,7 @@ redef class ANewExpr
                        return
                end
 
-               var msignature = propdef.msignature.as(not null)
-               msignature = v.resolve_signature_for(msignature, recvtype, false)
+               var msignature = v.resolve_signature_for(propdef, recvtype, false)
 
                var args = n_args.to_a
                v.check_signature(self, args, name, msignature)
@@ -1426,7 +1539,42 @@ end
 redef class AClosureCallExpr
        redef fun accept_typing(v)
        do
-               #TODO
+               var variable = self.variable
+               if variable == null then return # Skip error
+
+               var recvtype = v.nclassdef.mclassdef.bound_mtype
+               var msignature = variable.declared_type.as(not null)
+               msignature = v.resolve_for(msignature, recvtype, false).as(MSignature)
+
+               var args = n_args.to_a
+               v.check_signature(self, args, variable.name, msignature)
+
+               self.is_typed = true
+               self.mtype = msignature.return_mtype
+       end
+end
+
+redef class AClosureDef
+       var mclosure: nullable MParameter
+
+       private fun accept_typing(v: TypeVisitor, mparameter: MParameter)
+       do
+               var variables = self.variables
+               if variables == null then return
+
+               self.mclosure = mparameter
+               var msignature = mparameter.mtype.as(MSignature)
+
+               if msignature.arity != variables.length then
+                       v.error(self, "Type error: closure {mparameter.name} expects {msignature.arity} parameters, {variables.length} given")
+                       return
+               end
+
+               for i in [0..variables.length[ do
+                       variables[i].declared_type = msignature.mparameters[i].mtype
+               end
+
+               v.visit_stmt(self.n_expr)
        end
 end