model: `new` factories have a return type.
[nit.git] / src / modelize / modelize_property.nit
index 487110f..0d2e3a6 100644 (file)
@@ -38,7 +38,7 @@ end
 redef class ModelBuilder
        # Register the npropdef associated to each mpropdef
        # FIXME: why not refine the `MPropDef` class with a nullable attribute?
-       var mpropdef2npropdef: HashMap[MPropDef, APropdef] = new HashMap[MPropDef, APropdef]
+       var mpropdef2npropdef = new HashMap[MPropDef, APropdef]
 
        # Build the properties of `nclassdef`.
        # REQUIRE: all superclasses are built.
@@ -122,6 +122,26 @@ redef class ModelBuilder
                var mparameters = new Array[MParameter]
                var initializers = new Array[MProperty]
                for npropdef in nclassdef.n_propdefs do
+                       if npropdef isa AMethPropdef then
+                               if npropdef.mpropdef == null then return # Skip broken attribute
+                               var at = npropdef.get_single_annotation("autoinit", self)
+                               if at == null then continue # Skip non tagged init
+
+                               var sig = npropdef.mpropdef.msignature
+                               if sig == null then continue # Skip broken method
+
+                               if not npropdef.mpropdef.is_intro then
+                                       self.error(at, "Error: `autoinit` cannot be set on redefinitions")
+                                       continue
+                               end
+
+                               for param in sig.mparameters do
+                                       var ret_type = param.mtype
+                                       var mparameter = new MParameter(param.name, ret_type, false)
+                                       mparameters.add(mparameter)
+                               end
+                               initializers.add(npropdef.mpropdef.mproperty)
+                       end
                        if npropdef isa AAttrPropdef then
                                if npropdef.mpropdef == null then return # Skip broken attribute
                                var at = npropdef.get_single_annotation("noinit", self)
@@ -182,6 +202,7 @@ redef class ModelBuilder
                # 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
 
@@ -197,6 +218,7 @@ redef class ModelBuilder
                        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
                end
 
@@ -210,6 +232,7 @@ redef class ModelBuilder
                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)
+               mclassdef.mclass.root_init = mpropdef
        end
 
        # Check the visibility of `mtype` as an element of the signature of `mpropdef`.
@@ -221,7 +244,7 @@ redef class ModelBuilder
                # Extract visibility information of the main part of `mtype`
                # It is a case-by case
                var vis_type: nullable MVisibility = null # The own visibility of the type
-               var mmodule_type: nullable MModule = null # The origial module of the type
+               var mmodule_type: nullable MModule = null # The original module of the type
                mtype = mtype.as_notnullable
                if mtype isa MClassType then
                        vis_type = mtype.mclass.visibility
@@ -268,43 +291,27 @@ redef class MPropDef
 end
 
 redef class AClassdef
-       var build_properties_is_done: Bool = false
-       # The list of super-constructor to call at the start of the free constructor
-       # FIXME: this is needed to implement the crazy constructor thing of the of old compiler. We need to think what to do with since this cannot stay in the modelbuilder
-       var super_inits: nullable Collection[MMethod] = null
+       var build_properties_is_done = false
 
        # The free init (implicitely constructed by the class if required)
        var mfree_init: nullable MMethodDef = null
 end
 
+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
+end
+
 redef class MClassDef
        # What is the `APropdef` associated to a `MProperty`?
        # Used to check multiple definition of a property.
        var mprop2npropdef: Map[MProperty, APropdef] = new HashMap[MProperty, APropdef]
 end
 
-redef class Prod
-       # Join the text of all tokens
-       # Used to get the 'real name' of method definitions.
-       fun collect_text: String
-       do
-               var v = new TextCollectorVisitor
-               v.enter_visit(self)
-               assert v.text != ""
-               return v.text
-       end
-end
-
-private class TextCollectorVisitor
-       super Visitor
-       var text: String = ""
-       redef fun visit(n)
-       do
-               if n isa Token then text += n.text
-               n.visit_all(self)
-       end
-end
-
 redef class APropdef
        # The associated main model entity
        type MPROPDEF: MPropDef
@@ -445,7 +452,7 @@ redef class ASignature
                var ntype = self.n_type
                if ntype != null then
                        self.ret_type = modelbuilder.resolve_mtype(mmodule, mclassdef, ntype)
-                       if self.ret_type == null then return false # Skip errir
+                       if self.ret_type == null then return false # Skip error
                end
 
                self.is_visited = true
@@ -522,7 +529,7 @@ redef class AMethPropdef
                                name = "init"
                                name_node = n_kwinit
                        else if n_kwnew != null then
-                               name = "init"
+                               name = "new"
                                name_node = n_kwnew
                        else
                                abort
@@ -587,6 +594,16 @@ redef class AMethPropdef
                var mmodule = mclassdef.mmodule
                var nsig = self.n_signature
 
+               if mpropdef.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
+
                # Retrieve info from the signature AST
                var param_names = new Array[String] # Names of parameters from the AST
                var param_types = new Array[MType] # Types of parameters from the AST
