typing: move redef class check before inheritance
authorJean Privat <jean@pryen.org>
Sat, 26 Mar 2011 01:03:15 +0000 (21:03 -0400)
committerJean Privat <jean@pryen.org>
Thu, 31 Mar 2011 14:53:28 +0000 (10:53 -0400)
And move accept_class_verifier in AClassdef.
Thus:
1- avoid crashing on class arity missmatch;
2- avoid illegal super-classes in refinement.

Signed-off-by: Jean Privat <jean@pryen.org>

12 files changed:
src/syntax/mmbuilder.nit
tests/error_class_generic.nit [new file with mode: 0644]
tests/error_inh_loop.nit
tests/sav/error_class_generic.sav [new file with mode: 0644]
tests/sav/error_class_generic_alt1.sav [new file with mode: 0644]
tests/sav/error_class_generic_alt2.sav [new file with mode: 0644]
tests/sav/error_class_generic_alt3.sav [new file with mode: 0644]
tests/sav/error_class_generic_alt4.sav [new file with mode: 0644]
tests/sav/error_class_generic_alt5.sav [new file with mode: 0644]
tests/sav/error_class_generic_alt6.sav [new file with mode: 0644]
tests/test_variance_param.nit
tests/test_variance_ret.nit

index ce875a8..1fd92f3 100644 (file)
@@ -529,6 +529,7 @@ redef class AClassdef
                var local_classes = mod.src_local_classes
                if (local_classes.has_key(name)) then
                        local_class = local_classes[name]
+                       _local_class = local_class
                        if self isa AStdClassdef then
                                # If we are not a special implicit class then rant
                                v.error(self, "Error: A class {name} is already defined at line {local_class.node.location.line_start}.")
@@ -540,15 +541,16 @@ redef class AClassdef
                        n.next_node = self
                else
                        local_class = new MMSrcLocalClass(mod, name, self, arity)
+                       _local_class = local_class
                        local_classes[name] = local_class
                        if not mod.has_global_class_named(name) then
-                               local_class.new_global
+                               build_class_introduction(v)
                        else
-                               local_class.set_global(mod.global_class_named(name))
+                               var glob = mod.global_class_named(name)
+                               build_class_refinement(v, glob)
                        end
 
                end
-               _local_class = local_class
                v.local_class_arity = 0
                v.formals = local_class.formal_dict
 
@@ -559,6 +561,70 @@ redef class AClassdef
                v.formals = null
        end
 
+       fun build_class_introduction(v: AbsSyntaxVisitor)
+       do
+               local_class.new_global
+               var glob = local_class.global
+
+               glob.visibility_level = visibility_level
+               if self isa AStdClassdef then
+                       if n_kwredef != null then
+                               v.error(self, "Redef error: No class {name} is imported. Remove the redef keyword to define a new class.")
+                               return
+                       end
+                       glob.is_interface = n_classkind.is_interface
+                       glob.is_abstract = n_classkind.is_abstract
+                       glob.is_enum = n_classkind.is_enum
+               end
+       end
+
+       fun build_class_refinement(v: AbsSyntaxVisitor, glob: MMGlobalClass)
+       do
+               local_class.set_global(glob)
+
+               glob.check_visibility(v, self, v.mmmodule)
+               if self isa AStdClassdef and n_kwredef == null then
+                       v.error(self, "Redef error: {name} is an imported class. Add the redef keyword to refine it.")
+                       return
+               end
+
+               if glob.intro.arity != _local_class.arity then
+                       v.error(self, "Redef error: Formal parameter arity missmatch; got {_local_class.arity}, expected {glob.intro.arity}.")
+               end
+
+               if self isa AStdClassdef and (not glob.is_interface and n_classkind.is_interface or
+                       not glob.is_abstract and n_classkind.is_abstract or
+                       not glob.is_enum and n_classkind.is_enum)
+               then
+                       v.error(self, "Redef error: cannot change kind of class {name}.")
+               end
+       end
+
+       redef fun accept_class_verifier(v)
+       do
+               super
+               var glob = _local_class.global
+               for c in _local_class.cshe.direct_greaters do
+                       var cg = c.global
+                       if glob.is_interface then
+                               if cg.is_enum then
+                                       v.error(self, "Special error: Interface {name} try to specialise enum class {c.name}.")
+                               else if not cg.is_interface then
+                                       v.error(self, "Special error: Interface {name} try to specialise class {c.name}.")
+                               end
+                       else if glob.is_enum then
+                               if not cg.is_interface and not cg.is_enum then
+                                       v.error(self, "Special error: Enum class {name} try to specialise class {c.name}.")
+                               end
+                       else
+                               if cg.is_enum then
+                                       v.error(self, "Special error: Class {name} try to specialise enum class {c.name}.")
+                               end
+                       end
+
+               end
+       end
+
        redef fun accept_abs_syntax_visitor(v)
        do
                v.local_class = _local_class
