From 31110c7a689c682f5fcd770a516ac83ccc454b1e Mon Sep 17 00:00:00 2001 From: Louis-Vincent Boudreault Date: Fri, 11 Oct 2019 20:02:28 -0400 Subject: [PATCH] Callref bugfix in interpreter and compilers + autosav ~~~~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 --- src/compiler/global_compiler.nit | 4 ++-- src/compiler/separate_compiler.nit | 20 +++++++++++++------- src/interpreter/naive_interpreter.nit | 6 +++++- src/semantize/typing.nit | 28 +++++++++++++++++----------- tests/sav/test_callref.res | 1 + tests/test_callref.nit | 6 ++++++ 6 files changed, 44 insertions(+), 21 deletions(-) diff --git a/src/compiler/global_compiler.nit b/src/compiler/global_compiler.nit index 765e630..ac5a2a1 100644 --- a/src/compiler/global_compiler.nit +++ b/src/compiler/global_compiler.nit @@ -476,8 +476,8 @@ class GlobalCompilerVisitor 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 diff --git a/src/compiler/separate_compiler.nit b/src/compiler/separate_compiler.nit index 64edec5..4716dae 100644 --- a/src/compiler/separate_compiler.nit +++ b/src/compiler/separate_compiler.nit @@ -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}") - 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) @@ -2235,10 +2232,19 @@ class SeparateCompilerVisitor 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 diff --git a/src/interpreter/naive_interpreter.nit b/src/interpreter/naive_interpreter.nit index bbdb30c..7557da7 100644 --- a/src/interpreter/naive_interpreter.nit +++ b/src/interpreter/naive_interpreter.nit @@ -2295,8 +2295,12 @@ redef class ACallrefExpr do var recv = v.expr(self.n_expr) if recv == null then return null + var mtype = self.mtype 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 diff --git a/src/semantize/typing.nit b/src/semantize/typing.nit index 0658445..b9acd5e 100644 --- a/src/semantize/typing.nit +++ b/src/semantize/typing.nit @@ -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 @@ -424,7 +423,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 +443,6 @@ private class TypeVisitor # Other cases are managed later end - #debug("CALL {unsafe_type}.{msignature}") # Associate each parameter to a position in the arguments @@ -1177,7 +1174,6 @@ redef class AVarReassignExpr end end - redef class AContinueExpr redef fun accept_typing(v) do @@ -1503,7 +1499,6 @@ redef class AAndExpr end end - 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 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] - # 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 @@ -2509,7 +2516,6 @@ redef class AAttrExpr end end - redef class AAttrAssignExpr redef fun accept_typing(v) do diff --git a/tests/sav/test_callref.res b/tests/sav/test_callref.res index a97c247..6fbe92f 100644 --- a/tests/sav/test_callref.res +++ b/tests/sav/test_callref.res @@ -11,3 +11,4 @@ x is null x is null x is test x is 100 +x is 100 diff --git a/tests/test_callref.nit b/tests/test_callref.nit index 66125d6..08c3219 100644 --- a/tests/test_callref.nit +++ b/tests/test_callref.nit @@ -57,6 +57,9 @@ class C[E] 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 @@ -102,3 +105,6 @@ c2.x = 100 print f6.call # "x is test" print f7.call # "x is 100" + +var f8 = c2.foo +print f8.call # "x is 100" -- 1.7.9.5