Callref bugfix in interpreter and compilers + autosav
authorLouis-Vincent Boudreault <lv.boudreault95@gmail.com>
Sat, 12 Oct 2019 00:02:28 +0000 (20:02 -0400)
committerLouis-Vincent Boudreault <lv.boudreault95@gmail.com>
Sat, 12 Oct 2019 00:20:33 +0000 (20:20 -0400)
~~~~nitish
class A[E]
fun foo: A[E] do return self
fun bar: Fun0[A[E]] do return &foo # it didn't work before
end
~~~~

- Fixed a bug when `self` was a generic class with unsolved type. It was
impossible to return a callref, since the typing rule were not properly
executed.
- Added a test case in `test_callref.res`

Signed-off-by: Louis-Vincent Boudreault <lv.boudreault95@gmail.com>

src/compiler/global_compiler.nit
src/compiler/separate_compiler.nit
src/interpreter/naive_interpreter.nit
src/semantize/typing.nit
tests/sav/test_callref.res
tests/test_callref.nit

index 765e630..ac5a2a1 100644 (file)
@@ -476,8 +476,8 @@ class GlobalCompilerVisitor
                 thunk.polymorph_call_flag = not my_recv.is_exact
                 compiler.todo(method)
                 compiler.todo(thunk)
                 thunk.polymorph_call_flag = not my_recv.is_exact
                 compiler.todo(method)
                 compiler.todo(thunk)
-
-                var res = self.new_expr("NEW_{routine_mclass_type.c_name}({my_recv}, &{thunk.c_name})", routine_mclass_type)
+               var ret_type = self.anchor(routine_mclass_type).as(MClassType)
+                var res = self.new_expr("NEW_{ret_type.c_name}({my_recv}, &{thunk.c_name})", ret_type)
                 return res
         end
 
                 return res
         end
 
index 64edec5..4716dae 100644 (file)
@@ -2213,9 +2213,6 @@ class SeparateCompilerVisitor
 
                # The class of the concrete Routine must exist (e.g ProcRef0, FunRef0, etc.)
                self.require_declaration("class_{routine_mclass.c_name}")
 
                # The class of the concrete Routine must exist (e.g ProcRef0, FunRef0, etc.)
                self.require_declaration("class_{routine_mclass.c_name}")
-               self.require_declaration("type_{routine_type.c_name}")
-
-               compiler.undead_types.add(routine_type)
                self.require_declaration(mmethoddef.c_name)
 
                var thunk_function = mmethoddef.callref_thunk(my_recv_mclass_type)
                self.require_declaration(mmethoddef.c_name)
 
                var thunk_function = mmethoddef.callref_thunk(my_recv_mclass_type)
@@ -2235,10 +2232,19 @@ class SeparateCompilerVisitor
                        self.require_declaration(thunk_function.c_name)
                        compiler.thunk_todo(thunk_function)
                end
                        self.require_declaration(thunk_function.c_name)
                        compiler.thunk_todo(thunk_function)
                end
-
-               # Each RoutineRef points to a receiver AND a callref_thunk
-               var res = self.new_expr("NEW_{base_routine_mclass.c_name}({my_recv}, (nitmethod_t){c_ref}, &class_{routine_mclass.c_name}, &type_{routine_type.c_name})", routine_type)
-               #debug "LEAVING ref_instance"
+               var res: RuntimeVariable
+               if routine_type.need_anchor then
+                       hardening_live_open_type(routine_type)
+                       link_unresolved_type(self.frame.mpropdef.mclassdef, routine_type)
+                       var recv2 = self.frame.arguments.first
+                       var recv2_type_info = self.type_info(recv2)
+                       self.require_declaration(routine_type.const_color)
+                       res = self.new_expr("NEW_{base_routine_mclass.c_name}({my_recv}, (nitmethod_t){c_ref}, &class_{routine_mclass.c_name}, {recv2_type_info}->resolution_table->types[{routine_type.const_color}])", routine_type)
+               else
+                       self.require_declaration("type_{routine_type.c_name}")
+                       compiler.undead_types.add(routine_type)
+                       res = self.new_expr("NEW_{base_routine_mclass.c_name}({my_recv}, (nitmethod_t){c_ref}, &class_{routine_mclass.c_name}, &type_{routine_type.c_name})", routine_type)
+               end
                return res
        end
 
                return res
        end
 
