From 3a7f235c96176ceaac978f6cb0d44d3dadb668f6 Mon Sep 17 00:00:00 2001 From: Jean Privat Date: Fri, 25 Mar 2011 21:03:15 -0400 Subject: [PATCH] typing: move redef class check before inheritance 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 --- src/syntax/mmbuilder.nit | 128 +++++++++++++++++--------------- tests/error_class_generic.nit | 26 +++++++ tests/error_inh_loop.nit | 3 +- tests/sav/error_class_generic.sav | 1 + tests/sav/error_class_generic_alt1.sav | 1 + tests/sav/error_class_generic_alt2.sav | 1 + tests/sav/error_class_generic_alt3.sav | 1 + tests/sav/error_class_generic_alt4.sav | 1 + tests/sav/error_class_generic_alt5.sav | 1 + tests/sav/error_class_generic_alt6.sav | 1 + tests/test_variance_param.nit | 20 ++--- tests/test_variance_ret.nit | 30 ++++---- 12 files changed, 128 insertions(+), 86 deletions(-) create mode 100644 tests/error_class_generic.nit create mode 100644 tests/sav/error_class_generic.sav create mode 100644 tests/sav/error_class_generic_alt1.sav create mode 100644 tests/sav/error_class_generic_alt2.sav create mode 100644 tests/sav/error_class_generic_alt3.sav create mode 100644 tests/sav/error_class_generic_alt4.sav create mode 100644 tests/sav/error_class_generic_alt5.sav create mode 100644 tests/sav/error_class_generic_alt6.sav diff --git a/src/syntax/mmbuilder.nit b/src/syntax/mmbuilder.nit index ce875a8..1fd92f3 100644 --- a/src/syntax/mmbuilder.nit +++ b/src/syntax/mmbuilder.nit @@ -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 index 0000000..ea85015 --- /dev/null +++ b/tests/error_class_generic.nit @@ -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 diff --git a/tests/error_inh_loop.nit b/tests/error_inh_loop.nit index 510e4bd..0e778f9 100644 --- a/tests/error_inh_loop.nit +++ b/tests/error_inh_loop.nit @@ -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 index 0000000..1e64252 --- /dev/null +++ b/tests/sav/error_class_generic.sav @@ -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 index 0000000..7c16aaf --- /dev/null +++ b/tests/sav/error_class_generic_alt1.sav @@ -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 index 0000000..3d9a1ed --- /dev/null +++ b/tests/sav/error_class_generic_alt2.sav @@ -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 index 0000000..099b01d --- /dev/null +++ b/tests/sav/error_class_generic_alt3.sav @@ -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 index 0000000..b9e726b --- /dev/null +++ b/tests/sav/error_class_generic_alt4.sav @@ -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 index 0000000..bcb709d --- /dev/null +++ b/tests/sav/error_class_generic_alt5.sav @@ -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 index 0000000..5f03dfb --- /dev/null +++ b/tests/sav/error_class_generic_alt6.sav @@ -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. diff --git a/tests/test_variance_param.nit b/tests/test_variance_param.nit index 9a13498..47b6ec1 100644 --- a/tests/test_variance_param.nit +++ b/tests/test_variance_param.nit @@ -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 diff --git a/tests/test_variance_ret.nit b/tests/test_variance_ret.nit index 5e19834..107a202 100644 --- a/tests/test_variance_ret.nit +++ b/tests/test_variance_ret.nit @@ -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 -- 1.7.9.5