# Public clients need to use `mpropdef2node` to access stuff.
private var mpropdef2npropdef = new HashMap[MPropDef, APropdef]
+ # Associate a `npropdef` with its `mpropdef`
+ #
+ # Be careful, this method is unsafe, no checking is done when it's used.
+ # The safe way to add method it's to use the `build_property`
+ #
+ # See `mpropdef2npropdef`
+ fun unsafe_add_mpropdef2npropdef(mpropdef: MPropDef,npropdef: APropdef)
+ do
+ mpropdef2npropdef[mpropdef] = npropdef
+ end
+
# Retrieve the associated AST node of a mpropertydef.
# This method is used to associate model entity with syntactic entities.
#
toolcontext.run_phases_on_npropdef(res)
return res
end
- if mpropdef isa MMethodDef and mpropdef.mproperty.is_root_init then
- res = mclassdef2nclassdef.get_or_null(mpropdef.mclassdef)
- if res != null then return res
- end
+ # Fall back to the class node if any.
+ res = mclassdef2nclassdef.get_or_null(mpropdef.mclassdef)
+ if res != null then return res
return null
end
var mparameters = new Array[MParameter]
var msignature = new MSignature(mparameters, null)
mpropdef.msignature = msignature
- mpropdef.new_msignature = msignature
mprop.is_init = true
self.toolcontext.info("{mclassdef} gets a free empty constructor {mpropdef}{msignature}", 3)
the_root_init_mmethod = mprop
- return
end
# Is there already a constructor defined?
if mpropdef.mproperty.is_root_init then
assert defined_init == null
defined_init = mpropdef
- else if mpropdef.mproperty.name == "init" then
- # An explicit old-style init named "init", so return
+ end
+ if mpropdef.name == "defaultinit" then
return
end
end
+ if mclassdef.default_init != null then return
+
if not nclassdef isa AStdClassdef then return
# Collect undefined attributes
if mpropdef == null then return # Skip broken method
var sig = mpropdef.msignature
if sig == null then continue # Skip broken method
-
mparameters.add_all sig.mparameters
initializers.add(mpropdef.mproperty)
mpropdef.mproperty.is_autoinit = true
if the_root_init_mmethod == null then return
# Look for most-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.error(nclassdef.location, "Error: `{mclassdef}` does not specialize `{the_root_init_mmethod.intro_mclassdef}`. Possible duplication of the root class `Object`?")
- return
+ var spropdefs = new ArraySet[MMethodDef]
+ for x in mclassdef.in_hierarchy.direct_greaters do
+ var y = x.mclass.intro.default_init
+ if y == null then continue
+ if y.is_broken or y.msignature == null then return
+ spropdefs.add y
end
# Look at the autoinit class-annotation
abort
end
end
- else
+ else if spropdefs.not_empty then
# Search the longest-one and checks for conflict
var longest = spropdefs.first
if spropdefs.length > 1 then
mparameters.clear
initializers.clear
else
- # 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)
- mclassdef.mclass.root_init = longest
- return
- end
-
# Combine the inherited list to what is collected
if longest.initializers.length > 0 then
- mparameters.prepend longest.new_msignature.mparameters
+ mparameters.prepend longest.msignature.mparameters
initializers.prepend longest.initializers
end
end
end
- # If we already have a basic init definition, then setup its initializers
- if defined_init != null then
- defined_init.initializers.add_all(initializers)
+ # Create a specific new autoinit constructor
+ do
+ var mprop = new MMethod(mclassdef, "defaultinit", nclassdef.location, public_visibility)
+ mprop.is_init = true
+ var mpropdef = new MMethodDef(mclassdef, mprop, nclassdef.location)
+ mpropdef.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)
- mclassdef.mclass.root_init = defined_init
- return
+ mpropdef.msignature = msignature
+ mclassdef.default_init = mpropdef
+ self.toolcontext.info("{mclassdef} gets a free auto constructor `{mpropdef}{msignature}`. {spropdefs}", 3)
+ mclassdef.mclass.the_root_init_mmethod = the_root_init_mmethod
end
-
- # Else create the local implicit basic init definition
- var mprop = the_root_init_mmethod
- var mpropdef = new MMethodDef(mclassdef, mprop, nclassdef.location)
- mpropdef.has_supercall = true
- mpropdef.initializers.add_all(initializers)
- var msignature = new MSignature(mparameters, null)
- mpropdef.new_msignature = msignature
- mpropdef.msignature = new MSignature(new Array[MParameter], null) # always an empty real signature
- self.toolcontext.info("{mclassdef} gets a free constructor for attributes {mpropdef}{msignature}", 3)
- mclassdef.mclass.root_init = mpropdef
end
# Check the visibility of `mtype` as an element of the signature of `mpropdef`.
redef class MClass
# The base init of the class.
- # Used to get the common new_msignature and initializers
#
- # TODO: Where to put this information is not clear because unlike other
- # informations, the initialisers are stable in a same class.
- var root_init: nullable MMethodDef = null
+ # TODO: merge with `root_init` and `ModelBuilder::the_root_init_mmethod` if possible
+ var the_root_init_mmethod: nullable MMethod = null
end
redef class MClassDef
var name: String
var amethodid = self.n_methid
var name_node: ANode
+ var is_old_style_init = false
if amethodid == null then
if n_kwinit != null then
name = "init"
name_node = n_kwinit
+ var old_style_annot = get_single_annotation("old_style_init", modelbuilder)
+ if old_style_annot != null or self.n_signature.n_params.not_empty then
+ name = "defaultinit"
+ if old_style_annot != null then is_old_style_init = true
+ end
else if n_kwnew != null then
name = "new"
name_node = n_kwnew
var look_like_a_root_init = look_like_a_root_init(modelbuilder, mclassdef)
var mprop: nullable MMethod = null
- if not is_init or n_kwredef != null then mprop = modelbuilder.try_get_mproperty_by_name(name_node, mclassdef, name).as(nullable MMethod)
+ if not is_init or n_kwredef != null or look_like_a_root_init then mprop = modelbuilder.try_get_mproperty_by_name(name_node, mclassdef, name).as(nullable MMethod)
if mprop == null and look_like_a_root_init then
mprop = modelbuilder.the_root_init_mmethod
var nb = n_block
mclassdef.mprop2npropdef[mprop] = self
var mpropdef = new MMethodDef(mclassdef, mprop, self.location)
+ if mpropdef.name == "defaultinit" and mclassdef.is_intro then
+ assert mclassdef.default_init == null
+ mpropdef.is_old_style_init = is_old_style_init
+ mclassdef.default_init = mpropdef
+ if mpropdef.is_intro then
+ mpropdef.initializers.add mprop
+ mpropdef.is_calling_init = true
+ end
+ end
set_doc(mpropdef, modelbuilder)
var mmodule = mclassdef.mmodule
var nsig = self.n_signature
- if mproperty.is_root_init and not mclassdef.is_intro then
- var root_init = mclassdef.mclass.root_init
- if root_init != null then
- # Inherit the initializers by refinement
- mpropdef.new_msignature = root_init.new_msignature
- assert mpropdef.initializers.is_empty
- mpropdef.initializers.add_all root_init.initializers
- end
- end
-
var accept_special_last_parameter = self.n_methid == null or self.n_methid.accept_special_last_parameter
var return_is_mandatory = self.n_methid != null and self.n_methid.return_is_mandatory