lib: Replaced strings by buffer in HTML lib to fix memory leaks
[nit.git] / src / modelbuilder.nit
index 9728abb..3f39d6d 100644 (file)
@@ -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)
@@ -751,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
@@ -767,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
@@ -780,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
@@ -803,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
@@ -822,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)
@@ -879,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
@@ -918,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
 
 #
 
@@ -982,6 +1061,10 @@ redef class APropdef
 
        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.")
@@ -1092,7 +1175,7 @@ redef class AMethPropdef
                                name = "init"
                                name_node = self.n_kwinit
                        else if self isa AExternInitPropdef then
-                               name = "new"
+                               name = "init"
                                name_node = self.n_kwnew
                        else
                                abort
@@ -1128,6 +1211,7 @@ redef class AMethPropdef
                        end
                        check_redef_property_visibility(modelbuilder, nclassdef, self.n_visibility, mprop)
                end
+               nclassdef.mprop2npropdef[mprop] = self
 
                var mpropdef = new MMethodDef(mclassdef, mprop, self.location)
 
@@ -1295,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
@@ -1310,6 +1396,8 @@ redef class AAttrPropdef
                                check_redef_property_visibility(modelbuilder, nclassdef, self.n_visibility, 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
@@ -1326,6 +1414,8 @@ redef class AAttrPropdef
                                        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
@@ -1343,6 +1433,8 @@ redef class AAttrPropdef
                                        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
@@ -1365,6 +1457,8 @@ redef class AAttrPropdef
                                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
@@ -1389,6 +1483,8 @@ redef class AAttrPropdef
                                        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
@@ -1564,6 +1660,8 @@ redef class ATypePropdef
                        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