callsite: add `mmodule` and `anchor` to the callsite objects
[nit.git] / src / typing.nit
index 719fae2..f888b6f 100644 (file)
@@ -27,11 +27,6 @@ redef class ToolContext
        var typing_phase: Phase = new TypingPhase(self, [flow_phase, modelize_property_phase, local_var_init_phase])
 end
 
-redef class MPropDef
-       # Does the MPropDef contains a call to super or a call of a super-constructor?
-       var has_supercall: Bool = false
-end
-
 private class TypingPhase
        super Phase
        redef fun process_npropdef(npropdef) do npropdef.do_typing(toolcontext.modelbuilder)
@@ -279,7 +274,7 @@ private class TypeVisitor
                        end
                end
 
-               var callsite = new CallSite(node, recvtype, recv_is_self, mproperty, mpropdef, msignature, erasure_cast)
+               var callsite = new CallSite(node, recvtype, mmodule, anchor, recv_is_self, mproperty, mpropdef, msignature, erasure_cast)
                return callsite
        end
 
@@ -391,9 +386,15 @@ class CallSite
        # The assiciated node for location
        var node: ANode
 
-       # The statis type of the receiver
+       # The static type of the receiver (possibly unresolved)
        var recv: MType
 
+       # The module where the callsite is present
+       var mmodule: MModule
+
+       # The anchor to use with `recv` or `msignature`
+       var anchor: nullable MClassType
+
        # Is the receiver self?
        # If "for_self", virtual types of the signature are keeped
        # If "not_for_self", virtual type are erased
@@ -529,7 +530,7 @@ end
 
 redef class AExpr
        # The static type of the expression.
-       # null if self is a statement of in case of error
+       # null if self is a statement or in case of error
        var mtype: nullable MType = null
 
        # Is the statement correctly typed?
@@ -823,6 +824,11 @@ redef class AForExpr
 
        private fun do_type_iterator(v: TypeVisitor, mtype: MType)
        do
+               if mtype isa MNullType then
+                       v.error(self, "Type error: 'for' cannot iterate over 'null'")
+                       return
+               end
+
                # get obj class
                var objcla = v.get_mclass(self, "Object")
                if objcla == null then return
@@ -831,7 +837,7 @@ redef class AForExpr
                var unsafe_type = v.anchor_to(mtype)
                if v.try_get_mproperty_by_name2(self, unsafe_type, "iterator") == null then
                        if v.try_get_mproperty_by_name2(self, unsafe_type, "iterate") == null then
-                               v.error(self, "Type Error: Expected method 'iterator' in type {mtype}")
+                               v.error(self, "Type Error: 'for' expects a type providing 'iterator' method, got '{mtype}'.")
                        else
                                v.modelbuilder.error(self, "NOT YET IMPLEMENTED: Do 'for' on {mtype}")
                        end
@@ -840,7 +846,7 @@ redef class AForExpr
 
                var itdef = v.get_method(self, mtype, "iterator", true)
                if itdef == null then
-                       v.error(self, "Type Error: Expected method 'iterator' in type {mtype}")
+                       v.error(self, "Type Error: 'for' expects a type providing 'iterator' method, got '{mtype}'.")
                        return
                end
                self.method_iterator = itdef.mproperty
@@ -848,7 +854,7 @@ redef class AForExpr
                # check that iterator return something
                var ittype = itdef.msignature.return_mtype
                if ittype == null then
-                       v.error(self, "Type Error: Expected method 'iterator' to return an Iterator or MapIterator type")
+                       v.error(self, "Type Error: 'for' expects method 'iterator' to return an 'Iterator' or 'MapIterator' type'.")
                        return
                end
 
@@ -863,7 +869,7 @@ redef class AForExpr
                        var coltype = ittype.supertype_to(v.mmodule, v.anchor, colit_cla)
                        var variables =  self.variables
                        if variables.length != 1 then
-                               v.error(self, "Type Error: Expected one variable")
+                               v.error(self, "Type Error: 'for' expects only one variable when using 'Iterator'.")
                        else
                                variables.first.declared_type = coltype.arguments.first
                        end
