import counter
import pkgconfig
private import explain_assert_api
+import contracts
# Add compiling options
redef class ToolContext
fun compile_callsite(callsite: CallSite, arguments: Array[RuntimeVariable]): nullable RuntimeVariable
do
if callsite.is_broken then return null
- var initializers = callsite.mpropdef.initializers
- if not initializers.is_empty then
- var recv = arguments.first
-
- var i = 1
- for p in initializers do
- if p isa MMethod then
- var args = [recv]
- for x in p.intro.msignature.mparameters do
- args.add arguments[i]
- i += 1
- end
- self.send(p, args)
- else if p isa MAttribute then
- self.write_attribute(p, recv, arguments[i])
- i += 1
- else abort
- end
- assert i == arguments.length
-
- return self.send(callsite.mproperty, [recv])
- end
-
return self.send(callsite.mproperty, arguments)
end
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
+ fun routine_ref_instance(routine_mclass_type: MClassType, recv: RuntimeVariable, callsite: CallSite): RuntimeVariable is abstract
# Call the underlying referenced function
fun routine_ref_call(mmethoddef: MMethodDef, args: Array[RuntimeVariable]) is abstract
# of runtime variables to use in the call.
fun varargize(mpropdef: MMethodDef, map: nullable SignatureMap, recv: RuntimeVariable, args: SequenceRead[AExpr]): Array[RuntimeVariable]
do
- var msignature = mpropdef.new_msignature or else mpropdef.msignature.as(not null)
+ var msignature = mpropdef.msignature.as(not null)
var res = new Array[RuntimeVariable]
res.add(recv)
v.supercall(mpropdef, arguments.first.mtype.as(MClassType), arguments)
end
return
+ else if mclassdef.default_init == mpropdef then
+ var recv = arguments.first
+ var initializers = mpropdef.initializers
+ var no_init = false
+ if not initializers.is_empty and not mpropdef.is_old_style_init then
+ var i = 1
+ for p in initializers do
+ if p isa MMethod then
+ var args = [recv]
+ for x in p.intro.msignature.mparameters do
+ args.add arguments[i]
+ i += 1
+ end
+ v.send(p, args)
+ if p.intro.is_calling_init then no_init = true
+ else if p isa MAttribute then
+ v.write_attribute(p, recv, arguments[i])
+ i += 1
+ else abort
+ end
+ assert i == arguments.length
+
+ end
+ if not no_init then v.send(mclass.the_root_init_mmethod.as(not null), [recv])
+ return
else
abort
end
var res = v.compile_callsite(callsite, args)
if is_safe then
if res != null then
- var orig_res = res
+ # `callsite.mpropdef` may reference a method whose
+ # return type is a primitive type in C. If it is
+ # the case, we must convert the primitive type to
+ # a `val*` to support nullable assignment.
+ # Autobox's job is to convert primitive type to
+ # nullable type, eg from `Int` to `nullable `Int`.
+ # The target type reside in `self.mtype`.
+ var original_res = v.autobox(res, self.mtype.as(not null))
+
+ # Here we must create a new_var in case the original
+ # type is not nullable. We can't call `autobox` to
+ # convert a complex type to its nullable version.
+ # eg if we have a type `A`, calling autobox like
+ # `autobox(A, nullable A)` will return `A` since
+ # `A` and `nullable A` have the same primitive
+ # type. The nullable qualifier is only used at
+ # compile time to add appropriate null checks.
res = v.new_var(self.mtype.as(not null))
- v.add("{res} = {orig_res};")
+ v.add("{res} = {original_res};")
v.add("\} else \{")
v.add("{res} = NULL;")
end
redef fun expr(v)
do
var recv = v.expr(self.n_expr, null)
- var res = v.routine_ref_instance(mtype.as(MClassType), recv, callsite.as(not null).mpropdef)
+ var res = v.routine_ref_instance(mtype.as(MClassType), recv, callsite.as(not null))
return res
end
end