X-Git-Url: http://nitlanguage.org diff --git a/src/modelize/modelize_property.nit b/src/modelize/modelize_property.nit index 092acad..4633b3f 100644 --- a/src/modelize/modelize_property.nit +++ b/src/modelize/modelize_property.nit @@ -182,18 +182,11 @@ redef class ModelBuilder 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 - + if not npropdef.is_autoinit then continue # Skip non tagged autoinit + if npropdef.mpropdef == null then return # Skip broken method 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, ret_type isa MNullableType) @@ -203,25 +196,26 @@ redef class ModelBuilder npropdef.mpropdef.mproperty.is_autoinit = true end if npropdef isa AAttrPropdef then - if npropdef.mpropdef == null then return # Skip broken attribute + var mreadpropdef = npropdef.mreadpropdef + if mreadpropdef == null or mreadpropdef.msignature == null then return # Skip broken attribute if npropdef.noinit then continue # Skip noinit attribute - var atautoinit = npropdef.get_single_annotation("autoinit", self) - if atautoinit != null then - # For autoinit attributes, call the reader to force + var atlateinit = npropdef.get_single_annotation("lateinit", self) + if atlateinit != null then + # For lateinit attributes, call the reader to force # the lazy initialization of the attribute. - initializers.add(npropdef.mreadpropdef.mproperty) - npropdef.mreadpropdef.mproperty.is_autoinit = true + initializers.add(mreadpropdef.mproperty) + mreadpropdef.mproperty.is_autoinit = true continue end if npropdef.has_value then continue - var paramname = npropdef.mpropdef.mproperty.name.substring_from(1) - var ret_type = npropdef.mpropdef.static_mtype + var paramname = mreadpropdef.mproperty.name + var ret_type = mreadpropdef.msignature.return_mtype if ret_type == null then return var mparameter = new MParameter(paramname, ret_type, false, ret_type isa MNullableType) mparameters.add(mparameter) var msetter = npropdef.mwritepropdef if msetter == null then - # No setter, it is a old-style attribute, so just add it + # No setter, it is a readonly attribute, so just add it initializers.add(npropdef.mpropdef.mproperty) npropdef.mpropdef.mproperty.is_autoinit = true else @@ -298,25 +292,19 @@ redef class ModelBuilder abort end end - else if noautoinit != null then - if initializers.is_empty then - warning(noautoinit, "useless-noautoinit", "Warning: the list of autoinit is already empty.") - end - # Just clear initializers - mparameters.clear - initializers.clear else # 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 + # Check for conflict in the order of initializers + # Each initializer list must me a prefix of the longest list + # If `noautoinit` is set, just ignore conflicts + if noautoinit == null then for spd in spropdefs do var i = 0 for p in spd.initializers do if p != longest.initializers[i] then @@ -329,17 +317,27 @@ redef class ModelBuilder 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) - mclassdef.mclass.root_init = longest - return - end + if noautoinit != null then + # If there is local or inherited initializers, then complain. + if initializers.is_empty and longest.initializers.is_empty then + warning(noautoinit, "useless-noautoinit", "Warning: the list of autoinit is already empty.") + end + # Just clear initializers + 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 - initializers.prepend longest.initializers + # 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 end end @@ -655,6 +653,8 @@ redef class APropdef return true end + # Checks for useless type in redef signatures. + private fun check_repeated_types(modelbuilder: ModelBuilder) do end end redef class ASignature @@ -736,6 +736,8 @@ end redef class AMethPropdef redef type MPROPDEF: MMethodDef + # Is the method annotated `autoinit`? + var is_autoinit = false # Can self be used as a root init? private fun look_like_a_root_init(modelbuilder: ModelBuilder, mclassdef: MClassDef): Bool @@ -981,6 +983,17 @@ redef class AMethPropdef # Check annotations var at = self.get_single_annotation("lazy", modelbuilder) if at != null then modelbuilder.error(at, "Syntax Error: `lazy` must be used on attributes.") + + var atautoinit = self.get_single_annotation("autoinit", modelbuilder) + if atautoinit != null then + if not mpropdef.is_intro then + modelbuilder.error(atautoinit, "Error: `autoinit` cannot be set on redefinitions.") + else if not mclassdef.is_intro then + modelbuilder.error(atautoinit, "Error: `autoinit` cannot be used in class refinements.") + else + self.is_autoinit = true + end + end end redef fun check_signature(modelbuilder) @@ -1050,6 +1063,28 @@ redef class AMethPropdef var nt = nsig.n_type if nt != null then modelbuilder.check_visibility(nt, nt.mtype.as(not null), mpropdef) end + check_repeated_types(modelbuilder) + end + + # For parameters, type is always useless in a redef. + # For return type, type is useless if not covariant with introduction. + redef fun check_repeated_types(modelbuilder) do + if mpropdef.is_intro or n_signature == null then return + # check params + for param in n_signature.n_params do + if param.n_type != null then + modelbuilder.advice(param.n_type, "useless-signature", "Warning: useless type repetition on parameter `{param.n_id.text}` for redefined method `{mpropdef.name}`") + end + end + # get intro + var intro = mpropdef.mproperty.intro + var n_intro = modelbuilder.mpropdef2npropdef.get_or_null(intro) + if n_intro == null or not n_intro isa AMethPropdef then return + # check return type + var ret_type = n_signature.ret_type + if ret_type != null and ret_type == n_intro.n_signature.ret_type then + modelbuilder.advice(n_signature.n_type, "useless-signature", "Warning: useless return type repetition for redefined method `{mpropdef.name}`") + end end end @@ -1106,6 +1141,10 @@ end redef class AAttrPropdef redef type MPROPDEF: MAttributeDef + # The static type of the property (declared, inferred or inherited) + # This attribute is also used to check if the property was analyzed and is valid. + var mtype: nullable MType + # Is the node tagged `noinit`? var noinit = false @@ -1186,17 +1225,17 @@ redef class AAttrPropdef end var atlazy = self.get_single_annotation("lazy", modelbuilder) - var atautoinit = self.get_single_annotation("autoinit", modelbuilder) - if atlazy != null or atautoinit != null then - if atlazy != null and atautoinit != null then - modelbuilder.error(atlazy, "Error: `lazy` incompatible with `autoinit`.") + 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 atautoinit != null then - modelbuilder.error(atautoinit, "Error: `autoinit` attributes need a value.") + else if atlateinit != null then + modelbuilder.error(atlateinit, "Error: `lateinit` attributes need a value.") end has_value = true return @@ -1216,6 +1255,10 @@ redef class AAttrPropdef return end + if not mclassdef.is_intro and not has_value and not noinit then + modelbuilder.advice(self, "attr-in-refinement", "Warning: attributes in refinement need a value or `noautoinit`.") + end + var writename = name + "=" var atwritable = self.get_single_annotation("writable", modelbuilder) if atwritable != null then @@ -1288,6 +1331,9 @@ redef class AAttrPropdef else if nexpr isa AIntExpr then var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Int") if cla != null then mtype = cla.mclass_type + else if nexpr isa AByteExpr then + var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Byte") + if cla != null then mtype = cla.mclass_type else if nexpr isa AFloatExpr then var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Float") if cla != null then mtype = cla.mclass_type @@ -1323,6 +1369,8 @@ redef class AAttrPropdef return end + self.mtype = mtype + if mpropdef != null then mpropdef.static_mtype = mtype end @@ -1345,6 +1393,7 @@ redef class AAttrPropdef if mlazypropdef != null then mlazypropdef.static_mtype = modelbuilder.model.get_mclasses_by_name("Bool").first.mclass_type end + check_repeated_types(modelbuilder) end redef fun check_signature(modelbuilder) @@ -1352,7 +1401,7 @@ redef class AAttrPropdef var mpropdef = self.mpropdef if mpropdef == null then return # Error thus skipped var ntype = self.n_type - var mtype = self.mpropdef.static_mtype + var mtype = self.mtype if mtype == null then return # Error thus skipped var mclassdef = mpropdef.mclassdef @@ -1449,6 +1498,25 @@ redef class AAttrPropdef end end end + + # Type is useless if the attribute type is the same thant the intro. + redef fun check_repeated_types(modelbuilder) do + if mreadpropdef.is_intro or n_type == null then return + # get intro + var intro = mreadpropdef.mproperty.intro + var n_intro = modelbuilder.mpropdef2npropdef.get_or_null(intro) + if n_intro == null then return + # get intro type + var ntype = null + if n_intro isa AMethPropdef then + ntype = n_intro.n_signature.ret_type + else if n_intro isa AAttrPropdef and n_intro.n_type != null then + ntype = n_intro.n_type.mtype + end + # check + if ntype ==null or ntype != n_type.mtype then return + modelbuilder.advice(n_type, "useless-signature", "Warning: useless type repetition on redefined attribute `{mpropdef.name}`") + end end redef class ATypePropdef