typing: introduce SignatureMap to factorize parameters<->arguments mapping work
[nit.git] / src / semantize / typing.nit
index e7a5a09..8fe169d 100644 (file)
@@ -398,47 +398,58 @@ private class TypeVisitor
        # Visit the expressions of args and check their conformity with the corresponding type in signature
        # The point of this method is to handle varargs correctly
        # Note: The signature must be correctly adapted
-       fun check_signature(node: ANode, args: Array[AExpr], mproperty: MProperty, msignature: MSignature): Bool
+       fun check_signature(node: ANode, args: Array[AExpr], mproperty: MProperty, msignature: MSignature): nullable SignatureMap
        do
                var vararg_rank = msignature.vararg_rank
                if vararg_rank >= 0 then
                        if args.length < msignature.arity then
                                modelbuilder.error(node, "Error: expected at least {msignature.arity} argument(s) for `{mproperty}{msignature}`; got {args.length}. See introduction at `{mproperty.full_name}`.")
-                               return false
+                               return null
                        end
                else if args.length != msignature.arity then
                        modelbuilder.error(node, "Error: expected {msignature.arity} argument(s) for `{mproperty}{msignature}`; got {args.length}. See introduction at `{mproperty.full_name}`.")
-                       return false
+                       return null
                end
 
                #debug("CALL {unsafe_type}.{msignature}")
 
+               # Associate each parameter to a position in the arguments
+               var map = new SignatureMap
+
                var vararg_decl = args.length - msignature.arity
+               var j = 0
                for i in [0..msignature.arity[ do
-                       var j = i
-                       if i == vararg_rank then continue # skip the vararg
-                       if i > vararg_rank then
-                               j = i + vararg_decl
+                       var param = msignature.mparameters[i]
+                       var arg = args[j]
+                       map.map[i] = j
+                       j += 1
+
+                       if i == vararg_rank then
+                               j += vararg_decl
+                               continue # skip the vararg
                        end
-                       var paramtype = msignature.mparameters[i].mtype
-                       self.visit_expr_subtype(args[j], paramtype)
+
+                       var paramtype = param.mtype
+                       self.visit_expr_subtype(arg, paramtype)
                end
                if vararg_rank >= 0 then
                        var paramtype = msignature.mparameters[vararg_rank].mtype
                        var first = args[vararg_rank]
                        if vararg_decl == 0 and first isa AVarargExpr then
                                var mclass = get_mclass(node, "Array")
-                               if mclass == null then return false # Forward error
+                               if mclass == null then return null # Forward error
                                var array_mtype = mclass.get_mtype([paramtype])
                                self.visit_expr_subtype(first.n_expr, array_mtype)
                                first.mtype  = first.n_expr.mtype
                        else
-                               for j in [vararg_rank..vararg_rank+vararg_decl] do
-                                       self.visit_expr_subtype(args[j], paramtype)
+                               map.vararg_decl = vararg_decl + 1
+                               for i in [vararg_rank..vararg_rank+vararg_decl] do
+                                       self.visit_expr_subtype(args[i], paramtype)
                                end
                        end
                end
-               return true
+
+               return map
        end
 
        fun error(node: ANode, message: String)
@@ -508,6 +519,20 @@ private class TypeVisitor
        end
 end
 
+# Mapping between parameters and arguments in a call.
+#
+# Parameters and arguments are not stored in the class but referenced by their position (starting from 0)
+#
+# The point of this class is to help engine and other things to map arguments in the AST to parameters of the model.
+class SignatureMap
+       # Associate a parameter to an argument
+       var map = new ArrayMap[Int, Int]
+
+       # The length of the vararg sequence
+       # 0 if no vararg or if reverse vararg (cf `AVarargExpr`)
+       var vararg_decl: Int = 0
+end
+
 # A specific method call site with its associated informations.
 class CallSite
        # The associated node for location
@@ -540,9 +565,15 @@ class CallSite
        # Is a implicit cast required on erasure typing policy?
        var erasure_cast: Bool
 
+       # The mapping used on the call to associate arguments to parameters
+       # If null then no specific association is required.
+       var signaturemap: nullable SignatureMap = null
+
        private fun check_signature(v: TypeVisitor, args: Array[AExpr]): Bool
        do
-               return v.check_signature(self.node, args, self.mproperty, self.msignature)
+               var map = v.check_signature(self.node, args, self.mproperty, self.msignature)
+               signaturemap = map
+               return map == null
        end
 end
 
@@ -822,14 +853,7 @@ redef class AReassignFormExpr
        # Return the static type of the value to store.
        private fun resolve_reassignment(v: TypeVisitor, readtype, writetype: MType): nullable MType
        do
-               var reassign_name: String
-               if self.n_assign_op isa APlusAssignOp then
-                       reassign_name = "+"
-               else if self.n_assign_op isa AMinusAssignOp then
-                       reassign_name = "-"
-               else
-                       abort
-               end
+               var reassign_name = self.n_assign_op.operator
 
                self.read_type = readtype
 
@@ -1581,9 +1605,10 @@ end
 
 redef class ABinopExpr
        redef fun compute_raw_arguments do return [n_expr2]
+       redef fun property_name do return operator
+       redef fun property_node do return n_op
 end
 redef class AEqExpr
-       redef fun property_name do return "=="
        redef fun accept_typing(v)
        do
                super
@@ -1591,51 +1616,16 @@ redef class AEqExpr
        end
 end
 redef class ANeExpr
-       redef fun property_name do return "!="
        redef fun accept_typing(v)
        do
                super
                v.null_test(self)
        end
 end
-redef class ALtExpr
-       redef fun property_name do return "<"
-end
-redef class ALeExpr
-       redef fun property_name do return "<="
-end
-redef class ALlExpr
-       redef fun property_name do return "<<"
-end
-redef class AGtExpr
-       redef fun property_name do return ">"
-end
-redef class AGeExpr
-       redef fun property_name do return ">="
-end
-redef class AGgExpr
-       redef fun property_name do return ">>"
-end
-redef class APlusExpr
-       redef fun property_name do return "+"
-end
-redef class AMinusExpr
-       redef fun property_name do return "-"
-end
-redef class AStarshipExpr
-       redef fun property_name do return "<=>"
-end
-redef class AStarExpr
-       redef fun property_name do return "*"
-end
-redef class AStarstarExpr
-       redef fun property_name do return "**"
-end
-redef class ASlashExpr
-       redef fun property_name do return "/"
-end
-redef class APercentExpr
-       redef fun property_name do return "%"
+
+redef class AUplusExpr
+       redef fun property_name do return "unary +"
+       redef fun compute_raw_arguments do return new Array[AExpr]
 end
 
 redef class AUminusExpr
@@ -1778,7 +1768,7 @@ redef class ASuperExpr
                msignature = v.resolve_for(msignature, recvtype, true).as(MSignature)
                var args = self.n_args.to_a
                if args.length > 0 then
-                       v.check_signature(self, args, mproperty, msignature)
+                       signaturemap = v.check_signature(self, args, mproperty, msignature)
                end
                self.mtype = msignature.return_mtype
                self.is_typed = true
@@ -1786,6 +1776,10 @@ redef class ASuperExpr
                mpropdef = v.mpropdef.as(MMethodDef)
        end
 
+       # The mapping used on the call to associate arguments to parameters.
+       # If null then no specific association is required.
+       var signaturemap: nullable SignatureMap
+
        private fun process_superinit(v: TypeVisitor)
        do
                var anchor = v.anchor