@@ -592,62 +658,6 @@ redef class AStdClassdef
        do
                return n_formaldefs.length
        end
-       redef fun accept_class_verifier(v)
-       do
-               super
-               var glob = _local_class.global
-               if glob.intro == _local_class then
-                       # Intro
-                       glob.visibility_level = visibility_level
-                       glob.is_interface = n_classkind.is_interface
-                       glob.is_abstract = n_classkind.is_abstract
-                       glob.is_enum = n_classkind.is_enum
-                       if n_kwredef != null then
-                               v.error(self, "Redef error: No class {name} is imported. Remove the redef keyword to define a new class.")
-                       end
-
-                       for c in _local_class.cshe.direct_greaters do
-                               var cg = c.global
-                               if glob.is_interface then
-                                       if cg.is_enum then
-                                               v.error(self, "Special error: Interface {name} try to specialise enum class {c.name}.")
-                                       else if not cg.is_interface then
-                                               v.error(self, "Special error: Interface {name} try to specialise class {c.name}.")
-                                       end
-                               else if glob.is_enum then
-                                       if not cg.is_interface and not cg.is_enum then
-                                               v.error(self, "Special error: Enum class {name} try to specialise class {c.name}.")
-                                       end
-                               else
-                                       if cg.is_enum then
-                                               v.error(self, "Special error: Class {name} try to specialise enum class {c.name}.")
-                                       end
-                               end
-
-                       end
-                       return
-               end
-
-               # Redef
-
-               glob.check_visibility(v, self, v.mmmodule)
-               if n_kwredef == null then
-                       v.error(self, "Redef error: {name} is an imported class. Add the redef keyword to refine it.")
-                       return
-               end
-
-               if glob.intro.arity != _local_class.arity then
-                       v.error(self, "Redef error: Formal parameter arity missmatch; got {_local_class.arity}, expected {glob.intro.arity}.")
-               end
-
-               if 
-                       not glob.is_interface and n_classkind.is_interface or
-                       not glob.is_abstract and n_classkind.is_abstract or
-                       not glob.is_enum and n_classkind.is_enum
-               then
-                       v.error(self, "Redef error: cannot change kind of class {name}.")
-               end
-       end
 
        redef fun visibility_level
        do
diff --git a/tests/error_class_generic.nit b/tests/error_class_generic.nit
new file mode 100644 (file)
index 0000000..ea85015
--- /dev/null
@@ -0,0 +1,26 @@
+# 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 array
+
+#alt1#redef class Array
+#alt2#redef class Array[E: Float]
+#alt3#redef class Array[E: Float, E: Int]
+#alt4#class Array
+#alt5#class Array[E: Float]
+#alt6#class Array[E: Float, E: Int]
+end
+
+var c: Array = 5
+c.output
index 510e4bd..0e778f9 100644 (file)
@@ -14,8 +14,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-class Object
-end
+import kernel
 
 class A
        super B
