X-Git-Url: http://nitlanguage.org diff --git a/src/modelize/modelize_property.nit b/src/modelize/modelize_property.nit index 3ecbdd5..abce092 100644 --- a/src/modelize/modelize_property.nit +++ b/src/modelize/modelize_property.nit @@ -55,10 +55,9 @@ redef class ModelBuilder toolcontext.run_phases_on_npropdef(res) return res end - if mpropdef isa MMethodDef and mpropdef.mproperty.is_root_init then - res = mclassdef2nclassdef.get_or_null(mpropdef.mclassdef) - if res != null then return res - end + # Fall back to the class node if any. + res = mclassdef2nclassdef.get_or_null(mpropdef.mclassdef) + if res != null then return res return null end @@ -110,7 +109,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 MBottomType(mclassdef.mmodule.model) end end for npropdef in nclassdef2.n_propdefs do @@ -150,17 +150,11 @@ redef class ModelBuilder var mparameters = new Array[MParameter] var msignature = new MSignature(mparameters, null) 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 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 @@ -169,12 +163,16 @@ redef class ModelBuilder if mpropdef.mproperty.is_root_init then assert defined_init == null defined_init = mpropdef - else if mpropdef.mproperty.name == "init" then + else if mpropdef.mproperty.name == "autoinit" then # An explicit old-style init named "init", so return return end end + if mclassdef.auto_init != null then + return + end + if not nclassdef isa AStdClassdef then return # Collect undefined attributes @@ -183,21 +181,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 @@ -209,9 +206,9 @@ redef class ModelBuilder end if npropdef.has_value then continue var paramname = mreadpropdef.mproperty.name - var ret_type = mreadpropdef.msignature.return_mtype + var ret_type = 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 @@ -226,13 +223,16 @@ redef class ModelBuilder 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 - var spropdefs = the_root_init_mmethod.lookup_super_definitions(mclassdef.mmodule, mclassdef.bound_mtype) - if spropdefs.is_empty then - toolcontext.error(nclassdef.location, "Error: `{mclassdef}` does not specialize `{the_root_init_mmethod.intro_mclassdef}`. Possible duplication of the root class `Object`?") - return + var spropdefs = new ArraySet[MMethodDef] + for x in mclassdef.in_hierarchy.direct_greaters do + var y = x.mclass.intro.auto_init + if y == null then continue + if y.is_broken or y.msignature == null then return + spropdefs.add y end # Look at the autoinit class-annotation @@ -280,13 +280,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 @@ -308,7 +302,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 @@ -335,33 +334,25 @@ redef class ModelBuilder # Combine the inherited list to what is collected if longest.initializers.length > 0 then - mparameters.prepend longest.new_msignature.mparameters + mparameters.prepend longest.msignature.mparameters initializers.prepend longest.initializers end end end - # If we already have a basic init definition, then setup its initializers - if defined_init != null then - defined_init.initializers.add_all(initializers) + # Create a specific new autoinit constructor + do + var mprop = new MMethod(mclassdef, "autoinit", public_visibility) + mprop.is_init = true + var mpropdef = new MMethodDef(mclassdef, mprop, nclassdef.location) + mpropdef.initializers.add_all(initializers) 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 + mpropdef.msignature = msignature + mclassdef.auto_init = mpropdef + self.toolcontext.info("{mclassdef} gets a free auto constructor `{mpropdef}{msignature}`. {spropdefs}", 3) + #mclassdef.mclass.root_init = mpropdef + mclassdef.mclass.the_root_init_mmethod = the_root_init_mmethod end - - # Else create the local implicit basic init definition - var mprop = the_root_init_mmethod.as(not null) - 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 # Check the visibility of `mtype` as an element of the signature of `mpropdef`. @@ -377,7 +368,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 @@ -385,6 +376,8 @@ 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 node.debug "Unexpected type {mtype}" abort @@ -444,8 +437,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 @@ -490,18 +482,19 @@ 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 # 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 + + # The base init of the class. + # + # TODO: merge with `root_init` and `ModelBuilder::the_root_init_mmethod` if possible + var the_root_init_mmethod: nullable MMethod = null end redef class MClassDef @@ -633,12 +626,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 @@ -724,6 +717,7 @@ redef class ASignature res = false end end + if not res then is_broken = true return res end end @@ -784,6 +778,9 @@ redef class AMethPropdef else if n_kwinit != null then name = "init" name_node = n_kwinit + if self.n_signature.n_params.not_empty or get_single_annotation("old_style_init", modelbuilder) != null then + name = "autoinit" + end else if n_kwnew != null then name = "new" name_node = n_kwnew @@ -835,8 +832,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 @@ -845,7 +848,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 @@ -878,7 +884,6 @@ redef class AMethPropdef 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 @@ -952,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 @@ -1003,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 @@ -1023,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 @@ -1036,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 @@ -1049,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 @@ -1069,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 @@ -1241,7 +1246,9 @@ redef class AAttrPropdef end is_lazy = true var mlazyprop = new MAttribute(mclassdef, "lazy _" + name, none_visibility) + mlazyprop.is_fictive = true var mlazypropdef = new MAttributeDef(mclassdef, mlazyprop, self.location) + mlazypropdef.is_fictive = true self.mlazypropdef = mlazypropdef end @@ -1273,7 +1280,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 @@ -1343,11 +1352,28 @@ 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") @@ -1399,7 +1425,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 @@ -1516,6 +1542,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 @@ -1529,7 +1557,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 @@ -1539,31 +1567,32 @@ 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) 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 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) @@ -1611,7 +1640,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