Merge: nitc: fix some broken case in equal_test
authorJean Privat <jean@pryen.org>
Tue, 22 Sep 2015 19:41:23 +0000 (15:41 -0400)
committerJean Privat <jean@pryen.org>
Tue, 22 Sep 2015 19:41:23 +0000 (15:41 -0400)
The code that handle the various cases of comparison when one of the two types is primitive was broken in the specific sub-case of comparison between something tagged and something boxed.
The fact that this code date back from before tagging explain that, but the fact that the bug was discovered only now is more mysterious.

Reported-by: Lucas Bajolet <r4pass@hotmail.com>

Pull-Request: #1729
Reviewed-by: Lucas Bajolet <r4pass@hotmail.com>

lib/core/stream.nit
src/compiler/separate_compiler.nit
tests/base_eq_int4.nit [new file with mode: 0644]
tests/base_eq_int4b.nit [new file with mode: 0644]
tests/base_eq_int4c.nit [new file with mode: 0644]
tests/sav/base_eq_int4.res [new file with mode: 0644]
tests/sav/base_eq_int4b.res [new file with mode: 0644]
tests/sav/base_eq_int4c.res [new file with mode: 0644]

index 4b1e826..799d130 100644 (file)
@@ -275,7 +275,7 @@ abstract class Reader
        # ~~~
        # var w = new StringReader(" Hello, \n\t World!")
        # assert w.read_word == "Hello,"
-       # assert w.read_char == '\n'.ascii
+       # assert w.read_char == '\n'
        # assert w.read_word == "World!"
        # assert w.read_word == ""
        # ~~~
index ff5f3ba..00f3f00 100644 (file)
@@ -998,10 +998,13 @@ class SeparateCompiler
                        # use some Huffman coding.
                        if t.name == "Int" then
                                class_info[1] = t
+                               t.mclass_type.tag_value = 1
                        else if t.name == "Char" then
                                class_info[2] = t
+                               t.mclass_type.tag_value = 2
                        else if t.name == "Bool" then
                                class_info[3] = t
+                               t.mclass_type.tag_value = 3
                        else
                                continue
                        end
@@ -1858,7 +1861,7 @@ class SeparateCompilerVisitor
                        else
                                var mtype1 = value1.mtype.as(MClassType)
                                self.require_declaration("class_{mtype1.c_name}")
-                               self.add("{res} = ({value2} != NULL) && ({value2}->class == &class_{mtype1.c_name}); /* is_same_type_test */")
+                               self.add("{res} = ({value2} != NULL) && ({class_info(value2)} == &class_{mtype1.c_name}); /* is_same_type_test */")
                        end
                else
                        self.add("{res} = ({value1} == {value2}) || ({value1} != NULL && {value2} != NULL && {class_info(value1)} == {class_info(value2)}); /* is_same_type_test */")
@@ -1891,20 +1894,58 @@ class SeparateCompilerVisitor
                        value2 = tmp
                end
                if value1.mtype.is_c_primitive then
-                       if value2.mtype == value1.mtype then
+                       var t1 = value1.mtype
+                       assert t1 == value1.mcasttype
+
+                       # Fast case: same C type.
+                       if value2.mtype == t1 then
+                               # Same exact C primitive representation.
                                self.add("{res} = {value1} == {value2};")
-                       else if value2.mtype.is_c_primitive then
-                               self.add("{res} = 0; /* incompatible types {value1.mtype} vs. {value2.mtype}*/")
-                       else if value1.mtype.is_tagged then
-                               self.add("{res} = ({value2} != NULL) && ({self.autobox(value2, value1.mtype)} == {value1});")
+                               return res
+                       end
+
+                       # Complex case: value2 has a different representation
+                       # Thus, it should be checked if `value2` is type-compatible with `value1`
+                       # This compatibility is done statically if possible and dynamically else
+
+                       # Conjunction (ands) of dynamic tests according to the static knowledge
+                       var tests = new Array[String]
+
+                       var t2 = value2.mcasttype
+                       if t2 isa MNullableType then
+                               # The destination type cannot be null
+                               tests.add("({value2} != NULL)")
+                               t2 = t2.mtype
+                       else if t2 isa MNullType then
+                               # `value2` is known to be null, thus incompatible with a primitive
+                               self.add("{res} = 0; /* incompatible types {t1} vs. {t2}*/")
+                               return res
+                       end
+
+                       if t2 == t1 then
+                               # Same type but different representation.
+                       else if t2.is_c_primitive then
+                               # Type of `value2` is a different primitive type, thus incompatible
+                               self.add("{res} = 0; /* incompatible types {t1} vs. {t2}*/")
+                               return res
+                       else if t1.is_tagged then
+                               # To be equal, `value2` should also be correctly tagged
+                               tests.add("({extract_tag(value2)} == {t1.tag_value})")
                        else
