Skip to content

Commit

Permalink
Callref bugfix in interpreter and sep compiler + autosav
Browse files Browse the repository at this point in the history
~~~~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`
- Still need to fix the global and erasure compiler

Signed-off-by: Louis-Vincent Boudreault <lv.boudreault95@gmail.com>
  • Loading branch information
lvboudre committed Oct 12, 2019
1 parent 0709376 commit 67d4e94
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 19 deletions.
20 changes: 13 additions & 7 deletions src/compiler/separate_compiler.nit
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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

Expand Down
6 changes: 5 additions & 1 deletion src/interpreter/naive_interpreter.nit
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
28 changes: 17 additions & 11 deletions src/semantize/typing.nit
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -1177,7 +1174,6 @@ redef class AVarReassignExpr
end
end


redef class AContinueExpr
redef fun accept_typing(v)
do
Expand Down Expand Up @@ -1503,7 +1499,6 @@ redef class AAndExpr
end
end


redef class ANotExpr
redef fun accept_typing(v)
do
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -2509,7 +2516,6 @@ redef class AAttrExpr
end
end


redef class AAttrAssignExpr
redef fun accept_typing(v)
do
Expand Down
1 change: 1 addition & 0 deletions tests/sav/test_callref.res
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ x is null
x is null
x is test
x is 100
x is 100
6 changes: 6 additions & 0 deletions tests/test_callref.nit
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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"

0 comments on commit 67d4e94

Please sign in to comment.