X-Git-Url: http://nitlanguage.org diff --git a/src/modelize/modelize_property.nit b/src/modelize/modelize_property.nit index 23ac65f..c236170 100644 --- a/src/modelize/modelize_property.nit +++ b/src/modelize/modelize_property.nit @@ -42,6 +42,17 @@ redef class ModelBuilder # Public clients need to use `mpropdef2node` to access stuff. private var mpropdef2npropdef = new HashMap[MPropDef, APropdef] + # Associate a `npropdef` with its `mpropdef` + # + # Be careful, this method is unsafe, no checking is done when it's used. + # The safe way to add method it's to use the `build_property` + # + # See `mpropdef2npropdef` + fun unsafe_add_mpropdef2npropdef(mpropdef: MPropDef,npropdef: APropdef) + do + mpropdef2npropdef[mpropdef] = npropdef + end + # Retrieve the associated AST node of a mpropertydef. # This method is used to associate model entity with syntactic entities. # @@ -55,10 +66,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 @@ -80,7 +90,6 @@ redef class ModelBuilder end # Build the properties of `nclassdef`. - # REQUIRE: all superclasses are built. private fun build_properties(nclassdef: AClassdef) do # Force building recursively @@ -111,7 +120,7 @@ redef class ModelBuilder if not check_virtual_types_circularity(npropdef, mpropdef.mproperty, mclassdef.bound_mtype, mclassdef.mmodule) then # Invalidate the bound mpropdef.is_broken = true - mpropdef.bound = new MBottomType(mclassdef.mmodule.model) + mpropdef.bound = new MErrorType(mclassdef.mmodule.model) end end for npropdef in nclassdef2.n_propdefs do @@ -145,17 +154,15 @@ 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] var msignature = new MSignature(mparameters, null) mpropdef.msignature = msignature - mpropdef.new_msignature = msignature mprop.is_init = true self.toolcontext.info("{mclassdef} gets a free empty constructor {mpropdef}{msignature}", 3) the_root_init_mmethod = mprop - return end # Is there already a constructor defined? @@ -166,12 +173,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 @@ -228,10 +239,12 @@ redef class ModelBuilder 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 @@ -285,13 +298,31 @@ redef class ModelBuilder abort end end - else + else if spropdefs.not_empty then + # Search for inherited manual autoinit + var manual = null + for s in spropdefs do + if mpropdef2npropdef.has_key(s) then + self.toolcontext.info("{mclassdef} inherits a manual autoinit {s}", 3) + #mclassdef.autoinit = s + #return + 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 autoinit {manual} and automatic autoinit {spd}.", 3) + end + end + # conflict with manual autoinit? + if longest != manual and manual != null then + self.error(nclassdef, "Error: conflict between manual autoinit {manual} and automatic autoinit {longest}.") end # part 2. compare # Check for conflict in the order of initializers @@ -324,41 +355,26 @@ redef class ModelBuilder 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 + 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", nclassdef.location, 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.the_root_init_mmethod = the_root_init_mmethod end - - # Else create the local implicit basic init definition - 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 - 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`. @@ -384,6 +400,8 @@ redef class ModelBuilder # 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 @@ -492,11 +510,9 @@ 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 + # 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 @@ -670,14 +686,13 @@ redef class ASignature # Visit and fill information about a signature private fun visit_signature(modelbuilder: ModelBuilder, mclassdef: MClassDef): Bool do - var mmodule = mclassdef.mmodule var param_names = self.param_names var param_types = self.param_types for np in self.n_params do param_names.add(np.n_id.text) var ntype = np.n_type if ntype != null then - var mtype = modelbuilder.resolve_mtype_unchecked(mmodule, mclassdef, ntype, true) + var mtype = modelbuilder.resolve_mtype_unchecked(mclassdef, ntype, true) if mtype == null then return false # Skip error for i in [0..param_names.length-param_types.length[ do param_types.add(mtype) @@ -694,7 +709,7 @@ redef class ASignature end var ntype = self.n_type if ntype != null then - self.ret_type = modelbuilder.resolve_mtype_unchecked(mmodule, mclassdef, ntype, true) + self.ret_type = modelbuilder.resolve_mtype_unchecked(mclassdef, ntype, true) if self.ret_type == null then return false # Skip error end @@ -708,14 +723,14 @@ redef class ASignature for np in self.n_params do var ntype = np.n_type if ntype != null then - if modelbuilder.resolve_mtype(mclassdef.mmodule, mclassdef, ntype) == null then + if modelbuilder.resolve_mtype(mclassdef, ntype) == null then res = false end end end var ntype = self.n_type if ntype != null then - if modelbuilder.resolve_mtype(mclassdef.mmodule, mclassdef, ntype) == null then + if modelbuilder.resolve_mtype(mclassdef, ntype) == null then res = false end end @@ -769,22 +784,24 @@ redef class AMethPropdef do var n_kwinit = n_kwinit var n_kwnew = n_kwnew - var is_init = n_kwinit != null or n_kwnew != null + var is_new = n_kwnew != null + var is_init = n_kwinit != null or is_new var name: String var amethodid = self.n_methid var name_node: ANode if amethodid == null then - if not is_init then - name = "main" - name_node = self - else if n_kwinit != null then + 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 else - abort + name = "main" + name_node = self end else if amethodid isa AIdMethid then name = amethodid.n_id.text @@ -812,7 +829,7 @@ redef class AMethPropdef var look_like_a_root_init = look_like_a_root_init(modelbuilder, mclassdef) var mprop: nullable MMethod = null - if not is_init or n_kwredef != null then mprop = modelbuilder.try_get_mproperty_by_name(name_node, mclassdef, name).as(nullable MMethod) + if not is_init or n_kwredef != null or look_like_a_root_init then mprop = modelbuilder.try_get_mproperty_by_name(name_node, mclassdef, name).as(nullable MMethod) if mprop == null and look_like_a_root_init then mprop = modelbuilder.the_root_init_mmethod var nb = n_block @@ -822,23 +839,21 @@ 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 end mprop.is_init = is_init - mprop.is_new = n_kwnew != null - if mprop.is_new then mclassdef.mclass.has_new_factory = true + mprop.is_new = is_new + if 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 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 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 @@ -859,6 +874,14 @@ redef class AMethPropdef mclassdef.mprop2npropdef[mprop] = self var mpropdef = new MMethodDef(mclassdef, mprop, self.location) + if mprop.name == "autoinit" and mclassdef.is_intro then + assert mclassdef.auto_init == null + mclassdef.auto_init = mpropdef + if mpropdef.is_intro then + mpropdef.initializers.add mprop + mpropdef.is_calling_init = true + end + end set_doc(mpropdef, modelbuilder) @@ -875,20 +898,11 @@ redef class AMethPropdef do var mpropdef = self.mpropdef if mpropdef == null then return # Error thus skiped + var mproperty = mpropdef.mproperty var mclassdef = mpropdef.mclassdef var mmodule = mclassdef.mmodule var nsig = self.n_signature - if mpropdef.mproperty.is_root_init and not mclassdef.is_intro then - 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 - end - var accept_special_last_parameter = self.n_methid == null or self.n_methid.accept_special_last_parameter var return_is_mandatory = self.n_methid != null and self.n_methid.return_is_mandatory @@ -909,7 +923,7 @@ redef class AMethPropdef # FIXME: do not inherit from the intro, but from the most specific var msignature: nullable MSignature = null if not mpropdef.is_intro then - msignature = mpropdef.mproperty.intro.msignature + msignature = mproperty.intro.msignature if msignature == null then return # Skip error # The local signature is adapted to use the local formal types, if any. @@ -919,14 +933,14 @@ redef class AMethPropdef if param_names.length != msignature.arity then var node: ANode if nsig != null then node = nsig else node = self - modelbuilder.error(node, "Redef Error: expected {msignature.arity} parameter(s) for `{mpropdef.mproperty.name}{msignature}`; got {param_names.length}. See introduction at `{mpropdef.mproperty.full_name}`.") + modelbuilder.error(node, "Redef Error: expected {msignature.arity} parameter(s) for `{mproperty.name}{msignature}`; got {param_names.length}. See introduction at `{mproperty.full_name}`.") return end - else if mpropdef.mproperty.is_init and not mpropdef.mproperty.is_new then + else if mproperty.is_init and not mproperty.is_new then # FIXME UGLY: inherit signature from a super-constructor for msupertype in mclassdef.supertypes do msupertype = msupertype.anchor_to(mmodule, mclassdef.bound_mtype) - var candidate = modelbuilder.try_get_mproperty_by_name2(self, mmodule, msupertype, mpropdef.mproperty.name) + var candidate = modelbuilder.try_get_mproperty_by_name2(self, mmodule, msupertype, mproperty.name) if candidate != null then if msignature == null then msignature = candidate.intro.as(MMethodDef).msignature @@ -963,14 +977,14 @@ redef class AMethPropdef end # In `new`-factories, the return type is by default the classtype. - if ret_type == null and mpropdef.mproperty.is_new then ret_type = mclassdef.mclass.mclass_type + if ret_type == null and mproperty.is_new then ret_type = mclassdef.mclass.mclass_type # Special checks for operator methods if not accept_special_last_parameter and mparameters.not_empty and mparameters.last.is_vararg then - modelbuilder.error(self.n_signature.n_params.last, "Error: illegal variadic parameter `{mparameters.last}` for `{mpropdef.mproperty.name}`.") + modelbuilder.error(self.n_signature.n_params.last, "Error: illegal variadic parameter `{mparameters.last}` for `{mproperty.name}`.") end if ret_type == null and return_is_mandatory then - modelbuilder.error(self.n_methid, "Error: mandatory return type for `{mpropdef.mproperty.name}`.") + modelbuilder.error(self.n_methid, "Error: mandatory return type for `{mproperty.name}`.") end msignature = new MSignature(mparameters, ret_type) @@ -1159,8 +1173,8 @@ redef class AAttrPropdef # Is the node tagged optional? var is_optional = false - # Has the node a default value? - # Could be through `n_expr` or `n_block` + # Does the node have a default value? + # Could be through `n_expr`, `n_block` or `is_lazy` var has_value = false # The guard associated to a lazy attribute. @@ -1186,7 +1200,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 @@ -1196,14 +1210,24 @@ 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 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 @@ -1248,7 +1272,7 @@ 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 @@ -1295,10 +1319,14 @@ redef class AAttrPropdef # 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 + 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.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) @@ -1306,6 +1334,11 @@ redef class AAttrPropdef end mclassdef.mprop2npropdef[mwriteprop] = self + if attr_mpropdef != null then + mwriteprop.setter_for = attr_mpropdef.mproperty + attr_mpropdef.mproperty.setter = mwriteprop + end + var mwritepropdef = new MMethodDef(mclassdef, mwriteprop, self.location) self.mwritepropdef = mwritepropdef modelbuilder.mpropdef2npropdef[mwritepropdef] = self @@ -1341,7 +1374,7 @@ redef class AAttrPropdef var ntype = self.n_type if ntype != null then - mtype = modelbuilder.resolve_mtype_unchecked(mmodule, mclassdef, ntype, true) + mtype = modelbuilder.resolve_mtype_unchecked(mclassdef, ntype, true) if mtype == null then return end @@ -1361,62 +1394,12 @@ redef class AAttrPropdef var nexpr = self.n_expr if mtype == null then if nexpr != null then - if nexpr isa ANewExpr then - mtype = modelbuilder.resolve_mtype_unchecked(mmodule, mclassdef, nexpr.n_type, true) - 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: 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") - if cla != null then mtype = cla.mclass_type - else if nexpr isa ASuperstringExpr then - 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") - if cla != null then mtype = cla.mclass_type - else - modelbuilder.error(self, "Error: untyped attribute `{mreadpropdef}`. Implicit typing allowed only for literals and new.") - end - + mtype = infer_static_type(modelbuilder, nexpr, mclassdef, mmodule, mreadpropdef) if mtype == null then return end else if ntype != null and inherited_type == mtype then if nexpr isa ANewExpr then - var xmtype = modelbuilder.resolve_mtype_unchecked(mmodule, mclassdef, nexpr.n_type, true) + var xmtype = modelbuilder.resolve_mtype_unchecked(mclassdef, nexpr.n_type, true) if xmtype == mtype then modelbuilder.advice(ntype, "useless-type", "Warning: useless type definition") end @@ -1454,11 +1437,107 @@ redef class AAttrPropdef 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 + # Detect the static type from the value assigned to the attribute `self` + # + # Return the static type if it can be safely inferred. + private fun infer_static_type(modelbuilder: ModelBuilder, nexpr: AExpr, + mclassdef: MClassDef, mmodule: MModule, mreadpropdef: MPropDef): nullable MType + do + var mtype = null + if nexpr isa ANewExpr then + mtype = modelbuilder.resolve_mtype_unchecked(mclassdef, nexpr.n_type, true) + else if nexpr isa AAsCastExpr then + mtype = modelbuilder.resolve_mtype_unchecked(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: nullable MClass + 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") + if cla != null then mtype = cla.mclass_type + else if nexpr isa ASuperstringExpr then + 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: 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 if nexpr isa AArrayExpr and nexpr.n_type == null and nexpr.n_exprs.not_empty then + # Non-empty arrays without an explicit type + + var item_mtypes = new Set[MType] + var fails = false + for node in nexpr.n_exprs do + var item_mtype = infer_static_type(modelbuilder, node, mclassdef, mmodule, mreadpropdef) + if item_mtype == null then + fails = true + else + item_mtypes.add item_mtype + end + end + + if fails then return null # Failed to infer some types + + if item_mtypes.length > 1 then + modelbuilder.error(self, "Type Error: ambiguous array type {item_mtypes.join(" ")}") + end + + mtype = mmodule.array_type(item_mtypes.first) + else if nexpr isa AUminusExpr and (nexpr.n_expr isa AIntegerExpr or nexpr.n_expr isa AFloatExpr) then + # The Int and Float unary - is defined in `kernel`, so this may + # result in an invalid behavior when using a custom kernel. + # A workaround is to declare the attribute static type. + # This is still very useful, especially to novice programmers. + mtype = infer_static_type(modelbuilder, nexpr.n_expr, mclassdef, mmodule, mreadpropdef) + else if nexpr isa AOnceExpr then + mtype = infer_static_type(modelbuilder, nexpr.n_expr, mclassdef, mmodule, mreadpropdef) + else + modelbuilder.error(self, "Error: untyped attribute `{mreadpropdef}`. Implicit typing allowed only for literals and new.") + end + return mtype + end + redef fun check_signature(modelbuilder) do var mpropdef = self.mpropdef @@ -1472,11 +1551,11 @@ redef class AAttrPropdef # Check types if ntype != null then - if modelbuilder.resolve_mtype(mmodule, mclassdef, ntype) == null then return + if modelbuilder.resolve_mtype(mclassdef, ntype) == null then return end var nexpr = n_expr if nexpr isa ANewExpr then - if modelbuilder.resolve_mtype(mmodule, mclassdef, nexpr.n_type) == null then return + if modelbuilder.resolve_mtype(mclassdef, nexpr.n_type) == null then return end # Lookup for signature in the precursor @@ -1593,12 +1672,13 @@ redef class ATypePropdef 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_qid, "bad-type-name", "Warning: lowercase in the virtual type `{name}`.") break end else + if mprop.is_broken then return assert mprop isa MVirtualTypeProp check_redef_property_visibility(modelbuilder, self.n_visibility, mprop) end @@ -1628,11 +1708,10 @@ redef class ATypePropdef var mpropdef = self.mpropdef if mpropdef == null then return # Error thus skipped var mclassdef = mpropdef.mclassdef - var mmodule = mclassdef.mmodule var mtype: nullable MType = null var ntype = self.n_type - mtype = modelbuilder.resolve_mtype_unchecked(mmodule, mclassdef, ntype, true) + mtype = modelbuilder.resolve_mtype_unchecked(mclassdef, ntype, true) if mtype == null then return mpropdef.bound = mtype @@ -1654,7 +1733,7 @@ redef class ATypePropdef var anchor = mclassdef.bound_mtype var ntype = self.n_type - if modelbuilder.resolve_mtype(mmodule, mclassdef, ntype) == null then + if modelbuilder.resolve_mtype(mclassdef, ntype) == null then mpropdef.bound = null return end @@ -1668,8 +1747,7 @@ redef class ATypePropdef break end if p.mclassdef.mclass == mclassdef.mclass then - # Still a warning to pass existing bad code - modelbuilder.warning(n_type, "refine-type", "Redef Error: a virtual type cannot be refined.") + modelbuilder.error(n_type, "Redef Error: a virtual type cannot be refined.") break end if not modelbuilder.check_subtype(n_type, mmodule, anchor, bound, supbound) then