diff --git a/tests/sav/error_class_generic.sav b/tests/sav/error_class_generic.sav
new file mode 100644 (file)
index 0000000..1e64252
--- /dev/null
@@ -0,0 +1 @@
+./error_class_generic.nit:23,1--3: Syntax error: unexpected token.
diff --git a/tests/sav/error_class_generic_alt1.sav b/tests/sav/error_class_generic_alt1.sav
new file mode 100644 (file)
index 0000000..7c16aaf
--- /dev/null
@@ -0,0 +1 @@
+alt/error_class_generic_alt1.nit:17,1--17: Redef error: Formal parameter arity missmatch; got 0, expected 1.
diff --git a/tests/sav/error_class_generic_alt2.sav b/tests/sav/error_class_generic_alt2.sav
new file mode 100644 (file)
index 0000000..3d9a1ed
--- /dev/null
@@ -0,0 +1 @@
+alt/error_class_generic_alt2.nit:18,19--26: Redef error: Cannot change formal parameter type of class Array; got Float, expected nullable Object.
diff --git a/tests/sav/error_class_generic_alt3.sav b/tests/sav/error_class_generic_alt3.sav
new file mode 100644 (file)
index 0000000..099b01d
--- /dev/null
@@ -0,0 +1 @@
+alt/error_class_generic_alt3.nit:17,1--19,34: Redef error: Formal parameter arity missmatch; got 2, expected 1.
diff --git a/tests/sav/error_class_generic_alt4.sav b/tests/sav/error_class_generic_alt4.sav
new file mode 100644 (file)
index 0000000..b9e726b
--- /dev/null
@@ -0,0 +1 @@
+alt/error_class_generic_alt4.nit:17,1--20,11: Redef error: Array is an imported class. Add the redef keyword to refine it.
diff --git a/tests/sav/error_class_generic_alt5.sav b/tests/sav/error_class_generic_alt5.sav
new file mode 100644 (file)
index 0000000..bcb709d
--- /dev/null
@@ -0,0 +1 @@
+alt/error_class_generic_alt5.nit:17,1--21,20: Redef error: Array is an imported class. Add the redef keyword to refine it.
diff --git a/tests/sav/error_class_generic_alt6.sav b/tests/sav/error_class_generic_alt6.sav
new file mode 100644 (file)
index 0000000..5f03dfb
--- /dev/null
@@ -0,0 +1 @@
+alt/error_class_generic_alt6.nit:17,1--22,28: Redef error: Array is an imported class. Add the redef keyword to refine it.
index 9a13498..47b6ec1 100644 (file)
@@ -19,7 +19,7 @@ class A
        type U: B
        fun foo(a: T) do a.out
        fun bar(b: U) do b.out
-       fun baz(i: Int) do i.out
+       fun baz(i: C) do i.out
        fun out do 'A'.output
 
        init do end
@@ -28,37 +28,37 @@ end
 class B
        super A
        redef type T: B
-       redef type U: Int
+       redef type U: C
        redef fun foo(a: T) do a.out
        redef fun bar(b: U) do b.out
-       redef fun baz(i: Int) do i.out
+       redef fun baz(i: C) do i.out
        redef fun out do 'B'.output
 
        init do end
 end
 
-redef class Int
+class C
        super B
-       redef type T: Int
+       redef type T: C
        redef fun foo(a: T) do a.out
        redef fun bar(b: U) do b.out
-       redef fun output is intern
+       redef fun output do i.output
        redef fun out
        do
                var i: Object = self
-               if i isa Int then
+               if i isa C then
                        i.output
                else
                        'X'.output
                end
        end
-
+       var i: Int
+       init (i:Int) do self.i = i
 end
-
 var a = new A
 var b = new B
 var ab: A = b
-var i = 5
+var i = new C(5)
 var ai: A = i
 var bi: B = i
 
index 5e19834..107a202 100644 (file)
@@ -25,9 +25,9 @@ class A
            return new B 
     end
     
-    fun baz: Int 
+    fun baz: C
     do 
-           return 5 
+           return new C(5)
     end
     
     redef fun output 
@@ -44,13 +44,13 @@ class B
     do 
            return new B 
     end
-    redef fun bar: Int 
+    redef fun bar: C
     do 
-           return 6 
+           return new C(6)
     end
-    redef fun baz: Int 
+    redef fun baz: C 
     do 
-           return 7 
+           return new C(7)
     end
     redef fun output 
     do 
@@ -59,24 +59,24 @@ class B
 
     init do end
 end
-
-redef class Int
+class C
        super B
-    redef fun foo: Int 
+    redef fun foo: C
     do 
-           return 8 
+           return new C(8) 
     end
-    redef fun bar: Int 
+    redef fun bar: C 
     do
-           return 9
+           return new C(9)
     end
-    redef fun output is intern
+    redef fun output do i.output
+    var i: Int
+    init (i: Int) do self.i = i
 end
-
 var a = new A
 var b = new B
 var ab: A = b
-var i = 5
+var i = new C(5)
 var ai: A = i
 var bi: B = i