X-Git-Url: http://nitlanguage.org diff --git a/src/modelize/modelize_property.nit b/src/modelize/modelize_property.nit index 0a948d2..aadfb5c 100644 --- a/src/modelize/modelize_property.nit +++ b/src/modelize/modelize_property.nit @@ -110,6 +110,7 @@ redef class ModelBuilder if mpropdef.bound == null then continue if not check_virtual_types_circularity(npropdef, mpropdef.mproperty, mclassdef.bound_mtype, mclassdef.mmodule) then # Invalidate the bound + mpropdef.is_broken = true mpropdef.bound = mclassdef.mmodule.model.null_type end end @@ -158,9 +159,6 @@ redef class ModelBuilder 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 @@ -182,21 +180,14 @@ redef class ModelBuilder var initializers = new Array[MProperty] for npropdef in nclassdef.n_propdefs do if npropdef isa AMethPropdef then + if not npropdef.is_autoinit then continue # Skip non tagged autoinit if npropdef.mpropdef == null then return # Skip broken method - 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, ret_type isa MNullableType) + var mparameter = new MParameter(param.name, ret_type, false) mparameters.add(mparameter) end initializers.add(npropdef.mpropdef.mproperty) @@ -218,7 +209,7 @@ redef class ModelBuilder 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) + var mparameter = new MParameter(paramname, ret_type, false) mparameters.add(mparameter) var msetter = npropdef.mwritepropdef if msetter == null then @@ -287,13 +278,7 @@ redef class ModelBuilder if pd isa MMethodDef then # Get the signature resolved for the current receiver var sig = pd.msignature.resolve_for(mclassdef.mclass.mclass_type, mclassdef.bound_mtype, mclassdef.mmodule, false) - # Because the last parameter of setters is never default, try to default them for the autoinit. - for param in sig.mparameters do - if not param.is_default and param.mtype isa MNullableType then - param = new MParameter(param.name, param.mtype, param.is_vararg, true) - end - mparameters.add(param) - end + mparameters.add_all(sig.mparameters) else # TODO attributes? abort @@ -315,7 +300,12 @@ redef class ModelBuilder 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(", ")})") + var proposal = new ArraySet[MProperty] + for spd2 in spropdefs do + proposal.add_all spd2.initializers + end + proposal.add_all initializers + self.error(nclassdef, "Error: cannot generate automatic init for class {mclassdef.mclass}. Conflict in the order in inherited initializers {spd}({spd.initializers.join(", ")}) and {longest}({longest.initializers.join(", ")}). Use `autoinit` to order initializers. eg `autoinit {proposal.join(", ")}`") # TODO: invalidate the initializer to avoid more errors return end @@ -384,7 +374,7 @@ redef class ModelBuilder mtype = mtype.undecorate if mtype isa MClassType then vis_type = mtype.mclass.visibility - mmodule_type = mtype.mclass.intro.mmodule + mmodule_type = mtype.mclass.intro_mmodule else if mtype isa MVirtualType then vis_type = mtype.mproperty.visibility mmodule_type = mtype.mproperty.intro_mclassdef.mmodule @@ -640,12 +630,12 @@ redef class APropdef return false end - # Check for full-name conflicts in the project. - # A public property should have a unique qualified name `project::class::prop`. + # Check for full-name conflicts in the package. + # A public property should have a unique qualified name `package::class::prop`. if mprop.intro_mclassdef.mmodule.mgroup != null and mprop.visibility >= protected_visibility then var others = modelbuilder.model.get_mproperties_by_name(mprop.name) if others != null then for other in others do - if other != mprop and other.intro_mclassdef.mmodule.mgroup != null and other.intro_mclassdef.mmodule.mgroup.mproject == mprop.intro_mclassdef.mmodule.mgroup.mproject and other.intro_mclassdef.mclass.name == mprop.intro_mclassdef.mclass.name and other.visibility >= protected_visibility then + if other != mprop and other.intro_mclassdef.mmodule.mgroup != null and other.intro_mclassdef.mmodule.mgroup.mpackage == mprop.intro_mclassdef.mmodule.mgroup.mpackage and other.intro_mclassdef.mclass.name == mprop.intro_mclassdef.mclass.name and other.visibility >= protected_visibility then modelbuilder.advice(self, "full-name-conflict", "Warning: A property named `{other.full_name}` is already defined in module `{other.intro_mclassdef.mmodule}` for the class `{other.intro_mclassdef.mclass.name}`.") break end @@ -731,6 +721,7 @@ redef class ASignature res = false end end + if not res then is_broken = true return res end end @@ -743,6 +734,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 @@ -840,8 +833,14 @@ redef class AMethPropdef mprop.is_new = n_kwnew != null if mprop.is_new then mclassdef.mclass.has_new_factory = true if name == "sys" then mprop.is_toplevel = true # special case for sys allowed in `new` factories - self.check_redef_keyword(modelbuilder, mclassdef, n_kwredef, false, mprop) + if not self.check_redef_keyword(modelbuilder, mclassdef, n_kwredef, false, mprop) then + mprop.is_broken = true + return + end else + if mprop.is_broken then + return + end if not self.check_redef_keyword(modelbuilder, mclassdef, n_kwredef, not self isa AMainMethPropdef, mprop) then return check_redef_property_visibility(modelbuilder, self.n_visibility, mprop) end @@ -850,7 +849,10 @@ redef class AMethPropdef if is_init then for p, n in mclassdef.mprop2npropdef do if p != mprop and p isa MMethod and p.name == name then - check_redef_keyword(modelbuilder, mclassdef, n_kwredef, false, p) + if not check_redef_keyword(modelbuilder, mclassdef, n_kwredef, false, p) then + mprop.is_broken = true + return + end break end end @@ -957,13 +959,7 @@ redef class AMethPropdef var mparameters = new Array[MParameter] for i in [0..param_names.length[ do - var is_default = false - if vararg_rank == -1 and param_types[i] isa MNullableType then - if i < param_names.length-1 or accept_special_last_parameter then - is_default = true - end - end - var mparameter = new MParameter(param_names[i], param_types[i], i == vararg_rank, is_default) + var mparameter = new MParameter(param_names[i], param_types[i], i == vararg_rank) if nsig != null then nsig.n_params[i].mparameter = mparameter mparameters.add(mparameter) end @@ -988,6 +984,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) @@ -997,13 +1004,14 @@ redef class AMethPropdef var mclassdef = mpropdef.mclassdef var mmodule = mclassdef.mmodule var nsig = self.n_signature - var mysignature = self.mpropdef.msignature + var mysignature = mpropdef.msignature if mysignature == null then return # Error thus skiped # Check if nsig != null then if not nsig.check_signature(modelbuilder, mclassdef) then - self.mpropdef.msignature = null # invalidate + mpropdef.msignature = null # invalidate + mpropdef.is_broken = true return # Forward error end end @@ -1018,7 +1026,8 @@ redef class AMethPropdef var ret_type = mysignature.return_mtype if ret_type != null and precursor_ret_type == null then modelbuilder.error(nsig.n_type.as(not null), "Redef Error: `{mpropdef.mproperty}` is a procedure, not a function.") - self.mpropdef.msignature = null + mpropdef.msignature = null + mpropdef.is_broken = true return end @@ -1030,7 +1039,8 @@ redef class AMethPropdef var node = nsig.n_params[i] if not modelbuilder.check_sametype(node, mmodule, mclassdef.bound_mtype, myt, prt) then modelbuilder.error(node, "Redef Error: expected `{prt}` for parameter `{mysignature.mparameters[i].name}'; got `{myt}`.") - self.mpropdef.msignature = null + mpropdef.msignature = null + mpropdef.is_broken = true end end end @@ -1043,7 +1053,8 @@ redef class AMethPropdef ret_type = precursor_ret_type else if not modelbuilder.check_subtype(node, mmodule, mclassdef.bound_mtype, ret_type, precursor_ret_type) then modelbuilder.error(node, "Redef Error: expected `{precursor_ret_type}` for return type; got `{ret_type}`.") - self.mpropdef.msignature = null + mpropdef.msignature = null + mpropdef.is_broken = true end end end @@ -1135,6 +1146,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 @@ -1209,8 +1224,7 @@ redef class AAttrPropdef return end if atabstract != null then - modelbuilder.error(atnoinit, "Error: `noautoinit` attributes cannot be abstract.") - return + modelbuilder.warning(atnoinit, "useless-noautoinit", "Warning: superfluous `noautoinit` on abstract attribute.") end end @@ -1245,6 +1259,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 @@ -1260,7 +1278,9 @@ redef class AAttrPropdef if atwritable != null then mvisibility = new_property_visibility(modelbuilder, mclassdef, atwritable.n_visibility) else - mvisibility = private_visibility + mvisibility = mreadprop.visibility + # By default, use protected visibility at most + if mvisibility > protected_visibility then mvisibility = protected_visibility end mwriteprop = new MMethod(mclassdef, writename, mvisibility) if not self.check_redef_keyword(modelbuilder, mclassdef, nwkwredef, false, mwriteprop) then return @@ -1278,6 +1298,22 @@ redef class AAttrPropdef 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.") + end + else if atabstract != null then + # By default, abstract attribute are not autoinit + noinit = true + end end redef fun build_signature(modelbuilder) @@ -1314,11 +1350,26 @@ redef class AAttrPropdef if nexpr != null then if nexpr isa ANewExpr then mtype = modelbuilder.resolve_mtype_unchecked(mmodule, mclassdef, nexpr.n_type, true) - 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") + else if nexpr isa AIntegerExpr then + var cla: nullable MClass = null + if nexpr.value isa Int then + cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Int") + else if nexpr.value isa Byte then + cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Byte") + else if nexpr.value isa Int8 then + cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Int8") + else if nexpr.value isa Int16 then + cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Int16") + else if nexpr.value isa UInt16 then + cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "UInt16") + else if nexpr.value isa Int32 then + cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Int32") + else if nexpr.value isa UInt32 then + cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "UInt32") + else + # Should not happen, and should be updated as new types are added + abort + end 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") @@ -1355,6 +1406,8 @@ redef class AAttrPropdef return end + self.mtype = mtype + if mpropdef != null then mpropdef.static_mtype = mtype end @@ -1368,7 +1421,7 @@ redef class AAttrPropdef if mwritepropdef != null then var name: String name = n_id2.text - var mparameter = new MParameter(name, mtype, false, false) + var mparameter = new MParameter(name, mtype, false) var msignature = new MSignature([mparameter], null) mwritepropdef.msignature = msignature end @@ -1385,7 +1438,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