@@ -875,7 +881,7 @@ redef class AForExpr
                        var coltype = ittype.supertype_to(v.mmodule, v.anchor, mapit_cla)
                        var variables = self.variables
                        if variables.length != 2 then
-                               v.error(self, "Type Error: Expected two variables")
+                               v.error(self, "Type Error: 'for' expects two variables when using 'MapIterator'.")
                        else
                                variables[0].declared_type = coltype.arguments[0]
                                variables[1].declared_type = coltype.arguments[1]
@@ -884,33 +890,34 @@ redef class AForExpr
                end
 
                if not is_col and not is_map then
-                       v.error(self, "Type Error: Expected method 'iterator' to return an Iterator of MapIterator type")
+                       v.error(self, "Type Error: 'for' expects method 'iterator' to return an 'Iterator' or 'MapIterator' type'.")
                        return
                end
 
                # anchor formal and virtual types
                if mtype.need_anchor then mtype = v.anchor_to(mtype)
 
+               if mtype isa MNullableType then mtype = mtype.mtype
                self.coltype = mtype.as(MClassType)
 
                # 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}")
+                       v.error(self, "Type Error: 'for' expects a 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}")
+                       v.error(self, "Type Error: 'for' expects a 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}")
+                       v.error(self, "Type Error: 'for' expects a method 'next' in 'Iterator' type {ittype}.")
                        return
                end
                self.method_next = nextdef.mproperty
@@ -918,7 +925,7 @@ redef class AForExpr
                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}")
+                               v.error(self, "Type Error: 'for' expects a method 'key' in 'Iterator' type {ittype}.")
                                return
                        end
                        self.method_key = keydef.mproperty
@@ -1419,6 +1426,10 @@ redef class ASuperExpr
        # Note: if the super is a normal call-next-method, then this attribute is null
        var callsite: nullable CallSite
 
+       # The method to call is the super is a standard `call-next-method` super-call
+       # Note: if the super is a special super-init-call, then this attribute is null
+       var mpropdef: nullable MMethodDef
+
        redef fun accept_typing(v)
        do
                var recvtype = v.nclassdef.mclassdef.bound_mtype
@@ -1447,12 +1458,15 @@ redef class ASuperExpr
                self.mtype = msignature.return_mtype
                self.is_typed = true
                v.mpropdef.has_supercall = true
+               mpropdef = v.mpropdef.as(MMethodDef)
        end
 
        private fun process_superinit(v: TypeVisitor)
        do
                var recvtype = v.nclassdef.mclassdef.bound_mtype
-               var mproperty = v.mpropdef.mproperty
+               var mpropdef = v.mpropdef
+               assert mpropdef isa MMethodDef
+               var mproperty = mpropdef.mproperty
                var superprop: nullable MMethodDef = null
                for msupertype in v.nclassdef.mclassdef.supertypes do
                        msupertype = msupertype.anchor_to(v.mmodule, recvtype)
@@ -1483,14 +1497,28 @@ redef class ASuperExpr
                end
 
                var msignature = v.resolve_signature_for(superprop, recvtype, true)
-               var callsite = new CallSite(self, recvtype, true, superprop.mproperty, superprop, msignature, false)
+               var callsite = new CallSite(self, recvtype, v.mmodule, v.anchor, true, superprop.mproperty, superprop, msignature, false)
                self.callsite = callsite
 
                var args = self.n_args.to_a
                if args.length > 0 then
                        callsite.check_signature(v, args)
                else
-                       # TODO: Check signature
+                       # Check there is at least enough parameters
+                       if mpropdef.msignature.arity < msignature.arity then
+                               v.error(self, "Error: Not enough implicit arguments to pass. Got {mpropdef.msignature.arity}, expected at least {msignature.arity}. Signature is {msignature}")
+                               return
+                       end
+                       # Check that each needed parameter is conform
+                       var i = 0
+                       for sp in msignature.mparameters do
+                               var p = mpropdef.msignature.mparameters[i]
+                               if not v.is_subtype(p.mtype, sp.mtype) then
+                                       v.error(self, "Type error: expected argument #{i} of type {sp.mtype}, got implicit argument {p.name} of type {p.mtype}. Signature is {msignature}")
+                                       return
+                               end
+                               i += 1
+                       end
                end
 
                self.is_typed = true