X-Git-Url: http://nitlanguage.org diff --git a/src/modelize/modelize_property.nit b/src/modelize/modelize_property.nit index 8529ed6..b19145e 100644 --- a/src/modelize/modelize_property.nit +++ b/src/modelize/modelize_property.nit @@ -149,7 +149,11 @@ redef class ModelBuilder var mclassdef = nclassdef.mclassdef.as(not null) # Are we a refinement - if not mclassdef.is_intro then return + if not mclassdef.is_intro then + # Set the default_init of the mclassdef with the intro default_init + mclassdef.default_init = mclassdef.mclass.intro.default_init + return + end # Look for the init in Object, or create it if mclassdef.mclass.name == "Object" and the_root_init_mmethod == null then @@ -173,15 +177,15 @@ redef class ModelBuilder if mpropdef.mproperty.is_root_init then assert defined_init == null defined_init = mpropdef - end - if mpropdef.name == "defaultinit" then + else if mpropdef.name == "defaultinit" then return end end if mclassdef.default_init != null then return - if not nclassdef isa AStdClassdef then return + # If the class is not AStdClassdef or it's an enum just return. No defaultinit is need. + if not nclassdef isa AStdClassdef or nclassdef.n_classkind isa AEnumClasskind then return # Collect undefined attributes var mparameters = new Array[MParameter] @@ -237,7 +241,8 @@ redef class ModelBuilder # Look for most-specific new-stype init definitions var spropdefs = new ArraySet[MMethodDef] - for x in mclassdef.in_hierarchy.direct_greaters do + + for x in mclassdef.get_direct_supermtype do var y = x.mclass.intro.default_init if y == null then continue if y.is_broken or y.msignature == null then return @@ -296,12 +301,28 @@ redef class ModelBuilder end end else if spropdefs.not_empty then + # Search for inherited manual defaultinit + var manual = null + for s in spropdefs do + if mpropdef2npropdef.has_key(s) then + self.toolcontext.info("{mclassdef} inherits a manual defaultinit {s}", 3) + manual = s + end + end # Search the longest-one and checks for conflict var longest = spropdefs.first if spropdefs.length > 1 then # part 1. find the longest list for spd in spropdefs do if spd.initializers.length > longest.initializers.length then longest = spd + + if spd != manual and manual != null then + self.toolcontext.info("{mclassdef} conflict between manual defaultinit {manual} and automatic defaultinit {spd}.", 3) + end + end + # conflict with manual autoinit? + if longest != manual and manual != null then + self.error(nclassdef, "Error: conflict between manual defaultinit {manual} and automatic defaultinit {longest}.") end # part 2. compare # Check for conflict in the order of initializers @@ -860,10 +881,10 @@ redef class AMethPropdef 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 + # Set the initializers with the mproperty. + # This point is need when a super class define this own default_init and inherited class use the default_init generated automaticlely. + mpropdef.initializers.add mprop + mpropdef.is_calling_init = true end set_doc(mpropdef, modelbuilder) @@ -1160,6 +1181,10 @@ redef class AAttrPropdef # Could be through `n_expr`, `n_block` or `is_lazy` var has_value = false + # The name of the attribute + # Note: The name of the attribute is in reality the name of the mreadpropdef + var name: String = n_id2.text is lazy + # The guard associated to a lazy attribute. # Because some engines does not have a working `isset`, # this additional attribute is used to guard the lazy initialization. @@ -1174,48 +1199,14 @@ redef class AAttrPropdef redef fun build_property(modelbuilder, mclassdef) do var mclass = mclassdef.mclass - var nid2 = n_id2 - var name = nid2.text var atabstract = self.get_single_annotation("abstract", modelbuilder) - if atabstract == null then - if not mclass.kind.need_init then - modelbuilder.error(self, "Error: attempt to define attribute `{name}` in the {mclass.kind} `{mclass}`.") - end - var mprop = new MAttribute(mclassdef, "_" + name, self.location, private_visibility) - var mpropdef = new MAttributeDef(mclassdef, mprop, self.location) - self.mpropdef = mpropdef - modelbuilder.mpropdef2npropdef[mpropdef] = self - end - - var readname = name - var mreadprop = modelbuilder.try_get_mproperty_by_name(nid2, mclassdef, readname).as(nullable MMethod) - if mreadprop == null then - var mvisibility = new_property_visibility(modelbuilder, mclassdef, self.n_visibility) - mreadprop = new MMethod(mclassdef, readname, self.location, mvisibility) - if not self.check_redef_keyword(modelbuilder, mclassdef, n_kwredef, false, mreadprop) then - mreadprop.is_broken = true - return - end - else - if mreadprop.is_broken then return - if not self.check_redef_keyword(modelbuilder, mclassdef, n_kwredef, true, mreadprop) then return - check_redef_property_visibility(modelbuilder, self.n_visibility, mreadprop) - end - mclassdef.mprop2npropdef[mreadprop] = self + if atabstract == null then build_attribute_property(modelbuilder, mclassdef) - var attr_mpropdef = mpropdef - if attr_mpropdef != null then - mreadprop.getter_for = attr_mpropdef.mproperty - attr_mpropdef.mproperty.getter = mreadprop - end + # Construction of the read property. If it's not correctly built just return. + if not build_read_property(modelbuilder, mclassdef) then return - var mreadpropdef = new MMethodDef(mclassdef, mreadprop, self.location) - self.mreadpropdef = mreadpropdef - modelbuilder.mpropdef2npropdef[mreadpropdef] = self - set_doc(mreadpropdef, modelbuilder) - if mpropdef != null then mpropdef.mdoc = mreadpropdef.mdoc if atabstract != null then mreadpropdef.is_abstract = true has_value = n_expr != null or n_block != null @@ -1238,29 +1229,8 @@ redef class AAttrPropdef end end - var atlazy = self.get_single_annotation("lazy", modelbuilder) - var atlateinit = self.get_single_annotation("lateinit", modelbuilder) - if atlazy != null or atlateinit != null then - if atlazy != null and atlateinit != null then - modelbuilder.error(atlazy, "Error: `lazy` incompatible with `lateinit`.") - return - end - if not has_value then - if atlazy != null then - modelbuilder.error(atlazy, "Error: `lazy` attributes need a value.") - else if atlateinit != null then - modelbuilder.error(atlateinit, "Error: `lateinit` attributes need a value.") - end - has_value = true - return - end - is_lazy = true - var mlazyprop = new MAttribute(mclassdef, "lazy _" + name, self.location, none_visibility) - mlazyprop.is_fictive = true - var mlazypropdef = new MAttributeDef(mclassdef, mlazyprop, self.location) - mlazypropdef.is_fictive = true - self.mlazypropdef = mlazypropdef - end + # Construction of the read property. If it's not correctly built just return. + if not build_lazy_property(modelbuilder, mclassdef) then return var atoptional = self.get_single_annotation("optional", modelbuilder) if atoptional != null then @@ -1283,6 +1253,88 @@ redef class AAttrPropdef modelbuilder.advice(self, "attr-in-refinement", "Warning: attributes in refinement need a value or `noautoinit`.") end + # Construction of the read property. If it's not correctly built just return. + if not build_write_property(modelbuilder, mclassdef, false) then return + + if atabstract != null then mwritepropdef.is_abstract = true + + var atautoinit = self.get_single_annotation("autoinit", modelbuilder) + if atautoinit != null then + if has_value then + modelbuilder.error(atautoinit, "Error: `autoinit` attributes cannot have an initial value.") + else if not mwritepropdef.is_intro then + modelbuilder.error(atautoinit, "Error: `autoinit` attributes cannot be set on redefinitions.") + else if not mclassdef.is_intro then + modelbuilder.error(atautoinit, "Error: `autoinit` attributes cannot be used in class refinements.") + else if atabstract == null then + modelbuilder.warning(atautoinit, "useless-autoinit", "Warning: superfluous `autoinit` on attribute.") + end + else if atabstract != null then + # By default, abstract attribute are not autoinit + noinit = true + end + end + + # Build the attribute property + fun build_attribute_property(modelbuilder: ModelBuilder, mclassdef: MClassDef) + do + var mclass = mclassdef.mclass + var attribute_name = "_" + name + + if not mclass.kind.need_init then + modelbuilder.error(self, "Error: attempt to define attribute `{name}` in the {mclass.kind} `{mclass}`.") + end + var mprop = new MAttribute(mclassdef, "_" + name, self.location, private_visibility) + var mpropdef = new MAttributeDef(mclassdef, mprop, self.location) + self.mpropdef = mpropdef + modelbuilder.mpropdef2npropdef[mpropdef] = self + end + + # Build the read method property to get the value of the attribute + # Return `true` if the property was correctly created else return `false`. + # Warning the signature of the property is not set. This step is done by `build_signature`. + fun build_read_property(modelbuilder: ModelBuilder, mclassdef: MClassDef): Bool + do + var mclass = mclassdef.mclass + + var readname = name + var mreadprop = modelbuilder.try_get_mproperty_by_name(self, mclassdef, readname).as(nullable MMethod) + if mreadprop == null then + var mvisibility = new_property_visibility(modelbuilder, mclassdef, self.n_visibility) + mreadprop = new MMethod(mclassdef, readname, self.location, mvisibility) + if not self.check_redef_keyword(modelbuilder, mclassdef, n_kwredef, false, mreadprop) then + mreadprop.is_broken = true + return false + end + else + if mreadprop.is_broken then return false + if not self.check_redef_keyword(modelbuilder, mclassdef, n_kwredef, true, mreadprop) then return false + check_redef_property_visibility(modelbuilder, self.n_visibility, mreadprop) + end + mclassdef.mprop2npropdef[mreadprop] = self + + var attr_mpropdef = mpropdef + if attr_mpropdef != null then + mreadprop.getter_for = attr_mpropdef.mproperty + attr_mpropdef.mproperty.getter = mreadprop + end + + var mreadpropdef = new MMethodDef(mclassdef, mreadprop, self.location) + self.mreadpropdef = mreadpropdef + modelbuilder.mpropdef2npropdef[mreadpropdef] = self + set_doc(mreadpropdef, modelbuilder) + if mpropdef != null then mpropdef.mdoc = mreadpropdef.mdoc + + return true + end + + # Build the write method property to set the attribute value + # Return `true` if the property was correctly created else return `false`. + # Warning the signature of the property is not set. + fun build_write_property(modelbuilder: ModelBuilder, mclassdef: MClassDef, is_same_visibility: Bool): Bool + do + var mclass = mclassdef.mclass + var writename = name + "=" var atwritable = self.get_single_annotation("writable", modelbuilder) if atwritable != null then @@ -1290,7 +1342,7 @@ redef class AAttrPropdef writename = atwritable.arg_as_id(modelbuilder) or else writename end end - var mwriteprop = modelbuilder.try_get_mproperty_by_name(nid2, mclassdef, writename).as(nullable MMethod) + var mwriteprop = modelbuilder.try_get_mproperty_by_name(self, mclassdef, writename).as(nullable MMethod) var nwkwredef: nullable Token = null if atwritable != null then nwkwredef = atwritable.n_kwredef if mwriteprop == null then @@ -1298,25 +1350,26 @@ redef class AAttrPropdef if atwritable != null then mvisibility = new_property_visibility(modelbuilder, mclassdef, atwritable.n_visibility) else - mvisibility = mreadprop.visibility + mvisibility = mreadpropdef.mproperty.visibility # By default, use protected visibility at most - if mvisibility > protected_visibility then mvisibility = protected_visibility + if mvisibility > protected_visibility and not is_same_visibility then mvisibility = protected_visibility end mwriteprop = new MMethod(mclassdef, writename, self.location, mvisibility) if not self.check_redef_keyword(modelbuilder, mclassdef, nwkwredef, false, mwriteprop) then mwriteprop.is_broken = true - return + return false end - mwriteprop.deprecation = mreadprop.deprecation + mwriteprop.deprecation = mreadpropdef.mproperty.deprecation else - if mwriteprop.is_broken then return - if not self.check_redef_keyword(modelbuilder, mclassdef, nwkwredef or else n_kwredef, true, mwriteprop) then return + if mwriteprop.is_broken then return false + if not self.check_redef_keyword(modelbuilder, mclassdef, nwkwredef or else n_kwredef, true, mwriteprop) then return false if atwritable != null then check_redef_property_visibility(modelbuilder, atwritable.n_visibility, mwriteprop) end end mclassdef.mprop2npropdef[mwriteprop] = self + var attr_mpropdef = mpropdef if attr_mpropdef != null then mwriteprop.setter_for = attr_mpropdef.mproperty attr_mpropdef.mproperty.setter = mwriteprop @@ -1326,23 +1379,35 @@ redef class AAttrPropdef self.mwritepropdef = mwritepropdef modelbuilder.mpropdef2npropdef[mwritepropdef] = self mwritepropdef.mdoc = mreadpropdef.mdoc - if atabstract != null then mwritepropdef.is_abstract = true - var atautoinit = self.get_single_annotation("autoinit", modelbuilder) - if atautoinit != null then - if has_value then - modelbuilder.error(atautoinit, "Error: `autoinit` attributes cannot have an initial value.") - else if not mwritepropdef.is_intro then - modelbuilder.error(atautoinit, "Error: `autoinit` attributes cannot be set on redefinitions.") - else if not mclassdef.is_intro then - modelbuilder.error(atautoinit, "Error: `autoinit` attributes cannot be used in class refinements.") - else if atabstract == null then - modelbuilder.warning(atautoinit, "useless-autoinit", "Warning: superfluous `autoinit` on attribute.") + return true + end + + # Build the lazy attribute property + # Return `true` if the property was correctly created else return `false`. + fun build_lazy_property(modelbuilder: ModelBuilder, mclassdef: MClassDef): Bool + do + var mclass = mclassdef.mclass + + var atlazy = self.get_single_annotation("lazy", modelbuilder) + var atlateinit = self.get_single_annotation("lateinit", modelbuilder) + if atlazy != null or atlateinit != null then + if atlazy != null and atlateinit != null then + modelbuilder.error(atlazy, "Error: `lazy` incompatible with `lateinit`.") + return false end - else if atabstract != null then - # By default, abstract attribute are not autoinit - noinit = true + if not has_value then + if atlazy != null then + modelbuilder.error(atlazy, "Error: `lazy` attributes need a value.") + else if atlateinit != null then + modelbuilder.error(atlateinit, "Error: `lateinit` attributes need a value.") + end + has_value = true + return false + end + create_lazy end + return true end redef fun build_signature(modelbuilder) @@ -1400,23 +1465,9 @@ redef class AAttrPropdef mpropdef.static_mtype = mtype end - do - var msignature = new MSignature(new Array[MParameter], mtype) - mreadpropdef.msignature = msignature - end + build_read_signature - var mwritepropdef = self.mwritepropdef - if mwritepropdef != null then - var mwritetype = mtype - if is_optional then - mwritetype = mwritetype.as_nullable - end - var name: String - name = n_id2.text - var mparameter = new MParameter(name, mwritetype, false) - var msignature = new MSignature([mparameter], null) - mwritepropdef.msignature = msignature - end + if self.mwritepropdef != null then build_write_signature var mlazypropdef = self.mlazypropdef if mlazypropdef != null then @@ -1425,6 +1476,91 @@ redef class AAttrPropdef check_repeated_types(modelbuilder) end + # Build the read method signature + # `except`: mreadpropdef != null + # `expect`: mtype != null + fun build_read_signature + is + expect(mreadpropdef != null and mtype != null) + do + var msignature = new MSignature(new Array[MParameter], mtype) + mreadpropdef.msignature = msignature + end + + # Build the write method signature + # `except`: mwritepropdef != null + # `expect`: mtype != null + fun build_write_signature + is + expect(mwritepropdef != null and mtype != null) + do + var mwritetype = mtype.as(not null) + if is_optional then + mwritetype = mwritetype.as_nullable + end + var mparameter = new MParameter(name, mwritetype, false) + var msignature = new MSignature([mparameter], null) + mwritepropdef.msignature = msignature + end + + # Create a new setter for the attribute. + # + # `modelbuilder`: It's used to link the new `mwritepropdef` and `self` + # `visibility`: Is the setter has the same visibilty of the `mreadpropdef`. + # If `not is_same_visibility and mreadpropdef.mproperty.visibility > protected_visibility` the `mwritepropdef` visibility will be set to protected. + fun create_setter(modelbuilder: ModelBuilder, is_same_visibility: nullable Bool): AAttrPropdef + is + expect(mreadpropdef != null) # Use to define the visibility, the mclassdef and the doc of the `mwritepropdef` + do + if mwritepropdef != null then return self # Self already has a `mwritepropdef` + var same_visibility = false + if is_same_visibility != null then same_visibility = is_same_visibility + + self.build_write_property(modelbuilder, mreadpropdef.mclassdef, same_visibility) + self.build_write_signature + return self + end + + # Set the default `self` value + # + # `expr`: Represents the default value of the attribute. If `expr isa ABlockExpr` `self.n_block` will be set. + fun define_default(expr: AExpr): AAttrPropdef + do + self.has_value = true + if expr isa ABlockExpr then + self.n_block = expr + else + self.n_expr = expr + end + return self + end + + # Set `self` as optional + fun define_as_optional: AAttrPropdef + is + expect(has_value) + do + is_optional = true + return self + end + + # Create the lazy attribute. + # + # see `mlazypropdef` for more information about this property. + fun create_lazy: AAttrPropdef + is + expect(has_value and mpropdef != null) # The only way to get a null `mpropdef` is when the attribute is defined as `abstract`. But if the attribute has a value, it cannot be abstract. + do + if self.mlazypropdef != null then return self # Self already has a `mlazypropdef` + is_lazy = true + var mlazyprop = new MAttribute(mpropdef.mclassdef, "lazy _" + name, self.location, none_visibility) + mlazyprop.is_fictive = true + var mlazypropdef = new MAttributeDef(mpropdef.mclassdef, mlazyprop, self.location) + mlazypropdef.is_fictive = true + self.mlazypropdef = mlazypropdef + return self + end + # Detect the static type from the value assigned to the attribute `self` # # Return the static type if it can be safely inferred.