index bbdb30c..7557da7 100644 (file)
@@ -2295,8 +2295,12 @@ redef class ACallrefExpr
        do
                var recv = v.expr(self.n_expr)
                if recv == null then return null
        do
                var recv = v.expr(self.n_expr)
                if recv == null then return null
+               var mtype = self.mtype
                assert mtype != null
                assert mtype != null
-               var inst = new CallrefInstance(mtype.as(not null), recv, callsite.as(not null))
+               # In case we are in generic class where formal parameter can not
+               # be resolved.
+               var mtype2 = v.unanchor_type(mtype)
+               var inst = new CallrefInstance(mtype2, recv, callsite.as(not null))
                return inst
        end
 end
                return inst
        end
 end
index 0658445..b9acd5e 100644 (file)
@@ -181,7 +181,6 @@ private class TypeVisitor
                return self.visit_expr_subtype(nexpr, self.type_bool(nexpr))
        end
 
                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
        fun check_expr_cast(node: ANode, nexpr: AExpr, ntype: AType): nullable MType
        do
                var sub = nexpr.mtype
@@ -424,7 +423,6 @@ private class TypeVisitor
                return build_callsite_by_name(node, recvtype, name, recv_is_self)
        end
 
                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
        # 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 +443,6 @@ private class TypeVisitor
                        # Other cases are managed later
                end
 
                        # Other cases are managed later
                end
 
-
                #debug("CALL {unsafe_type}.{msignature}")
 
                # Associate each parameter to a position in the arguments
                #debug("CALL {unsafe_type}.{msignature}")
 
                # Associate each parameter to a position in the arguments
@@ -1177,7 +1174,6 @@ redef class AVarReassignExpr
        end
 end
 
        end
 end
 
-
 redef class AContinueExpr
        redef fun accept_typing(v)
        do
 redef class AContinueExpr
        redef fun accept_typing(v)
        do
@@ -1503,7 +1499,6 @@ redef class AAndExpr
        end
 end
 
        end
 end
 
-
 redef class ANotExpr
        redef fun accept_typing(v)
        do
 redef class ANotExpr
        redef fun accept_typing(v)
        do
@@ -2074,7 +2069,6 @@ redef class AUnaryopExpr
        redef fun compute_raw_arguments do return new Array[AExpr]
 end
 
        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
 redef class ACallExpr
        redef fun property_name do return n_qid.n_id.text
        redef fun property_node do return n_qid
@@ -2215,11 +2209,24 @@ redef class ACallrefExpr
                 # end
                 #
                 # var a = new A[Int]
                 # end
                 #
                 # var a = new A[Int]
-                # var f = &a.toto <- without anchor : ProcRef1[E]
-                #               ^--- with anchor : ProcRef[Int]
+                # var f = &a.toto # without anchor : ProcRef1[E]
+                #                # with anchor : ProcRef[Int]
                 # ~~~~
                 # ~~~~
-                var routine_type = routine_mclass.get_mtype(types_list).anchor_to(v.mmodule, recv.as(MClassType))
-
+               # 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
                 is_typed = true
                self.mtype = routine_type
        end
@@ -2509,7 +2516,6 @@ redef class AAttrExpr
        end
 end
 
        end
 end
 
-
 redef class AAttrAssignExpr
        redef fun accept_typing(v)
        do
 redef class AAttrAssignExpr
        redef fun accept_typing(v)
        do
index a97c247..6fbe92f 100644 (file)
@@ -11,3 +11,4 @@ x is null
 x is null
 x is test
 x is 100
 x is null
 x is test
 x is 100
+x is 100
index 66125d6..08c3219 100644 (file)
@@ -57,6 +57,9 @@ class C[E]
                end
                return "x is null"
        end
                end
                return "x is null"
        end
+
+       fun bar: C[E] do return self
+       fun foo: Fun0[C[E]] do return &bar
 end
 
 var a = new A
 end
 
 var a = new A
@@ -102,3 +105,6 @@ c2.x = 100
 
 print f6.call  # "x is test"
 print f7.call  # "x is 100"
 
 print f6.call  # "x is test"
 print f7.call  # "x is 100"
+
+var f8 = c2.foo
+print f8.call  # "x is 100"