typing: Add `do_typing` on AExpr
[nit.git] / src / semantize / typing.nit
index a85a1b0..7c530c1 100644 (file)
@@ -181,7 +181,6 @@ private class TypeVisitor
                return self.visit_expr_subtype(nexpr, self.type_bool(nexpr))
        end
 
-
        fun check_expr_cast(node: ANode, nexpr: AExpr, ntype: AType): nullable MType
        do
                var sub = nexpr.mtype
@@ -316,13 +315,22 @@ private class TypeVisitor
 
                var mproperty = self.try_get_mproperty_by_name2(node, unsafe_type, name)
                if name == "new" and mproperty == null then
-                       name = "init"
+                       name = "defaultinit"
                        mproperty = self.try_get_mproperty_by_name2(node, unsafe_type, name)
+                       if mproperty == null then
+                               name = "init"
+                               mproperty = self.try_get_mproperty_by_name2(node, unsafe_type, name)
+                       end
                end
 
                if mproperty == null then
                        if recv_is_self then
-                               self.modelbuilder.error(node, "Error: method or variable `{name}` unknown in `{recvtype}`.")
+                               # FIXME This test was added to display a more explicit error when a potential duplication of root object class.
+                               if name == "init" then
+                                       self.modelbuilder.error(node, "Possible duplication of the root class `Object`")
+                               else
+                                       self.modelbuilder.error(node, "Error: method or variable `{name}` unknown in `{recvtype}`.")
+                               end
                        else if recvtype.need_anchor then
                                self.modelbuilder.error(node, "Error: method `{name}` does not exists in `{recvtype}: {unsafe_type}`.")
                        else
@@ -396,7 +404,7 @@ private class TypeVisitor
        # The `build_callsite_by_propdef` builds the callsite directly with the `mprodef` passed in argument.
        fun build_callsite_by_propdef(node: ANode, recvtype: MType, mpropdef: MMethodDef, recv_is_self: Bool): nullable CallSite
        do
-               var msignature = mpropdef.new_msignature or else mpropdef.msignature
+               var msignature = mpropdef.msignature
                if msignature == null then return null # skip error
                msignature = resolve_for(msignature, recvtype, recv_is_self).as(MSignature)
 
@@ -424,7 +432,6 @@ private class TypeVisitor
                return build_callsite_by_name(node, recvtype, name, recv_is_self)
        end
 
-
        # 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
@@ -445,7 +452,6 @@ private class TypeVisitor
                        # Other cases are managed later
                end
 
-
                #debug("CALL {unsafe_type}.{msignature}")
 
                # Associate each parameter to a position in the arguments
@@ -1026,6 +1032,18 @@ redef class AExpr
                end
                return res
        end
+
+       # Type the expression as if located in `visited_mpropdef`
+       # `TypeVisitor` and `PostTypingVisitor` will be used to do the typing, see them for more information.
+       #
+       # `visited_mpropdef`: Correspond to the evaluation context in which the expression is located.
+       fun do_typing(modelbuilder: ModelBuilder, visited_mpropdef: MPropDef)
+       do
+               var type_visitor = new TypeVisitor(modelbuilder, visited_mpropdef)
+               type_visitor.visit_stmt(self)
+               var post_visitor = new PostTypingVisitor(type_visitor)
+               post_visitor.enter_visit(self)
+       end
 end
 
 redef class ABlockExpr
@@ -1177,7 +1195,6 @@ redef class AVarReassignExpr
        end
 end
 
-
 redef class AContinueExpr
        redef fun accept_typing(v)
        do
@@ -1503,7 +1520,6 @@ redef class AAndExpr
        end
 end
 
-
 redef class ANotExpr
        redef fun accept_typing(v)
        do
@@ -1779,7 +1795,7 @@ redef class ARangeExpr
                # get the constructor
                var callsite
                if self isa ACrangeExpr then
-                       callsite = v.build_callsite_by_name(self, mtype, "init", false)
+                       callsite = v.build_callsite_by_name(self, mtype, "defaultinit", false)
                else if self isa AOrangeExpr then
                        callsite = v.build_callsite_by_name(self, mtype, "without_last", false)
                else
