X-Git-Url: http://nitlanguage.org diff --git a/src/modelbuilder.nit b/src/modelbuilder.nit index 4b2bac7..64b1a5a 100644 --- a/src/modelbuilder.nit +++ b/src/modelbuilder.nit @@ -504,7 +504,7 @@ class ModelBuilder var nfd = nclassdef.n_formaldefs[i] var nfdt = nfd.n_type if nfdt != null then - var bound = resolve_mtype(nclassdef, nfdt) + var bound = resolve_mtype_unchecked(nclassdef, nfdt) if bound == null then return # Forward error if bound.need_anchor then # No F-bounds! @@ -517,7 +517,7 @@ class ModelBuilder bounds.add(objectclass.mclass_type.as_nullable) else # Inherit the bound - bounds.add(mclass.mclassdefs.first.bound_mtype.arguments[i]) + bounds.add(mclass.intro.bound_mtype.arguments[i]) end end end @@ -548,7 +548,7 @@ class ModelBuilder for nsc in nclassdef.n_superclasses do specobject = false var ntype = nsc.n_type - var mtype = resolve_mtype(nclassdef, ntype) + var mtype = resolve_mtype_unchecked(nclassdef, ntype) if mtype == null then continue # Skip because of error if not mtype isa MClassType then error(ntype, "Error: supertypes cannot be a formal type") @@ -567,13 +567,18 @@ class ModelBuilder end # Check the validity of the specialization heirarchy - # FIXME Stub implementation private fun check_supertypes(nmodule: AModule, nclassdef: AClassdef) do var mmodule = nmodule.mmodule.as(not null) var objectclass = try_get_mclass_by_name(nmodule, mmodule, "Object") var mclass = nclassdef.mclass.as(not null) var mclassdef = nclassdef.mclassdef.as(not null) + + for s in mclassdef.supertypes do + if s.is_subtype(mmodule, mclassdef.bound_mtype, mclassdef.bound_mtype) then + error(nclassdef, "Error: Inheritance loop for class {mclass} with type {s}") + end + end end # Build the classes of the module `nmodule'. @@ -614,6 +619,34 @@ class ModelBuilder mclassdef.add_in_hierarchy end + # Check inheritance + for nclassdef in nmodule.n_classdefs do + self.check_supertypes(nmodule, nclassdef) + end + + # Check unchecked ntypes + for nclassdef in nmodule.n_classdefs do + if nclassdef isa AStdClassdef then + # check bound of formal parameter + for nfd in nclassdef.n_formaldefs do + var nfdt = nfd.n_type + if nfdt != null and nfdt.mtype != null then + var bound = resolve_mtype(nclassdef, nfdt) + if bound == null then return # Forward error + end + end + # check declared super types + for nsc in nclassdef.n_superclasses do + var ntype = nsc.n_type + if ntype.mtype != null then + var mtype = resolve_mtype(nclassdef, ntype) + if mtype == null then return # Forward error + end + end + end + + end + # TODO: Check that the super-class is not intrusive # TODO: Check that the super-class is not already known (by transitivity) @@ -728,6 +761,7 @@ class ModelBuilder var mparameters = new Array[MParameter] for npropdef in nclassdef.n_propdefs do if npropdef isa AAttrPropdef and npropdef.n_expr == null then + if npropdef.mpropdef == null then return # Skip broken attribute var paramname = npropdef.mpropdef.mproperty.name.substring_from(1) var ret_type = npropdef.mpropdef.static_mtype if ret_type == null then return @@ -750,7 +784,7 @@ class ModelBuilder # The mmodule used as context is `nclassdef.mmodule' # In case of problem, an error is displayed on `ntype' and null is returned. # FIXME: the name "resolve_mtype" is awful - fun resolve_mtype(nclassdef: AClassdef, ntype: AType): nullable MType + fun resolve_mtype_unchecked(nclassdef: AClassdef, ntype: AType): nullable MType do var name = ntype.n_id.text var mclassdef = nclassdef.mclassdef @@ -766,6 +800,7 @@ class ModelBuilder end res = prop.mvirtualtype if ntype.n_kwnullable != null then res = res.as_nullable + ntype.mtype = res return res end end @@ -779,6 +814,7 @@ class ModelBuilder if mclassdef.parameter_names[i] == name then res = mclassdef.mclass.mclass_type.arguments[i] if ntype.n_kwnullable != null then res = res.as_nullable + ntype.mtype = res return res end end @@ -802,16 +838,18 @@ class ModelBuilder if arity == 0 then res = mclass.mclass_type if ntype.n_kwnullable != null then res = res.as_nullable + ntype.mtype = res return res else var mtypes = new Array[MType] for nt in ntype.n_types do - var mt = resolve_mtype(nclassdef, nt) + var mt = resolve_mtype_unchecked(nclassdef, nt) if mt == null then return null # Forward error mtypes.add(mt) end res = mclass.get_mtype(mtypes) if ntype.n_kwnullable != null then res = res.as_nullable + ntype.mtype = res return res end end @@ -821,6 +859,37 @@ class ModelBuilder return null end + # Return the static type associated to the node `ntype'. + # `classdef' is the context where the call is made (used to understand formal types) + # The mmodule used as context is `nclassdef.mmodule' + # In case of problem, an error is displayed on `ntype' and null is returned. + # FIXME: the name "resolve_mtype" is awful + fun resolve_mtype(nclassdef: AClassdef, ntype: AType): nullable MType + do + var mtype = ntype.mtype + if mtype == null then mtype = resolve_mtype_unchecked(nclassdef, ntype) + if mtype == null then return null # Forward error + + if ntype.checked_mtype then return mtype + if mtype isa MGenericType then + var mmodule = nclassdef.parent.as(AModule).mmodule.as(not null) + var mclassdef = nclassdef.mclassdef + var mclass = mtype.mclass + for i in [0..mclass.arity[ do + var bound = mclass.intro.bound_mtype.arguments[i] + var nt = ntype.n_types[i] + var mt = resolve_mtype(nclassdef, nt) + if mt == null then return null # forward error + if not mt.is_subtype(mmodule, mclassdef.bound_mtype, bound) then + error(nt, "Type error: expected {bound}, got {mt}") + return null + end + end + end + ntype.checked_mtype = true + return mtype + end + # Helper function to display an error on a node. # Alias for `self.toolcontext.error(n.hot_location, text)' fun error(n: ANode, text: String) @@ -878,6 +947,10 @@ redef class AClassdef # The free init (implicitely constructed by the class if required) var mfree_init: nullable MMethodDef = null + + # What is the APropdef associated to a MProperty? + # Used to check multiple definition of a property. + var mprop2npropdef: Map[MProperty, APropdef] = new HashMap[MProperty, APropdef] end redef class AClasskind @@ -917,6 +990,13 @@ redef class APrivateVisibility redef fun mvisibility do return private_visibility end +redef class AType + # The mtype associated to the node + var mtype: nullable MType = null + + # Is the mtype a valid one? + var checked_mtype: Bool = false +end # @@ -979,17 +1059,24 @@ redef class APropdef end end - private fun check_redef_keyword(modelbuilder: ModelBuilder, nclassdef: AClassdef, kwredef: nullable Token, need_redef: Bool, mprop: MProperty) + private fun check_redef_keyword(modelbuilder: ModelBuilder, nclassdef: AClassdef, kwredef: nullable Token, need_redef: Bool, mprop: MProperty): Bool do + if nclassdef.mprop2npropdef.has_key(mprop) then + modelbuilder.error(self, "Error: A property {mprop} is already defined in class {nclassdef.mclassdef.mclass}.") + return false + end if kwredef == null then if need_redef then modelbuilder.error(self, "Redef error: {nclassdef.mclassdef.mclass}::{mprop.name} is an inherited property. To redefine it, add the redef keyword.") + return false end else if not need_redef then modelbuilder.error(self, "Error: No property {nclassdef.mclassdef.mclass}::{mprop.name} is inherited. Remove the redef keyword to define a new property.") + return false end end + return true end end @@ -1113,17 +1200,18 @@ redef class AMethPropdef mprop = new MMethod(mclassdef, name, mvisibility) mprop.is_init = is_init mprop.is_new = self isa AExternInitPropdef - self.check_redef_keyword(modelbuilder, nclassdef, n_kwredef, false, mprop) + if not self.check_redef_keyword(modelbuilder, nclassdef, n_kwredef, false, mprop) then return else if n_kwredef == null then if self isa AMainMethPropdef then # no warning else - self.check_redef_keyword(modelbuilder, nclassdef, n_kwredef, true, mprop) + if not self.check_redef_keyword(modelbuilder, nclassdef, n_kwredef, true, mprop) then return end end check_redef_property_visibility(modelbuilder, nclassdef, self.n_visibility, mprop) end + nclassdef.mprop2npropdef[mprop] = self var mpropdef = new MMethodDef(mclassdef, mprop, self.location) @@ -1291,6 +1379,8 @@ redef class AAttrPropdef modelbuilder.error(self, "Error: Attempt to define attribute {name} in the interface {mclass}.") else if mclass.kind == enum_kind then modelbuilder.error(self, "Error: Attempt to define attribute {name} in the enum class {mclass}.") + else if mclass.kind == extern_kind then + modelbuilder.error(self, "Error: Attempt to define attribute {name} in the extern class {mclass}.") end var nid = self.n_id @@ -1300,12 +1390,14 @@ redef class AAttrPropdef if mprop == null then var mvisibility = new_property_visibility(modelbuilder, nclassdef, self.n_visibility) mprop = new MAttribute(mclassdef, name, mvisibility) - self.check_redef_keyword(modelbuilder, nclassdef, self.n_kwredef, false, mprop) + if not self.check_redef_keyword(modelbuilder, nclassdef, self.n_kwredef, false, mprop) then return else assert mprop isa MAttribute check_redef_property_visibility(modelbuilder, nclassdef, self.n_visibility, mprop) - self.check_redef_keyword(modelbuilder, nclassdef, self.n_kwredef, true, mprop) + if not self.check_redef_keyword(modelbuilder, nclassdef, self.n_kwredef, true, mprop) then return end + nclassdef.mprop2npropdef[mprop] = self + var mpropdef = new MAttributeDef(mclassdef, mprop, self.location) self.mpropdef = mpropdef modelbuilder.mpropdef2npropdef[mpropdef] = self @@ -1317,11 +1409,13 @@ redef class AAttrPropdef if mreadprop == null then var mvisibility = new_property_visibility(modelbuilder, nclassdef, nreadable.n_visibility) mreadprop = new MMethod(mclassdef, readname, mvisibility) - self.check_redef_keyword(modelbuilder, nclassdef, nreadable.n_kwredef, false, mreadprop) + if not self.check_redef_keyword(modelbuilder, nclassdef, nreadable.n_kwredef, false, mreadprop) then return else - self.check_redef_keyword(modelbuilder, nclassdef, nreadable.n_kwredef, true, mreadprop) + if not self.check_redef_keyword(modelbuilder, nclassdef, nreadable.n_kwredef, true, mreadprop) then return check_redef_property_visibility(modelbuilder, nclassdef, nreadable.n_visibility, mreadprop) end + nclassdef.mprop2npropdef[mreadprop] = self + var mreadpropdef = new MMethodDef(mclassdef, mreadprop, self.location) self.mreadpropdef = mreadpropdef modelbuilder.mpropdef2npropdef[mreadpropdef] = self @@ -1334,11 +1428,13 @@ redef class AAttrPropdef if mwriteprop == null then var mvisibility = new_property_visibility(modelbuilder, nclassdef, nwritable.n_visibility) mwriteprop = new MMethod(mclassdef, writename, mvisibility) - self.check_redef_keyword(modelbuilder, nclassdef, nwritable.n_kwredef, false, mwriteprop) + if not self.check_redef_keyword(modelbuilder, nclassdef, nwritable.n_kwredef, false, mwriteprop) then return else - self.check_redef_keyword(modelbuilder, nclassdef, nwritable.n_kwredef, true, mwriteprop) + if not self.check_redef_keyword(modelbuilder, nclassdef, nwritable.n_kwredef, true, mwriteprop) then return check_redef_property_visibility(modelbuilder, nclassdef, nwritable.n_visibility, mwriteprop) end + nclassdef.mprop2npropdef[mwriteprop] = self + var mwritepropdef = new MMethodDef(mclassdef, mwriteprop, self.location) self.mwritepropdef = mwritepropdef modelbuilder.mpropdef2npropdef[mwritepropdef] = self @@ -1356,11 +1452,13 @@ redef class AAttrPropdef if mreadprop == null then var mvisibility = new_property_visibility(modelbuilder, nclassdef, self.n_visibility) mreadprop = new MMethod(mclassdef, readname, mvisibility) - self.check_redef_keyword(modelbuilder, nclassdef, n_kwredef, false, mreadprop) + if not self.check_redef_keyword(modelbuilder, nclassdef, n_kwredef, false, mreadprop) then return else - self.check_redef_keyword(modelbuilder, nclassdef, n_kwredef, true, mreadprop) + if not self.check_redef_keyword(modelbuilder, nclassdef, n_kwredef, true, mreadprop) then return check_redef_property_visibility(modelbuilder, nclassdef, self.n_visibility, mreadprop) end + nclassdef.mprop2npropdef[mreadprop] = self + var mreadpropdef = new MMethodDef(mclassdef, mreadprop, self.location) self.mreadpropdef = mreadpropdef modelbuilder.mpropdef2npropdef[mreadpropdef] = self @@ -1378,13 +1476,15 @@ redef class AAttrPropdef mvisibility = private_visibility end mwriteprop = new MMethod(mclassdef, writename, mvisibility) - self.check_redef_keyword(modelbuilder, nclassdef, nwkwredef, false, mwriteprop) + if not self.check_redef_keyword(modelbuilder, nclassdef, nwkwredef, false, mwriteprop) then return else - self.check_redef_keyword(modelbuilder, nclassdef, nwkwredef, true, mwriteprop) + if not self.check_redef_keyword(modelbuilder, nclassdef, nwkwredef, true, mwriteprop) then return if nwritable != null then check_redef_property_visibility(modelbuilder, nclassdef, nwritable.n_visibility, mwriteprop) end end + nclassdef.mprop2npropdef[mwriteprop] = self + var mwritepropdef = new MMethodDef(mclassdef, mwriteprop, self.location) self.mwritepropdef = mwritepropdef modelbuilder.mpropdef2npropdef[mwritepropdef] = self @@ -1554,12 +1654,14 @@ redef class ATypePropdef if mprop == null then var mvisibility = new_property_visibility(modelbuilder, nclassdef, self.n_visibility) mprop = new MVirtualTypeProp(mclassdef, name, mvisibility) - self.check_redef_keyword(modelbuilder, nclassdef, self.n_kwredef, false, mprop) + if not self.check_redef_keyword(modelbuilder, nclassdef, self.n_kwredef, false, mprop) then return else - self.check_redef_keyword(modelbuilder, nclassdef, self.n_kwredef, true, mprop) + if not self.check_redef_keyword(modelbuilder, nclassdef, self.n_kwredef, true, mprop) then return assert mprop isa MVirtualTypeProp check_redef_property_visibility(modelbuilder, nclassdef, self.n_visibility, mprop) end + nclassdef.mprop2npropdef[mprop] = self + var mpropdef = new MVirtualTypeDef(mclassdef, mprop, self.location) self.mpropdef = mpropdef end