model: fix bug where order of classes produces buggy models
authorJean Privat <jean@pryen.org>
Tue, 6 Nov 2012 04:47:58 +0000 (23:47 -0500)
committerJean Privat <jean@pryen.org>
Tue, 6 Nov 2012 04:47:58 +0000 (23:47 -0500)
The problem was a caching of a non-final information.
collect_things visit the mclassdefs of the module but they may not all
be analyzed (ie. their super-types not all identified)

To solve this we build the model in one more pass:

 - a pass to assign the super-types to each mclassdef
 - a pass to build the mclassdef hierarchy

a test file is added to prevent regressions.

Reported-by: Alexis Laferrière <alexis.laf@xymus.net>
Signed-off-by: Jean Privat <jean@pryen.org>

src/model/model.nit
src/modelbuilder.nit
tests/bug_inv_special.nit [new file with mode: 0644]
tests/sav/bug_inv_special.res [new file with mode: 0644]

index 13b0f5c..3410d2f 100644 (file)
@@ -390,15 +390,15 @@ class MClassDef
        # FIXME: quite ugly but not better idea yet
        var supertypes: Array[MClassType] = new Array[MClassType]
 
-       # Register the super-types for the class (ie "super SomeType")
-       # This function can only invoked once by class
+       # Register some super-types for the class (ie "super SomeType")
+       #
+       # The hierarchy must not already be set
+       # REQUIRE: self.in_hierarchy == null
        fun set_supertypes(supertypes: Array[MClassType])
        do
                assert unique_invocation: self.in_hierarchy == null
                var mmodule = self.mmodule
                var model = mmodule.model
-               var res = model.mclassdef_hierarchy.add_node(self)
-               self.in_hierarchy = res
                var mtype = self.bound_mtype
 
                for supertype in supertypes do
@@ -412,6 +412,23 @@ class MClassDef
                        end
                end
 
+       end
+
+       # Collect the super-types (set by set_supertypes) to build the hierarchy
+       #
+       # This function can only invoked once by class
+       # REQUIRE: self.in_hierarchy == null
+       # ENSURE: self.in_hierarchy != null
+       fun add_in_hierarchy
+       do
+               assert unique_invocation: self.in_hierarchy == null
+               var model = mmodule.model
+               var res = model.mclassdef_hierarchy.add_node(self)
+               self.in_hierarchy = res
+               var mtype = self.bound_mtype
+
+               # Here we need to connect the mclassdef to its pairs in the mclassdef_hierarchy
+               # The simpliest way is to attach it to collect_mclassdefs
                for mclassdef in mtype.collect_mclassdefs(mmodule) do
                        res.poset.add_edge(self, mclassdef)
                end
index 18cb12f..e2649de 100644 (file)
@@ -530,8 +530,8 @@ class ModelBuilder
                end
        end
 
-       # Visit the AST and set the super-types of the MClass objects (ie compute the inheritance)
-       private fun build_a_mclassdef_inheritance(nmodule: AModule, nclassdef: AClassdef)
+       # Visit the AST and set the super-types of the MClassdef objects
+       private fun collect_a_mclassdef_inheritance(nmodule: AModule, nclassdef: AClassdef)
        do
                var mmodule = nmodule.mmodule.as(not null)
                var objectclass = try_get_mclass_by_name(nmodule, mmodule, "Object")
@@ -599,7 +599,13 @@ class ModelBuilder
 
                # Create inheritance on all classdefs
                for nclassdef in nmodule.n_classdefs do
-                       self.build_a_mclassdef_inheritance(nmodule, nclassdef)
+                       self.collect_a_mclassdef_inheritance(nmodule, nclassdef)
+               end
+
+               # Create the mclassdef hierarchy
+               for nclassdef in nmodule.n_classdefs do
+                       var mclassdef = nclassdef.mclassdef.as(not null)
+                       mclassdef.add_in_hierarchy
                end
 
                # TODO: Check that the super-class is not intrusive
diff --git a/tests/bug_inv_special.nit b/tests/bug_inv_special.nit
new file mode 100644 (file)
index 0000000..2d0bc8e
--- /dev/null
@@ -0,0 +1,41 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import kernel
+
+class C
+       super B
+
+       redef fun foo do 1.output
+       fun baz do foo
+end
+
+class A
+       fun foo do 2.output
+       fun bar do 3.output
+end
+
+class B
+       super A
+end
+
+fun test(a: A)
+do
+       a.foo
+       a.bar
+end
+
+test(new A)
+test(new B)
+test(new C)
diff --git a/tests/sav/bug_inv_special.res b/tests/sav/bug_inv_special.res
new file mode 100644 (file)
index 0000000..7626055
--- /dev/null
@@ -0,0 +1,6 @@
+2
+3
+2
+3
+1
+3