X-Git-Url: http://nitlanguage.org diff --git a/src/modelize/modelize_property.nit b/src/modelize/modelize_property.nit index be862c6..5ba3196 100644 --- a/src/modelize/modelize_property.nit +++ b/src/modelize/modelize_property.nit @@ -110,7 +110,8 @@ 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.bound = mclassdef.mmodule.model.null_type + mpropdef.is_broken = true + mpropdef.bound = new MErrorType(mclassdef.mmodule.model) end end for npropdef in nclassdef2.n_propdefs do @@ -144,7 +145,7 @@ redef class ModelBuilder # 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) + var mprop = new MMethod(mclassdef, "init", nclassdef.location, mclassdef.mclass.visibility) mprop.is_root_init = true var mpropdef = new MMethodDef(mclassdef, mprop, nclassdef.location) var mparameters = new Array[MParameter] @@ -152,7 +153,6 @@ redef class ModelBuilder 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 @@ -180,21 +180,20 @@ redef class ModelBuilder 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 sig = npropdef.mpropdef.msignature + var mpropdef = npropdef.mpropdef + if mpropdef == null then return # Skip broken method + var sig = mpropdef.msignature if sig == null then continue # Skip broken method - for param in sig.mparameters do - var ret_type = param.mtype - var mparameter = new MParameter(param.name, ret_type, false, ret_type isa MNullableType) - mparameters.add(mparameter) - end - initializers.add(npropdef.mpropdef.mproperty) - npropdef.mpropdef.mproperty.is_autoinit = true + mparameters.add_all sig.mparameters + initializers.add(mpropdef.mproperty) + mpropdef.mproperty.is_autoinit = true end if npropdef isa AAttrPropdef then var mreadpropdef = npropdef.mreadpropdef - if mreadpropdef == null or mreadpropdef.msignature == null then return # Skip broken attribute + if mreadpropdef == null then return # Skip broken attribute + var msignature = mreadpropdef.msignature + if msignature == null then return # Skip broken attribute if npropdef.noinit then continue # Skip noinit attribute var atlateinit = npropdef.get_single_annotation("lateinit", self) if atlateinit != null then @@ -204,25 +203,28 @@ redef class ModelBuilder mreadpropdef.mproperty.is_autoinit = true continue end - if npropdef.has_value then continue - 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) + if npropdef.has_value and not npropdef.is_optional then continue var msetter = npropdef.mwritepropdef if msetter == null then # No setter, it is a readonly attribute, so just add it + var paramname = mreadpropdef.mproperty.name + var ret_type = msignature.return_mtype + if ret_type == null then return + var mparameter = new MParameter(paramname, ret_type, false) + mparameters.add(mparameter) + initializers.add(npropdef.mpropdef.mproperty) npropdef.mpropdef.mproperty.is_autoinit = true else # Add the setter to the list + mparameters.add_all msetter.msignature.mparameters initializers.add(msetter.mproperty) msetter.mproperty.is_autoinit = true end end end + var the_root_init_mmethod = self.the_root_init_mmethod if the_root_init_mmethod == null then return # Look for most-specific new-stype init definitions @@ -277,13 +279,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 @@ -354,14 +350,13 @@ redef class ModelBuilder end # Else create the local implicit basic init definition - var mprop = the_root_init_mmethod.as(not null) + var mprop = the_root_init_mmethod var mpropdef = new MMethodDef(mclassdef, mprop, nclassdef.location) mpropdef.has_supercall = true mpropdef.initializers.add_all(initializers) var msignature = new MSignature(mparameters, null) 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) mclassdef.mclass.root_init = mpropdef end @@ -379,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 @@ -387,6 +382,10 @@ redef class ModelBuilder # nothing, always visible else if mtype isa MNullType then # nothing to do. + else if mtype isa MBottomType then + # nothing to do. + else if mtype isa MErrorType then + # nothing to do. else node.debug "Unexpected type {mtype}" abort @@ -446,8 +445,7 @@ redef class ModelBuilder var vt = t.mproperty # Because `vt` is possibly unchecked, we have to do the bound-lookup manually var defs = vt.lookup_definitions(mmodule, recv) - # TODO something to manage correctly bound conflicts - assert not defs.is_empty + if defs.is_empty then return false nexts = new Array[MType] for d in defs do var next = defs.first.bound @@ -492,9 +490,6 @@ end redef class AClassdef # Marker used in `ModelBuilder::build_properties` private 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 @@ -596,7 +591,7 @@ redef class APropdef var mdoc = ndoc.to_mdoc mpropdef.mdoc = mdoc mdoc.original_mentity = mpropdef - else if mpropdef.is_intro and mpropdef.mproperty.visibility >= protected_visibility then + else if mpropdef.is_intro and mpropdef.mproperty.visibility >= protected_visibility and mpropdef.name != "new" then modelbuilder.advice(self, "missing-doc", "Documentation warning: Undocumented property `{mpropdef.mproperty}`") end @@ -635,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 @@ -726,6 +721,7 @@ redef class ASignature res = false end end + if not res then is_broken = true return res end end @@ -828,7 +824,7 @@ redef class AMethPropdef end if mprop == null then var mvisibility = new_property_visibility(modelbuilder, mclassdef, self.n_visibility) - mprop = new MMethod(mclassdef, name, mvisibility) + mprop = new MMethod(mclassdef, name, self.location, mvisibility) if look_like_a_root_init and modelbuilder.the_root_init_mmethod == null then modelbuilder.the_root_init_mmethod = mprop mprop.is_root_init = true @@ -837,8 +833,12 @@ 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 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 @@ -847,7 +847,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 @@ -954,13 +957,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 @@ -1005,13 +1002,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 @@ -1025,8 +1023,9 @@ redef class AMethPropdef var precursor_ret_type = msignature.return_mtype 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 + modelbuilder.error(nsig.n_type, "Redef Error: `{mpropdef.mproperty}` is a procedure, not a function.") + mpropdef.msignature = null + mpropdef.is_broken = true return end @@ -1038,7 +1037,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 @@ -1051,12 +1051,13 @@ 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 - if mysignature.arity > 0 then + if nsig != null then # Check parameters visibility for i in [0..mysignature.arity[ do var nt = nsig.n_params[i].n_type @@ -1071,6 +1072,8 @@ redef class AMethPropdef # 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 + var mpropdef = self.mpropdef + if mpropdef == null then return if mpropdef.is_intro or n_signature == null then return # check params for param in n_signature.n_params do @@ -1153,6 +1156,9 @@ redef class AAttrPropdef # Is the node tagged lazy? var is_lazy = false + # Is the node tagged optional? + var is_optional = false + # Has the node a default value? # Could be through `n_expr` or `n_block` var has_value = false @@ -1180,7 +1186,7 @@ redef class AAttrPropdef modelbuilder.error(self, "Error: attempt to define attribute `{name}` in the {mclass.kind} `{mclass}`.") end - var mprop = new MAttribute(mclassdef, "_" + name, private_visibility) + 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 @@ -1190,9 +1196,13 @@ redef class AAttrPropdef 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, mvisibility) - if not self.check_redef_keyword(modelbuilder, mclassdef, n_kwredef, false, mreadprop) then return + 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 @@ -1242,11 +1252,21 @@ redef class AAttrPropdef return end is_lazy = true - var mlazyprop = new MAttribute(mclassdef, "lazy _" + name, none_visibility) + 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 + var atoptional = self.get_single_annotation("optional", modelbuilder) + if atoptional != null then + if not has_value then + modelbuilder.error(atoptional, "Error: `optional` attributes need a default value.") + end + is_optional = true + end + var atreadonly = self.get_single_annotation("readonly", modelbuilder) if atreadonly != null then if not has_value then @@ -1275,12 +1295,18 @@ 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, self.location, mvisibility) + if not self.check_redef_keyword(modelbuilder, mclassdef, nwkwredef, false, mwriteprop) then + mwriteprop.is_broken = true + return end - mwriteprop = new MMethod(mclassdef, writename, mvisibility) - if not self.check_redef_keyword(modelbuilder, mclassdef, nwkwredef, false, mwriteprop) then return mwriteprop.deprecation = mreadprop.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 atwritable != null then check_redef_property_visibility(modelbuilder, atwritable.n_visibility, mwriteprop) @@ -1345,17 +1371,41 @@ 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 AAsCastExpr then + mtype = modelbuilder.resolve_mtype_unchecked(mmodule, mclassdef, nexpr.n_type, true) + 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") if cla != null then mtype = cla.mclass_type else if nexpr isa ACharExpr then - var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Char") + var cla: nullable MClass + if nexpr.is_ascii then + cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Byte") + else if nexpr.is_code_point then + cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Int") + else + cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Char") + end if cla != null then mtype = cla.mclass_type else if nexpr isa ABoolExpr then var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Bool") @@ -1364,7 +1414,16 @@ redef class AAttrPropdef var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "String") if cla != null then mtype = cla.mclass_type else if nexpr isa AStringFormExpr then - var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "String") + var cla: nullable MClass + if nexpr.is_bytestring then + cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Bytes") + else if nexpr.is_re then + cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Regex") + else if nexpr.is_string then + cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "String") + else + abort + end if cla != null then mtype = cla.mclass_type else modelbuilder.error(self, "Error: untyped attribute `{mreadpropdef}`. Implicit typing allowed only for literals and new.") @@ -1399,16 +1458,20 @@ redef class AAttrPropdef 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, mtype, false, false) + var mparameter = new MParameter(name, mwritetype, false) var msignature = new MSignature([mparameter], null) mwritepropdef.msignature = msignature end var mlazypropdef = self.mlazypropdef if mlazypropdef != null then - mlazypropdef.static_mtype = modelbuilder.model.get_mclasses_by_name("Bool").first.mclass_type + mlazypropdef.static_mtype = mmodule.bool_type end check_repeated_types(modelbuilder) end @@ -1518,6 +1581,8 @@ redef class AAttrPropdef # Type is useless if the attribute type is the same thant the intro. redef fun check_repeated_types(modelbuilder) do + var mreadpropdef = self.mreadpropdef + if mreadpropdef == null then return if mreadpropdef.is_intro or n_type == null then return # get intro var intro = mreadpropdef.mproperty.intro @@ -1531,7 +1596,7 @@ redef class AAttrPropdef ntype = n_intro.n_type.mtype end # check - if ntype ==null or ntype != n_type.mtype then return + if ntype == null or ntype != n_type.mtype or mpropdef == null then return modelbuilder.advice(n_type, "useless-signature", "Warning: useless type repetition on redefined attribute `{mpropdef.name}`") end end @@ -1541,31 +1606,33 @@ redef class ATypePropdef redef fun build_property(modelbuilder, mclassdef) do - var name = self.n_id.text - var mprop = modelbuilder.try_get_mproperty_by_name(self.n_id, mclassdef, name) + var name = self.n_qid.n_id.text + var mprop = modelbuilder.try_get_mproperty_by_name(self.n_qid, mclassdef, name) if mprop == null then var mvisibility = new_property_visibility(modelbuilder, mclassdef, self.n_visibility) - mprop = new MVirtualTypeProp(mclassdef, name, mvisibility) + mprop = new MVirtualTypeProp(mclassdef, name, self.location, mvisibility) for c in name.chars do if c >= 'a' and c<= 'z' then - modelbuilder.warning(n_id, "bad-type-name", "Warning: lowercase in the virtual type `{name}`.") + modelbuilder.warning(n_qid, "bad-type-name", "Warning: lowercase in the virtual type `{name}`.") break end - if not self.check_redef_keyword(modelbuilder, mclassdef, self.n_kwredef, false, mprop) then return else - if not self.check_redef_keyword(modelbuilder, mclassdef, self.n_kwredef, true, mprop) then return + if mprop.is_broken then return assert mprop isa MVirtualTypeProp check_redef_property_visibility(modelbuilder, self.n_visibility, mprop) end - mclassdef.mprop2npropdef[mprop] = self var mpropdef = new MVirtualTypeDef(mclassdef, mprop, self.location) self.mpropdef = mpropdef - modelbuilder.mpropdef2npropdef[mpropdef] = self if mpropdef.is_intro then modelbuilder.toolcontext.info("{mpropdef} introduces new type {mprop.full_name}", 4) else modelbuilder.toolcontext.info("{mpropdef} redefines type {mprop.full_name}", 4) end + if not self.check_redef_keyword(modelbuilder, mclassdef, self.n_kwredef, not mpropdef.is_intro, mprop) then + mpropdef.is_broken =true + end + mclassdef.mprop2npropdef[mprop] = self + modelbuilder.mpropdef2npropdef[mpropdef] = self set_doc(mpropdef, modelbuilder) var atfixed = get_single_annotation("fixed", modelbuilder) @@ -1613,7 +1680,7 @@ redef class ATypePropdef # Check redefinitions for p in mpropdef.mproperty.lookup_super_definitions(mmodule, anchor) do var supbound = p.bound - if supbound == null then break # broken super bound, skip error + if supbound == null or supbound isa MBottomType or p.is_broken then break # broken super bound, skip error if p.is_fixed then modelbuilder.error(self, "Redef Error: virtual type `{mpropdef.mproperty}` is fixed in super-class `{p.mclassdef.mclass}`.") break