@@ -614,7 +631,7 @@ redef class AMethPropdef
                                modelbuilder.error(node, "Redef error: {mpropdef} redefines {mpropdef.mproperty.intro} with {param_names.length} parameter(s), {msignature.arity} expected. Signature is {mpropdef}{msignature}")
                                return
                        end
-               else if mpropdef.mproperty.is_init then
+               else if mpropdef.mproperty.is_init and not mpropdef.mproperty.is_new then
                        # FIXME UGLY: inherit signature from a super-constructor
                        for msupertype in mclassdef.supertypes do
                                msupertype = msupertype.anchor_to(mmodule, mclassdef.bound_mtype)
@@ -654,6 +671,9 @@ redef class AMethPropdef
                        mparameters.add(mparameter)
                end
 
+               # In `new`-factories, the return type is by default the classtype.
+               if ret_type == null and mpropdef.mproperty.is_new then ret_type = mclassdef.mclass.mclass_type
+
                msignature = new MSignature(mparameters, ret_type)
                mpropdef.msignature = msignature
                mpropdef.is_abstract = self.get_single_annotation("abstract", modelbuilder) != null
@@ -723,12 +743,12 @@ redef class AAttrPropdef
        # Is the node tagged `noinit`?
        var noinit = false
 
-       # Is the node taggeg lazy?
+       # Is the node tagged lazy?
        var is_lazy = false
 
-       # The guard associated to a lasy attribute.
+       # The guard associated to a lazy attribute.
        # Because some engines does not have a working `isset`,
-       # this additionnal attribute is used to guard the lazy initialization.
+       # this additional attribute is used to guard the lazy initialization.
        # TODO: to remove once isset is correctly implemented
        var mlazypropdef: nullable MAttributeDef
 
@@ -758,7 +778,6 @@ redef class AAttrPropdef
                var mpropdef = new MAttributeDef(mclassdef, mprop, self.location)
                self.mpropdef = mpropdef
                modelbuilder.mpropdef2npropdef[mpropdef] = self
-               set_doc(mpropdef, modelbuilder)
 
                var readname = name
                var mreadprop = modelbuilder.try_get_mproperty_by_name(nid2, mclassdef, readname).as(nullable MMethod)
@@ -776,7 +795,8 @@ redef class AAttrPropdef
                var mreadpropdef = new MMethodDef(mclassdef, mreadprop, self.location)
                self.mreadpropdef = mreadpropdef
                modelbuilder.mpropdef2npropdef[mreadpropdef] = self
-               mreadpropdef.mdoc = mpropdef.mdoc
+               set_doc(mreadpropdef, modelbuilder)
+               mpropdef.mdoc = mreadpropdef.mdoc
 
                var atlazy = self.get_single_annotation("lazy", modelbuilder)
                if atlazy != null then
@@ -835,7 +855,7 @@ redef class AAttrPropdef
        redef fun build_signature(modelbuilder)
        do
                var mpropdef = self.mpropdef
-               if mpropdef == null then return # Error thus skiped
+               if mpropdef == null then return # Error thus skipped
                var mclassdef = mpropdef.mclassdef
                var mmodule = mclassdef.mmodule
                var mtype: nullable MType = null
@@ -848,10 +868,10 @@ redef class AAttrPropdef
                        if mtype == null then return
                end
 
-               # Inherit the type from the getter (usually an abstact getter)
+               # Inherit the type from the getter (usually an abstract getter)
                if mtype == null and mreadpropdef != null and not mreadpropdef.is_intro then
                        var msignature = mreadpropdef.mproperty.intro.msignature
-                       if msignature == null then return # Error, thus skiped
+                       if msignature == null then return # Error, thus skipped
                        mtype = msignature.return_mtype
                end
 
@@ -923,12 +943,10 @@ redef class AAttrPropdef
        redef fun check_signature(modelbuilder)
        do
                var mpropdef = self.mpropdef
-               if mpropdef == null then return # Error thus skiped
-               var mclassdef = mpropdef.mclassdef
-               var mmodule = mclassdef.mmodule
+               if mpropdef == null then return # Error thus skipped
                var ntype = self.n_type
                var mtype = self.mpropdef.static_mtype
-               if mtype == null then return # Error thus skiped
+               if mtype == null then return # Error thus skipped
 
                # Lookup for signature in the precursor
                # FIXME all precursors should be considered
@@ -1051,7 +1069,7 @@ redef class ATypePropdef
        redef fun build_signature(modelbuilder)
        do
                var mpropdef = self.mpropdef
-               if mpropdef == null then return # Error thus skiped
+               if mpropdef == null then return # Error thus skipped
                var mclassdef = mpropdef.mclassdef
                var mmodule = mclassdef.mmodule
                var mtype: nullable MType = null
@@ -1067,10 +1085,10 @@ redef class ATypePropdef
        redef fun check_signature(modelbuilder)
        do
                var mpropdef = self.mpropdef
-               if mpropdef == null then return # Error thus skiped
+               if mpropdef == null then return # Error thus skipped
 
                var bound = self.mpropdef.bound
-               if bound == null then return # Error thus skiped
+               if bound == null then return # Error thus skipped
 
                modelbuilder.check_visibility(n_type, bound, mpropdef)