X-Git-Url: http://nitlanguage.org diff --git a/src/modelize_property.nit b/src/modelize_property.nit index 8273fb8..db51cbd 100644 --- a/src/modelize_property.nit +++ b/src/modelize_property.nit @@ -68,6 +68,11 @@ redef class ModelBuilder 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) @@ -77,27 +82,54 @@ redef class ModelBuilder # 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) @@ -117,6 +149,7 @@ redef class ModelBuilder # 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 @@ -135,6 +168,14 @@ redef class ModelBuilder 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 @@ -148,15 +189,14 @@ redef class ModelBuilder # 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 @@ -166,13 +206,75 @@ redef class ModelBuilder 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