@@ -1989,7 +2005,9 @@ redef class ASendExpr
 
                var args = compute_raw_arguments
 
-               callsite.check_signature(v, node, args)
+                if not self isa ACallrefExpr then
+                       callsite.check_signature(v, node, args)
+                end
 
                if callsite.mproperty.is_init then
                        var vmpropdef = v.mpropdef
@@ -2072,7 +2090,6 @@ redef class AUnaryopExpr
        redef fun compute_raw_arguments do return new Array[AExpr]
 end
 
-
 redef class ACallExpr
        redef fun property_name do return n_qid.n_id.text
        redef fun property_node do return n_qid
@@ -2160,7 +2177,7 @@ redef class ABraReassignExpr
 end
 
 redef class AInitExpr
-       redef fun property_name do return "init"
+       redef fun property_name do if n_args.n_exprs.is_empty then return "init" else return "defaultinit"
        redef fun property_node do return n_kwinit
        redef fun compute_raw_arguments do return n_args.to_a
 end
@@ -2173,13 +2190,66 @@ redef class ACallrefExpr
        redef fun accept_typing(v)
        do
                super # do the job as if it was a real call
-
-               # TODO: inspect self.callsite to get information about the method
                var res = callsite.mproperty
 
-               # TODO: return a functionnal type
-               self.mtype = null
-               v.error(self, "Error: NOT YET IMPLEMENTED callref expressions.")
+                var msignature = callsite.mpropdef.msignature
+                var recv = callsite.recv
+                assert msignature != null
+                var arity = msignature.mparameters.length
+
+                var routine_type_name = "ProcRef"
+                if msignature.return_mtype != null then
+                        routine_type_name = "FunRef"
+                end
+
+                var target_routine_class = "{routine_type_name}{arity}"
+                var routine_mclass = v.get_mclass(self, target_routine_class)
+
+                if routine_mclass == null then
+                        v.error(self, "Error: missing functional types, try `import functional`")
+                        return
+                end
+
+                var types_list = new Array[MType]
+                for param in msignature.mparameters do
+                        if param.is_vararg then
+                                types_list.push(v.mmodule.array_type(param.mtype))
+                        else
+                                types_list.push(param.mtype)
+                        end
+                end
+                if msignature.return_mtype != null then
+                        types_list.push(msignature.return_mtype.as(not null))
+                end
+
+                # Why we need an anchor :
+                #
+                # ~~~~nitish
+                # class A[E]
+                #       def toto(x: E) do print "{x}"
+                # end
+                #
+                # var a = new A[Int]
+                # var f = &a.toto # without anchor : ProcRef1[E]
+                #                # with anchor : ProcRef[Int]
+                # ~~~~
+               # However, we can only anchor if we can resolve every formal
+               # parameter, here's an example where we can't.
+               # ~~~~nitish
+               # class A[E]
+               #       fun bar: A[E] do return self
+               #       fun foo: Fun0[A[E]] do return &bar # here we can't anchor
+               # end
+               # var f1 = a1.foo # when this expression will be evaluated,
+               #                 # `a1` will anchor `&bar` returned by `foo`.
+               # print f1.call
+               # ~~~~
+               var routine_type = routine_mclass.get_mtype(types_list)
+               if not recv.need_anchor then
+                       routine_type = routine_type.anchor_to(v.mmodule, recv.as(MClassType))
+               end
+                is_typed = true
+               self.mtype = routine_type
        end
 end
 
@@ -2276,7 +2346,7 @@ redef class ASuperExpr
                        return
                end
 
-               var msignature = superprop.new_msignature or else superprop.msignature.as(not null)
+               var msignature = superprop.msignature.as(not null)
                msignature = v.resolve_for(msignature, recvtype, true).as(MSignature)
 
                var callsite = new CallSite(hot_location, recvtype, v.mmodule, v.anchor, true, superprop.mproperty, superprop, msignature, false)
@@ -2467,7 +2537,6 @@ redef class AAttrExpr
        end
 end
 
-
 redef class AAttrAssignExpr
        redef fun accept_typing(v)
        do