Callref expression support for Separate Compiler.
[nit.git] / src / compiler / abstract_compiler.nit
index b512cdd..669159f 100644 (file)
@@ -625,6 +625,20 @@ abstract class AbstractCompiler
        # The targeted specific platform
        var target_platform: Platform is noinit
 
        # The targeted specific platform
        var target_platform: Platform is noinit
 
+        # All methods who already has a callref_thunk generated for
+        var compiled_callref_thunk = new HashSet[MMethodDef]
+
+        var all_routine_types_name: Set[String] do
+                var res = new HashSet[String]
+                for name in ["Fun", "Proc", "FunRef", "ProcRef"] do
+                        # Currently there's 20 arity per func type
+                        for i in [0..20[ do
+                                res.add("{name}{i}")
+                        end
+                end
+                return res
+        end
+
        init
        do
                self.realmainmodule = mainmodule
        init
        do
                self.realmainmodule = mainmodule
@@ -1377,6 +1391,12 @@ abstract class AbstractCompilerVisitor
        # The method is unsafe and is just a direct wrapper for the specific implementation of native arrays
        fun native_array_set(native_array: RuntimeVariable, index: Int, value: RuntimeVariable) is abstract
 
        # The method is unsafe and is just a direct wrapper for the specific implementation of native arrays
        fun native_array_set(native_array: RuntimeVariable, index: Int, value: RuntimeVariable) is abstract
 
+        # Instantiate a new routine pointer
+        fun routine_ref_instance(routine_mclass_type: MClassType, recv: RuntimeVariable, mmethoddef: MMethodDef): RuntimeVariable is abstract
+
+        # Call the underlying referenced function
+        fun routine_ref_call(mmethoddef: MMethodDef, args: Array[RuntimeVariable]) is abstract
+
        # Allocate `size` bytes with the low_level `nit_alloc` C function
        #
        # This method can be redefined to inject statistic or tracing code.
        # Allocate `size` bytes with the low_level `nit_alloc` C function
        #
        # This method can be redefined to inject statistic or tracing code.
@@ -2524,6 +2544,19 @@ redef class MClassType
        end
 end
 
        end
 end
 
+redef class MSignature
+        fun change_all_mtype_for(mtype: MType): MSignature
+        do
+                var ps = new Array[MParameter]
+                for p in mparameters do
+                        ps.push(new MParameter(p.name, mtype, p.is_vararg))
+                end
+                var ret: nullable MType = null
+                if return_mtype != null then ret = mtype
+                return new MSignature(ps, ret)
+        end
+end
+
 redef class MPropDef
        type VISITOR: AbstractCompilerVisitor
 end
 redef class MPropDef
        type VISITOR: AbstractCompilerVisitor
 end
@@ -2689,10 +2722,15 @@ redef class AMethPropdef
                var pname = mpropdef.mproperty.name
                var cname = mpropdef.mclassdef.mclass.name
                var ret = mpropdef.msignature.return_mtype
                var pname = mpropdef.mproperty.name
                var cname = mpropdef.mclassdef.mclass.name
                var ret = mpropdef.msignature.return_mtype
-               if ret != null then
+                var compiler = v.compiler
+                # WARNING: we must not resolve the return type when it's a functional type.
+                # Otherwise, we get a compile error exactly here. This weird behavior doesn't affect
+                # the inner mecanics of callref since the return type is already solved by
+                # `routine_ref_call`
+                if ret != null and not compiler.all_routine_types_name.has(cname) then
                        ret = v.resolve_for(ret, arguments.first)
                end
                        ret = v.resolve_for(ret, arguments.first)
                end
-               if pname != "==" and pname != "!=" then
+               if pname != "==" and pname != "!=" and pname != "call" and not compiler.all_routine_types_name.has(cname) then
                        v.adapt_signature(mpropdef, arguments)
                        v.unbox_signature_extern(mpropdef, arguments)
                end
                        v.adapt_signature(mpropdef, arguments)
                        v.unbox_signature_extern(mpropdef, arguments)
                end
@@ -3455,6 +3493,9 @@ redef class AMethPropdef
                                v.ret(v.new_expr("~{arguments[0]}", ret.as(not null)))
                                return true
                        end
                                v.ret(v.new_expr("~{arguments[0]}", ret.as(not null)))
                                return true
                        end
+                else if compiler.all_routine_types_name.has(cname) then
+                        v.routine_ref_call(mpropdef, arguments)
+                        return true
                end
                if pname == "exit" then
                        v.add("exit((int){arguments[1]});")
                end
                if pname == "exit" then
                        v.add("exit((int){arguments[1]});")
@@ -4375,8 +4416,9 @@ end
 redef class ACallrefExpr
         redef fun expr(v)
         do
 redef class ACallrefExpr
         redef fun expr(v)
         do
-                v.add_abort("NOT YET IMPLEMENTED callref expressions.")
-                return null
+                var recv = v.expr(self.n_expr, null)
+                var res = v.routine_ref_instance(mtype.as(MClassType), recv, callsite.as(not null).mpropdef)
+                return res
         end
 end
 
         end
 end