return self.compiler.modelbuilder.force_get_primitive_method(self.current_node.as(not null), name, recv.mclass, self.compiler.mainmodule)
end
- fun compile_callsite(callsite: CallSite, args: Array[RuntimeVariable]): nullable RuntimeVariable
+ fun compile_callsite(callsite: CallSite, arguments: Array[RuntimeVariable]): nullable RuntimeVariable
do
- return self.send(callsite.mproperty, args)
+ var initializers = callsite.mpropdef.initializers
+ if not initializers.is_empty then
+ var recv = arguments.first
+
+ assert initializers.length == arguments.length - 1 else debug("expected {initializers.length}, got {arguments.length - 1}")
+ var i = 1
+ for p in initializers do
+ if p isa MMethod then
+ self.send(p, [recv, arguments[i]])
+ else if p isa MAttribute then
+ self.write_attribute(p, recv, arguments[i])
+ else abort
+ i += 1
+ end
+
+ return self.send(callsite.mproperty, [recv])
+ end
+
+ return self.send(callsite.mproperty, arguments)
end
fun native_array_instance(elttype: MType, length: RuntimeVariable): RuntimeVariable is abstract
private fun compile_to_c(v: AbstractCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable])
do
if mpropdef == self.mfree_init then
+ if mpropdef.mproperty.is_root_init then
+ assert self.super_inits == null
+ assert arguments.length == 1
+ if not mpropdef.is_intro then
+ v.supercall(mpropdef, arguments.first.mtype.as(MClassType), arguments)
+ end
+ return
+ end
+
var super_inits = self.super_inits
if super_inits != null then
var args_of_super = arguments
v.send(su, args_of_super)
end
end
+
var recv = arguments.first
var i = 1
# Collect undefined attributes
end
# Still here? So it means that we must determine what super inits need to be automatically invoked
+ # The code that follow is required to deal with complex cases with old-style and new-style inits
+ # Look for old-style super constructors
var auto_super_inits = new Array[CallSite]
for msupertype in mclassdef.supertypes do
# FIXME: the order is quite arbitrary
end
assert candidate isa MMethod
+ # Skip new-style init
+ if candidate.is_root_init then continue
+
var candidatedefs = candidate.lookup_definitions(mmodule, anchor)
var candidatedef = candidatedefs.first
# TODO, we drop the others propdefs in the callsite, that is not great :(
- var msignature = candidatedef.msignature
+ var msignature = candidatedef.new_msignature or else candidatedef.msignature
msignature = msignature.resolve_for(recvtype, anchor, mmodule, true)
var callsite = new CallSite(self, recvtype, mmodule, anchor, true, candidate, candidatedef, msignature, false)
auto_super_inits.add(callsite)
end
+
+ # No old style? The look for new-style super constructors (called from a old style constructor)
+ var the_root_init_mmethod = modelbuilder.the_root_init_mmethod
+ if the_root_init_mmethod != null and auto_super_inits.is_empty then
+ var candidatedefs = the_root_init_mmethod.lookup_definitions(mmodule, anchor)
+
+ # Search the longest-one and checks for conflict
+ var candidatedef = candidatedefs.first
+ if candidatedefs.length > 1 then
+ # Check for conflict in the order of initializers
+ # Each initializer list must me a prefix of the longest list
+ # part 1. find the longest list
+ for spd in candidatedefs do
+ if spd.initializers.length > candidatedef.initializers.length then candidatedef = spd
+ end
+ # compare
+ for spd in candidatedefs do
+ var i = 0
+ for p in spd.initializers do
+ if p != candidatedef.initializers[i] then
+ modelbuilder.error(self, "Error: Cannot do an implicit constructor call to comflicting for inherited inits {spd}({spd.initializers.join(", ")}) and {candidatedef}({candidatedef.initializers.join(", ")}). NOTE: Do not mix old-style and new-style init!")
+ return
+ end
+ i += 1
+ end
+ end
+ end
+
+ var msignature = candidatedef.new_msignature or else candidatedef.msignature
+ msignature = msignature.resolve_for(recvtype, anchor, mmodule, true)
+
+ var callsite = new CallSite(self, recvtype, mmodule, anchor, true, the_root_init_mmethod, candidatedef, msignature, false)
+ auto_super_inits.add(callsite)
+ end
if auto_super_inits.is_empty then
modelbuilder.error(self, "Error: No constructors to call implicitely in {mpropdef}. Call one explicitely.")
return
end
+
+ # Can the super-constructors be called?
for auto_super_init in auto_super_inits do
var auto_super_init_def = auto_super_init.mpropdef
var msig = mpropdef.msignature.as(not null)
# therefore, you should use `is_init_for` the verify if the property is a legal constructor for a given class
var is_init: Bool writable = false
+ # The constructor is a (the) root init with empty signature but a set of initializers
+ var is_root_init: Bool writable = false
+
# The the property a 'new' contructor?
var is_new: Bool writable = false
# The signature attached to the property definition
var msignature: nullable MSignature writable = null
+ # The signature attached to the `new` call on a root-init
+ # This is a concatenation of the signatures of the initializers
+ #
+ # REQUIRE `mproperty.is_root_init == (new_msignature != null)`
+ var new_msignature: nullable MSignature writable = null
+
+ # List of initialisers to call in root-inits
+ #
+ # They could be setters or attributes
+ #
+ # REQUIRE `mproperty.is_root_init == (new_msignature != null)`
+ var initializers = new Array[MProperty]
+
# Is the method definition abstract?
var is_abstract: Bool writable = false
process_default_constructors(nclassdef)
end
+ # the root init of the Object class
+ # Is usually implicitly defined
+ # Then explicit or implicit definitions of root-init are attached to it
+ var the_root_init_mmethod: nullable MMethod
+
# Introduce or inherit default constructor
# This is the last part of `build_properties`.
private fun process_default_constructors(nclassdef: AClassdef)
# Are we a refinement
if not mclassdef.is_intro then return
+ var mmodule = nclassdef.mclassdef.mmodule
+
+ # Look for the init in Object, or create it
+ if mclassdef.mclass.name == "Object" and the_root_init_mmethod == null then
+ # Create the implicit root-init method
+ var mprop = new MMethod(mclassdef, "init", mclassdef.mclass.visibility)
+ mprop.is_root_init = true
+ var mpropdef = new MMethodDef(mclassdef, mprop, nclassdef.location)
+ var mparameters = new Array[MParameter]
+ var msignature = new MSignature(mparameters, null)
+ mpropdef.msignature = msignature
+ mpropdef.new_msignature = msignature
+ mprop.is_init = true
+ nclassdef.mfree_init = mpropdef
+ self.toolcontext.info("{mclassdef} gets a free empty constructor {mpropdef}{msignature}", 3)
+ the_root_init_mmethod = mprop
+ return
+ end
+
# Is the class forbid constructors?
if not mclassdef.mclass.kind.need_init then return
# Is there already a constructor defined?
+ var defined_init: nullable MMethodDef = null
for mpropdef in mclassdef.mpropdefs do
if not mpropdef isa MMethodDef then continue
- if mpropdef.mproperty.is_init then return
+ if not mpropdef.mproperty.is_init then continue
+ if mpropdef.mproperty.is_root_init then
+ assert defined_init == null
+ defined_init = mpropdef
+ else
+ # An explicit old-style init, so return
+ return
+ end
end
if not nclassdef isa AStdClassdef then return
- var mmodule = mclassdef.mmodule
- # Do we inherit for a constructor?
- var combine = new Array[MMethod]
- var inhc: nullable MClass = null
- for st in mclassdef.supertypes do
+ # Do we inherit a old-style constructor?
+ var combine = new Array[MMethod] # old-style constructors without arguments
+ var inhc: nullable MClass = null # single super-class with a constructor with arguments
+ if defined_init == null then for st in mclassdef.supertypes do
var c = st.mclass
if not c.kind.need_init then continue
st = st.anchor_to(mmodule, mclassdef.bound_mtype)
var candidate = self.try_get_mproperty_by_name2(nclassdef, mmodule, st, "init").as(nullable MMethod)
if candidate != null then
+ if candidate.is_root_init then continue
if candidate.intro.msignature != null then
if candidate.intro.msignature.arity == 0 then
combine.add(candidate)
# Collect undefined attributes
var mparameters = new Array[MParameter]
+ var initializers = new Array[MProperty]
var anode: nullable ANode = null
for npropdef in nclassdef.n_propdefs do
if npropdef isa AAttrPropdef then
if ret_type == null then return
var mparameter = new MParameter(paramname, ret_type, false)
mparameters.add(mparameter)
+ var msetter = npropdef.mwritepropdef
+ if msetter == null then
+ # No setter, it is a old-style attribute, so just add it
+ initializers.add(npropdef.mpropdef.mproperty)
+ else
+ # Add the setter to the list
+ initializers.add(msetter.mproperty)
+ end
if anode == null then anode = npropdef
end
end
# TODO: actively inherit the consturctor
self.toolcontext.info("{mclassdef} inherits all constructors from {inhc}", 3)
- mclassdef.mclass.inherit_init_from = inhc
- return
+ #mclassdef.mclass.inherit_init_from = inhc
+ #return
end
if not combine.is_empty and inhc != null then
self.error(nclassdef, "Error: Cannot provide a defaut constructor: conflict for {combine.join(", ")} and {inhc}")
return
end
-
if not combine.is_empty then
if mparameters.is_empty and combine.length == 1 then
# No need to create a local init, the inherited one is enough
return
end
nclassdef.super_inits = combine
+ var mprop = new MMethod(mclassdef, "init", mclassdef.mclass.visibility)
+ var mpropdef = new MMethodDef(mclassdef, mprop, nclassdef.location)
+ var msignature = new MSignature(mparameters, null)
+ mpropdef.msignature = msignature
+ mprop.is_init = true
+ nclassdef.mfree_init = mpropdef
+ self.toolcontext.info("{mclassdef} gets a free empty constructor {mpropdef}{msignature}", 3)
+ return
+ end
+
+ if the_root_init_mmethod == null then return
+
+ # Look for nost-specific new-stype init definitions
+ var spropdefs = the_root_init_mmethod.lookup_super_definitions(mclassdef.mmodule, mclassdef.bound_mtype)
+ if spropdefs.is_empty then
+ toolcontext.fatal_error(nclassdef.location, "Fatal error: {mclassdef} does not specialize {the_root_init_mmethod.intro_mclassdef}. Possible duplication of the root class `Object`?")
end
- var mprop = new MMethod(mclassdef, "init", mclassdef.mclass.visibility)
+ # Search the longest-one and checks for conflict
+ var longest = spropdefs.first
+ if spropdefs.length > 1 then
+ # Check for conflict in the order of initializers
+ # Each initializer list must me a prefix of the longest list
+ # part 1. find the longest list
+ for spd in spropdefs do
+ if spd.initializers.length > longest.initializers.length then longest = spd
+ end
+ # part 2. compare
+ for spd in spropdefs do
+ var i = 0
+ for p in spd.initializers do
+ if p != longest.initializers[i] then
+ self.error(nclassdef, "Error: conflict for inherited inits {spd}({spd.initializers.join(", ")}) and {longest}({longest.initializers.join(", ")})")
+ return
+ end
+ i += 1
+ end
+ end
+ end
+
+ # Can we just inherit?
+ if spropdefs.length == 1 and mparameters.is_empty and defined_init == null then
+ self.toolcontext.info("{mclassdef} inherits the basic constructor {longest}", 3)
+ return
+ end
+
+ # Combine the inherited list to what is collected
+ if longest.initializers.length > 0 then
+ mparameters.prepend longest.new_msignature.mparameters
+ initializers.prepend longest.initializers
+ end
+
+ # If we already have a basic init definition, then setup its initializers
+ if defined_init != null then
+ defined_init.initializers.add_all(initializers)
+ var msignature = new MSignature(mparameters, null)
+ defined_init.new_msignature = msignature
+ self.toolcontext.info("{mclassdef} extends its basic constructor signature to {defined_init}{msignature}", 3)
+ return
+ end
+
+ # Else create the local implicit basic init definition
+ var mprop = the_root_init_mmethod.as(not null)
var mpropdef = new MMethodDef(mclassdef, mprop, nclassdef.location)
+ mpropdef.has_supercall = true
+ mpropdef.initializers.add_all(initializers)
var msignature = new MSignature(mparameters, null)
- mpropdef.msignature = msignature
- mprop.is_init = true
+ mpropdef.new_msignature = msignature
+ mpropdef.msignature = new MSignature(new Array[MParameter], null) # always an empty real signature
nclassdef.mfree_init = mpropdef
self.toolcontext.info("{mclassdef} gets a free constructor for attributes {mpropdef}{msignature}", 3)
end
# Use this method, instead of `send` to execute and control the aditionnal behavior of the call-sites
fun callsite(callsite: nullable CallSite, arguments: Array[Instance]): nullable Instance
do
+ var initializers = callsite.mpropdef.initializers
+ if not initializers.is_empty then
+ assert initializers.length == arguments.length - 1 else debug("expected {initializers.length} got {arguments.length - 1}")
+ var recv = arguments.first
+ var i = 1
+ for p in initializers do
+ if p isa MMethod then
+ self.send(p, [recv, arguments[i]])
+ else if p isa MAttribute then
+ assert recv isa MutableInstance
+ recv.attributes[p] = arguments[i]
+ else abort
+ i += 1
+ end
+ return send(callsite.mproperty, [recv])
+ end
return send(callsite.mproperty, arguments)
end
# Execute an implicit `mpropdef` associated with the current node.
private fun call(v: NaiveInterpreter, mpropdef: MMethodDef, args: Array[Instance]): nullable Instance
do
+ if mpropdef.mproperty.is_root_init then
+ assert self.super_inits == null
+ assert args.length == 1
+ if not mpropdef.is_intro then
+ # standard call-next-method
+ var superpd = mpropdef.lookup_next_definition(v.mainmodule, args.first.mtype)
+ v.call_without_varargs(superpd, args)
+ end
+ return null
+ end
+
var super_inits = self.super_inits
if super_inits != null then
var args_of_super = args
v.add_monomorphic_send(vararg, self.modelbuilder.force_get_primitive_method(node, "with_native", vararg.mclass, self.mainmodule))
end
+ # TODO? new_msignature
var sig = mmethoddef.msignature.as(not null)
var osig = mmeth.intro.msignature.as(not null)
for i in [0..sig.arity[ do
v.add_monomorphic_send(v.receiver, su)
end
end
+
+ if mmethoddef.mproperty.is_root_init and not mmethoddef.is_intro then
+ self.add_super_send(v.receiver, mmethoddef)
+ end
else
abort
end
fun add_cast_type(mtype: MType) do analysis.add_cast(mtype)
fun add_callsite(callsite: nullable CallSite) do if callsite != null then
+ for m in callsite.mpropdef.initializers do
+ if m isa MMethod then
+ analysis.add_send(callsite.recv, m)
+ end
+ end
analysis.add_send(callsite.recv, callsite.mproperty)
analysis.live_callsites.add(callsite)
end
do
var rta = compiler.runtime_type_analysis
var recv = args.first.mtype
- if compiler.modelbuilder.toolcontext.opt_direct_call_monomorph.value and rta != null then
+ var mmethod = callsite.mproperty
+ # TODO: Inlining of new-style constructors
+ if compiler.modelbuilder.toolcontext.opt_direct_call_monomorph.value and rta != null and not mmethod.is_root_init then
var tgs = rta.live_targets(callsite)
if tgs.length == 1 then
# DIRECT CALL
- var mmethod = callsite.mproperty
self.varargize(mmethod.intro, mmethod.intro.msignature.as(not null), args)
var res0 = before_send(mmethod, args)
var res = call(tgs.first, tgs.first.mclassdef.bound_mtype, args)
end
- var msignature = mpropdef.msignature.as(not null)
+ var msignature = mpropdef.new_msignature or else mpropdef.msignature.as(not null)
msignature = resolve_for(msignature, recvtype, recv_is_self).as(MSignature)
var erasure_cast = false
if not (vmpropdef isa MMethodDef and vmpropdef.mproperty.is_init) then
v.error(self, "Can call a init only in another init")
end
+ if vmpropdef isa MMethodDef and vmpropdef.mproperty.is_root_init and not callsite.mproperty.is_root_init then
+ v.error(self, "Error: {vmpropdef} cannot call a factory {callsite.mproperty}")
+ end
end
var ret = msignature.return_mtype
if v.modelbuilder.toolcontext.error_count > errcount then return # Forard error
continue # Try next super-class
end
- if superprop != null and superprop.mproperty != candidate then
+ if superprop != null and candidate.is_root_init then
+ continue
+ end
+ if superprop != null and superprop.mproperty != candidate and not superprop.mproperty.is_root_init then
v.error(self, "Error: conflicting super constructor to call for {mproperty}: {candidate.full_name}, {superprop.mproperty.full_name}")
return
end
var candidatedefs = candidate.lookup_definitions(v.mmodule, recvtype)
- if superprop != null then
+ if superprop != null and superprop.mproperty == candidate then
if superprop == candidatedefs.first then continue
candidatedefs.add(superprop)
end
return
end
- var msignature = superprop.msignature.as(not null)
+ var msignature = superprop.new_msignature or else superprop.msignature.as(not null)
msignature = v.resolve_for(msignature, recvtype, true).as(MSignature)
var callsite = new CallSite(self, recvtype, v.mmodule, v.anchor, true, superprop.mproperty, superprop, msignature, false)