-                               var mtype1 = value1.mtype.as(MClassType)
-                               self.require_declaration("class_{mtype1.c_name}")
-                               self.add("{res} = ({value2} != NULL) && ({value2}->class == &class_{mtype1.c_name});")
-                               self.add("if ({res}) \{")
-                               self.add("{res} = ({self.autobox(value2, value1.mtype)} == {value1});")
-                               self.add("\}")
+                               # To be equal, `value2` should also be boxed with the same class
+                               self.require_declaration("class_{t1.c_name}")
+                               tests.add "({class_info(value2)} == &class_{t1.c_name})"
                        end
+
+                       # Compare the unboxed `value2` with `value1`
+                       if tests.not_empty then
+                               self.add "if ({tests.join(" && ")}) \{"
+                       end
+                       self.add "{res} = {self.autobox(value2, t1)} == {value1};"
+                       if tests.not_empty then
+                               self.add "\} else {res} = 0;"
+                       end
+
                        return res
                end
                var maybe_null = true
@@ -2327,6 +2368,12 @@ redef class MType
        # Are values of `self` tagged?
        # If false, it means that the type is not primitive, or is boxed.
        var is_tagged = false
+
+       # The tag value of the type
+       #
+       # ENSURE `is_tagged == (tag_value > 0)`
+       # ENSURE `not is_tagged == (tag_value == 0)`
+       var tag_value = 0
 end
 
 redef class MEntity
diff --git a/tests/base_eq_int4.nit b/tests/base_eq_int4.nit
new file mode 100644 (file)
index 0000000..60144b2
--- /dev/null
@@ -0,0 +1,196 @@
+# 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
+
+var i = 1
+var b = true
+var f = 1u8
+var ni: nullable Int = 1
+var nb: nullable Bool = true
+var nf: nullable Byte = 1u8
+var oi: nullable Object = 1
+var ob: nullable Object = true
+var of: nullable Object = 1u8
+
+
+(i == i).output
+(b == i).output
+(f == i).output
+
+'\n'.output
+
+(i == ni).output
+(b == ni).output
+(f == ni).output
+
+'\n'.output
+
+(i == oi).output
+(b == oi).output
+(f == oi).output
+
+'\n'.output
+'\n'.output
+
+(ni == i).output
+(nb == i).output
+(nf == i).output
+
+'\n'.output
+
+(ni == ni).output
+(nb == ni).output
+(nf == ni).output
+
+'\n'.output
+
+(ni == oi).output
+(nb == oi).output
+(nf == oi).output
+
+'\n'.output
+'\n'.output
+
+(oi == i).output
+(ob == i).output
+(of == i).output
+
+'\n'.output
+
+(oi == ni).output
+(ob == ni).output
+(of == ni).output
+
+'\n'.output
+
+(oi == oi).output
+(ob == oi).output
+(of == oi).output
+
+'\n'.output
+'\n'.output
+'\n'.output
+
+(i == b).output
+(b == b).output
+(f == b).output
+
+'\n'.output
+
+(i == nb).output
+(b == nb).output
+(f == nb).output
+
+'\n'.output
+
+(i == ob).output
+(b == ob).output
+(f == ob).output
+
+'\n'.output
+'\n'.output
+
+(ni == b).output
+(nb == b).output
+(nf == b).output
+
+'\n'.output
+
+(ni == nb).output
+(nb == nb).output
+(nf == nb).output
+
+'\n'.output
+
+(ni == ob).output
+(nb == ob).output
+(nf == ob).output
+
+'\n'.output
+'\n'.output
+
+(oi == b).output
+(ob == b).output
+(of == b).output
+
+'\n'.output
+
+(oi == nb).output
+(ob == nb).output
+(of == nb).output
+
+'\n'.output
+
+(oi == ob).output
+(ob == ob).output
+(of == ob).output
+
+'\n'.output
+'\n'.output
+'\n'.output
+
+(i == f).output
+(b == f).output
+(f == f).output
+
+'\n'.output
+
+(i == nf).output
+(b == nf).output
+(f == nf).output
+
+'\n'.output
+
+(i == of).output
+(b == of).output
+(f == of).output
+
+'\n'.output
+'\n'.output
+
+(ni == f).output
+(nb == f).output
+(nf == f).output
+
+'\n'.output
+
+(ni == nf).output
+(nb == nf).output
+(nf == nf).output
+
+'\n'.output
+
+(ni == of).output
+(nb == of).output
+(nf == of).output
+
+'\n'.output
+'\n'.output
+
+(oi == f).output
+(ob == f).output
+(of == f).output
+
+'\n'.output
+
+(oi == nf).output
+(ob == nf).output
+(of == nf).output
+
+'\n'.output
+
+(oi == of).output
+(ob == of).output
+(of == of).output
diff --git a/tests/base_eq_int4b.nit b/tests/base_eq_int4b.nit
new file mode 100644 (file)
index 0000000..fea2020
--- /dev/null
@@ -0,0 +1,196 @@
+# 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
+
+var i = 1
+var b = true
+var f = 1u8
+var ni: nullable Int = 1
+var nb: nullable Bool = true
+var nf: nullable Byte = 1u8
+var oi: nullable Object = 1
+var ob: nullable Object = true
+var of: nullable Object = 1u8
+
+
+(i.is_same_instance(i)).output
+(b.is_same_instance(i)).output
+(f.is_same_instance(i)).output
+
+'\n'.output
+
+(i.is_same_instance(ni)).output
+(b.is_same_instance(ni)).output
+(f.is_same_instance(ni)).output
+
+'\n'.output
+
+(i.is_same_instance(oi)).output
+(b.is_same_instance(oi)).output
+(f.is_same_instance(oi)).output
+
+'\n'.output
+'\n'.output
+
+(ni.is_same_instance(i)).output
+(nb.is_same_instance(i)).output
+(nf.is_same_instance(i)).output
+
+'\n'.output
+
+(ni.is_same_instance(ni)).output
+(nb.is_same_instance(ni)).output
+(nf.is_same_instance(ni)).output
+
+'\n'.output
+
+(ni.is_same_instance(oi)).output
+(nb.is_same_instance(oi)).output
+(nf.is_same_instance(oi)).output
+
+'\n'.output
+'\n'.output
+
+(oi.is_same_instance(i)).output
+(ob.is_same_instance(i)).output
+(of.is_same_instance(i)).output
+
+'\n'.output
+
+(oi.is_same_instance(ni)).output
+(ob.is_same_instance(ni)).output
+(of.is_same_instance(ni)).output
+
+'\n'.output
+
+(oi.is_same_instance(oi)).output
+(ob.is_same_instance(oi)).output
+(of.is_same_instance(oi)).output
+
+'\n'.output
+'\n'.output
+'\n'.output
+
+(i.is_same_instance(b)).output
+(b.is_same_instance(b)).output
+(f.is_same_instance(b)).output
+
+'\n'.output
+
+(i.is_same_instance(nb)).output
+(b.is_same_instance(nb)).output
+(f.is_same_instance(nb)).output
+
+'\n'.output
+
+(i.is_same_instance(ob)).output
+(b.is_same_instance(ob)).output
+(f.is_same_instance(ob)).output
+
+'\n'.output
+'\n'.output
+
+(ni.is_same_instance(b)).output
+(nb.is_same_instance(b)).output
+(nf.is_same_instance(b)).output
+
+'\n'.output
+
+(ni.is_same_instance(nb)).output
+(nb.is_same_instance(nb)).output
+(nf.is_same_instance(nb)).output
+
+'\n'.output
+
+(ni.is_same_instance(ob)).output
+(nb.is_same_instance(ob)).output
+(nf.is_same_instance(ob)).output
+
+'\n'.output
+'\n'.output
+
+(oi.is_same_instance(b)).output
+(ob.is_same_instance(b)).output
+(of.is_same_instance(b)).output
+
+'\n'.output
+
+(oi.is_same_instance(nb)).output
+(ob.is_same_instance(nb)).output
+(of.is_same_instance(nb)).output
+
+'\n'.output
+
+(oi.is_same_instance(ob)).output
+(ob.is_same_instance(ob)).output
+(of.is_same_instance(ob)).output
+
+'\n'.output
+'\n'.output
+'\n'.output
+
+(i.is_same_instance(f)).output
+(b.is_same_instance(f)).output
+(f.is_same_instance(f)).output
+
+'\n'.output
+
+(i.is_same_instance(nf)).output
+(b.is_same_instance(nf)).output
+(f.is_same_instance(nf)).output
+
+'\n'.output
+
+(i.is_same_instance(of)).output
+(b.is_same_instance(of)).output
+(f.is_same_instance(of)).output
+
+'\n'.output
+'\n'.output
+
+(ni.is_same_instance(f)).output
+(nb.is_same_instance(f)).output
+(nf.is_same_instance(f)).output
+
+'\n'.output
+
+(ni.is_same_instance(nf)).output
+(nb.is_same_instance(nf)).output
+(nf.is_same_instance(nf)).output
+
+'\n'.output
+
+(ni.is_same_instance(of)).output
+(nb.is_same_instance(of)).output
+(nf.is_same_instance(of)).output
+
+'\n'.output
+'\n'.output
+
+(oi.is_same_instance(f)).output
+(ob.is_same_instance(f)).output
+(of.is_same_instance(f)).output
+
+'\n'.output
+
+(oi.is_same_instance(nf)).output
+(ob.is_same_instance(nf)).output
+(of.is_same_instance(nf)).output
+
+'\n'.output
+
+(oi.is_same_instance(of)).output
+(ob.is_same_instance(of)).output
+(of.is_same_instance(of)).output
diff --git a/tests/base_eq_int4c.nit b/tests/base_eq_int4c.nit
new file mode 100644 (file)
index 0000000..89e2882
--- /dev/null
@@ -0,0 +1,196 @@
+# 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
+
+var i = 1
+var b = true
+var f = 1u8
+var ni: Int = 0
+var nb: Bool = false
+var nf: Byte = 0u8
+var oi: Object = 1
+var ob: Object = true
+var of: Object = 1u8
+
+
+(i.is_same_type(i)).output
+(b.is_same_type(i)).output
+(f.is_same_type(i)).output
+
+'\n'.output
+
+(i.is_same_type(ni)).output
+(b.is_same_type(ni)).output
+(f.is_same_type(ni)).output
+
+'\n'.output
+
+(i.is_same_type(oi)).output
+(b.is_same_type(oi)).output
+(f.is_same_type(oi)).output
+
+'\n'.output
+'\n'.output
+
+(ni.is_same_type(i)).output
+(nb.is_same_type(i)).output
+(nf.is_same_type(i)).output
+
+'\n'.output
+
+(ni.is_same_type(ni)).output
+(nb.is_same_type(ni)).output
+(nf.is_same_type(ni)).output
+
+'\n'.output
+
+(ni.is_same_type(oi)).output
+(nb.is_same_type(oi)).output
+(nf.is_same_type(oi)).output
+
+'\n'.output
+'\n'.output
+
+(oi.is_same_type(i)).output
+(ob.is_same_type(i)).output
+(of.is_same_type(i)).output
+
+'\n'.output
+
+(oi.is_same_type(ni)).output
+(ob.is_same_type(ni)).output
+(of.is_same_type(ni)).output
+
+'\n'.output
+
+(oi.is_same_type(oi)).output
+(ob.is_same_type(oi)).output
+(of.is_same_type(oi)).output
+
+'\n'.output
+'\n'.output
+'\n'.output
+
+(i.is_same_type(b)).output
+(b.is_same_type(b)).output
+(f.is_same_type(b)).output
+
+'\n'.output
+
+(i.is_same_type(nb)).output
+(b.is_same_type(nb)).output
+(f.is_same_type(nb)).output
+
+'\n'.output
+
+(i.is_same_type(ob)).output
+(b.is_same_type(ob)).output
+(f.is_same_type(ob)).output
+
+'\n'.output
+'\n'.output
+
+(ni.is_same_type(b)).output
+(nb.is_same_type(b)).output
+(nf.is_same_type(b)).output
+
+'\n'.output
+
+(ni.is_same_type(nb)).output
+(nb.is_same_type(nb)).output
+(nf.is_same_type(nb)).output
+
+'\n'.output
+
+(ni.is_same_type(ob)).output
+(nb.is_same_type(ob)).output
+(nf.is_same_type(ob)).output
+
+'\n'.output
+'\n'.output
+
+(oi.is_same_type(b)).output
+(ob.is_same_type(b)).output
+(of.is_same_type(b)).output
+
+'\n'.output
+
+(oi.is_same_type(nb)).output
+(ob.is_same_type(nb)).output
+(of.is_same_type(nb)).output
+
+'\n'.output
+
+(oi.is_same_type(ob)).output
+(ob.is_same_type(ob)).output
+(of.is_same_type(ob)).output
+
+'\n'.output
+'\n'.output
+'\n'.output
+
+(i.is_same_type(f)).output
+(b.is_same_type(f)).output
+(f.is_same_type(f)).output
+
+'\n'.output
+
+(i.is_same_type(nf)).output
+(b.is_same_type(nf)).output
+(f.is_same_type(nf)).output
+
+'\n'.output
+
+(i.is_same_type(of)).output
+(b.is_same_type(of)).output
+(f.is_same_type(of)).output
+
+'\n'.output
+'\n'.output
+
+(ni.is_same_type(f)).output
+(nb.is_same_type(f)).output
+(nf.is_same_type(f)).output
+
+'\n'.output
+
+(ni.is_same_type(nf)).output
+(nb.is_same_type(nf)).output
+(nf.is_same_type(nf)).output
+
+'\n'.output
+
+(ni.is_same_type(of)).output
+(nb.is_same_type(of)).output
+(nf.is_same_type(of)).output
+
+'\n'.output
+'\n'.output
+
+(oi.is_same_type(f)).output
+(ob.is_same_type(f)).output
+(of.is_same_type(f)).output
+
+'\n'.output
+
+(oi.is_same_type(nf)).output
+(ob.is_same_type(nf)).output
+(of.is_same_type(nf)).output
+
+'\n'.output
+
+(oi.is_same_type(of)).output
+(ob.is_same_type(of)).output
+(of.is_same_type(of)).output
diff --git a/tests/sav/base_eq_int4.res b/tests/sav/base_eq_int4.res
new file mode 100644 (file)
index 0000000..cf1d59c
--- /dev/null
@@ -0,0 +1,117 @@
+true
+false
+false
+
+true
+false
+false
+
+true
+false
+false
+
+
+true
+false
+false
+
+true
+false
+false
+
+true
+false
+false
+
+
+true
+false
+false
+
+true
+false
+false
+
+true
+false
+false
+
+
+
+false
+true
+false
+
+false
+true
+false
+
+false
+true
+false
+
+
+false
+true
+false
+
+false
+true
+false
+
+false
+true
+false
+
+
+false
+true
+false
+
+false
+true
+false
+
+false
+true
+false
+
+
+
+false
+false
+true
+
+false
+false
+true
+
+false
+false
+true
+
+
+false
+false
+true
+
+false
+false
+true
+
+false
+false
+true
+
+
+false
+false
+true
+
+false
+false
+true
+
+false
+false
+true
diff --git a/tests/sav/base_eq_int4b.res b/tests/sav/base_eq_int4b.res
new file mode 100644 (file)
index 0000000..cf1d59c
--- /dev/null
@@ -0,0 +1,117 @@
+true
+false
+false
+
+true
+false
+false
+
+true
+false
+false
+
+
+true
+false
+false
+
+true
+false
+false
+
+true
+false
+false
+
+
+true
+false
+false
+
+true
+false
+false
+
+true
+false
+false
+
+
+
+false
+true
+false
+
+false
+true
+false
+
+false
+true
+false
+
+
+false
+true
+false
+
+false
+true
+false
+
+false
+true
+false
+
+
+false
+true
+false
+
+false
+true
+false
+
+false
+true
+false
+
+
+
+false
+false
+true
+
+false
+false
+true
+
+false
+false
+true
+
+
+false
+false
+true
+
+false
+false
+true
+
+false
+false
+true
+
+
+false
+false
+true
+
+false
+false
+true
+
+false
+false
+true
diff --git a/tests/sav/base_eq_int4c.res b/tests/sav/base_eq_int4c.res
new file mode 100644 (file)
index 0000000..cf1d59c
--- /dev/null
@@ -0,0 +1,117 @@
+true
+false
+false
+
+true
+false
+false
+
+true
+false
+false
+
+
+true
+false
+false
+
+true
+false
+false
+
+true
+false
+false
+
+
+true
+false
+false
+
+true
+false
+false
+
+true
+false
+false
+
+
+
+false
+true
+false
+
+false
+true
+false
+
+false
+true
+false
+
+
+false
+true
+false
+
+false
+true
+false
+
+false
+true
+false
+
+
+false
+true
+false
+
+false
+true
+false
+
+false
+true
+false
+
+
+
+false
+false
+true
+
+false
+false
+true
+
+false
+false
+true
+
+
+false
+false
+true
+
+false
+false
+true
+
+false
+false
+true
+
+
+false
+false
+true
+
+false
+false
+true
+
+false
+false
+true