From: Jean Privat Date: Tue, 17 Jun 2014 01:14:04 +0000 (-0400) Subject: Merge: Give top-level methods some rules X-Git-Tag: v0.6.6~29 X-Git-Url: http://nitlanguage.org?hp=d630b33bfbef8394cc58a373f2997f1b13600283 Merge: Give top-level methods some rules 1. explicit `self` is forbidden in top-level method 2. top-level methods can only be called without a explicit receiver In the code, there is workarounds for 3 hard-coded special cases: * `sys` and `exit`: because, for an unknown reason, intern method cannot be top-level. #493 * `args` because it is currently both in Sys and Object thus has a crazy status. #461 These rules are only enforced as it in `typing` but does not change the model, tools, or engines. Note: the first commits fix a bug in the `for` where the implicit `iterator` method was resolved with the `recv_is_self` flag always set to true. Pull-Request: #494 Reviewed-by: Alexandre Terrasa Reviewed-by: Lucas Bajolet --- diff --git a/src/typing.nit b/src/typing.nit index edb1c89..5db0ada 100644 --- a/src/typing.nit +++ b/src/typing.nit @@ -51,6 +51,11 @@ private class TypeVisitor var selfvariable: Variable = new Variable("self") + # Is `self` use restricted? + # * no explicit `self` + # * method called on the implicit self must be top-level + var is_toplevel_context = false + init(modelbuilder: ModelBuilder, mmodule: MModule, mpropdef: nullable MPropDef) do self.modelbuilder = modelbuilder @@ -67,6 +72,11 @@ private class TypeVisitor var selfvariable = new Variable("self") self.selfvariable = selfvariable selfvariable.declared_type = mclass.mclass_type + + var mprop = mpropdef.mproperty + if mprop isa MMethod and mprop.is_toplevel then + is_toplevel_context = true + end end end @@ -241,6 +251,15 @@ private class TypeVisitor end assert mproperty isa MMethod + + if is_toplevel_context and recv_is_self and not mproperty.is_toplevel and name != "sys" and name != "exit" and name != "args" then + # FIXME named methods are here as a workaround + error(node, "Error: '{name}' is not a top-level method, thus need a receiver.") + end + if not recv_is_self and mproperty.is_toplevel then + error(node, "Error: cannot call '{name}', a top-level method, with a receiver.") + end + if mproperty.visibility == protected_visibility and not recv_is_self and self.mmodule.visibility_for(mproperty.intro_mclassdef.mmodule) < intrude_visibility and not modelbuilder.toolcontext.opt_ignore_visibility.value then self.modelbuilder.error(node, "Error: Method '{name}' is protected and can only acceded by self.") return null @@ -833,7 +852,7 @@ redef class AForExpr if objcla == null then return # check iterator method - var itdef = v.get_method(self, mtype, "iterator", true) + var itdef = v.get_method(self, mtype, "iterator", n_expr isa ASelfExpr) if itdef == null then v.error(self, "Type Error: 'for' expects a type providing 'iterator' method, got '{mtype}'.") return @@ -1199,6 +1218,9 @@ redef class ASelfExpr redef var its_variable: nullable Variable redef fun accept_typing(v) do + if v.is_toplevel_context and not self isa AImplicitSelfExpr then + v.error(self, "Error: self cannot be used in top-level method.") + end var variable = v.selfvariable self.its_variable = variable self.mtype = v.get_variable(self, variable) diff --git a/tests/error_toplevel.nit b/tests/error_toplevel.nit new file mode 100644 index 0000000..c33bcb0 --- /dev/null +++ b/tests/error_toplevel.nit @@ -0,0 +1,49 @@ +# 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 + +redef class Object + fun baz do + output + end + + fun foo1 + do + bar(1) + bar(self) + #alt1#3.bar(3) + + 5.baz + baz + end +end + +fun foo2 +do + bar(10) + #alt2#self.bar(20) + #alt3#bar(self) + #alt4#4.bar(40) + + 50.baz + #alt5#baz +end + +fun bar(o: Object) +do + o.output +end + +0.foo1 +foo2 diff --git a/tests/sav/base_iterator3.res b/tests/sav/base_iterator3.res index 7711bba..8163c32 100644 --- a/tests/sav/base_iterator3.res +++ b/tests/sav/base_iterator3.res @@ -1,6 +1,6 @@ base_iterator3.nit:35,1--25: Type Error: 'for' expects method 'iterator' to return an 'Iterator' or 'MapIterator' type'. base_iterator3.nit:39,1--25: Type Error: 'for' expects method 'iterator' to return an 'Iterator' or 'MapIterator' type'. -base_iterator3.nit:43,1--25: Error: Method or variable 'iterator' unknown in Test3. +base_iterator3.nit:43,1--25: Error: Method 'iterator' doesn't exists in Test3. base_iterator3.nit:43,1--25: Type Error: 'for' expects a type providing 'iterator' method, got 'Test3'. base_iterator3.nit:46,1--48: Type Error: 'for' expects only one variable when using 'Iterator'. base_iterator3.nit:47,1--47: Type Error: 'for' expects two variables when using 'MapIterator'. diff --git a/tests/sav/error_expr_not_ok_alt4.res b/tests/sav/error_expr_not_ok_alt4.res index ac5bee9..3919001 100644 --- a/tests/sav/error_expr_not_ok_alt4.res +++ b/tests/sav/error_expr_not_ok_alt4.res @@ -10,6 +10,7 @@ alt/error_expr_not_ok_alt4.nit:43,1--8: Error: Method 'fail' doesn't exists in I alt/error_expr_not_ok_alt4.nit:45,7--10: Type error: expected A, got Object alt/error_expr_not_ok_alt4.nit:46,1--9: Error: Method 'fail' doesn't exists in Object. alt/error_expr_not_ok_alt4.nit:49,7--10: Type error: expected A, got Object +alt/error_expr_not_ok_alt4.nit:50,1--10: Error: cannot call 'trash', a top-level method, with a receiver. alt/error_expr_not_ok_alt4.nit:50,1--10: Error: Incorrect number of parameters. Got 0, expected 1. Signature is (x: A) alt/error_expr_not_ok_alt4.nit:60,4--7: Type error: expected Bool, got Int alt/error_expr_not_ok_alt4.nit:60,20: Type error: expected A, got Int @@ -22,7 +23,7 @@ alt/error_expr_not_ok_alt4.nit:66,21: Type error: expected A, got Int alt/error_expr_not_ok_alt4.nit:67,1--18: Warning: use 'loop' instead of 'while true do'. alt/error_expr_not_ok_alt4.nit:69,24: Type error: expected A, got Int alt/error_expr_not_ok_alt4.nit:69,1--25: Type Error: 'for' expects a type providing 'iterator' method, got 'Int'. -alt/error_expr_not_ok_alt4.nit:69,1--25: Error: Method or variable 'iterator' unknown in Int. +alt/error_expr_not_ok_alt4.nit:69,1--25: Error: Method 'iterator' doesn't exists in Int. alt/error_expr_not_ok_alt4.nit:71,8--11: Type error: expected Bool, got Int alt/error_expr_not_ok_alt4.nit:72,7--15: Type error: expected A, got Int alt/error_expr_not_ok_alt4.nit:73,7--10: Type error: expected Bool, got Int diff --git a/tests/sav/error_expr_not_ok_alt5.res b/tests/sav/error_expr_not_ok_alt5.res index 7b7b730..d9dd373 100644 --- a/tests/sav/error_expr_not_ok_alt5.res +++ b/tests/sav/error_expr_not_ok_alt5.res @@ -18,7 +18,7 @@ alt/error_expr_not_ok_alt5.nit:66,21: Type error: expected A, got Int alt/error_expr_not_ok_alt5.nit:67,1--18: Warning: use 'loop' instead of 'while true do'. alt/error_expr_not_ok_alt5.nit:69,24: Type error: expected A, got Int alt/error_expr_not_ok_alt5.nit:69,1--25: Type Error: 'for' expects a type providing 'iterator' method, got 'Int'. -alt/error_expr_not_ok_alt5.nit:69,1--25: Error: Method or variable 'iterator' unknown in Int. +alt/error_expr_not_ok_alt5.nit:69,1--25: Error: Method 'iterator' doesn't exists in Int. alt/error_expr_not_ok_alt5.nit:71,8--11: Type error: expected Bool, got Int alt/error_expr_not_ok_alt5.nit:72,7--15: Type error: expected A, got Int alt/error_expr_not_ok_alt5.nit:73,7--10: Type error: expected Bool, got Int diff --git a/tests/sav/error_expr_not_ok_alt6.res b/tests/sav/error_expr_not_ok_alt6.res index 50c3b32..212ed6f 100644 --- a/tests/sav/error_expr_not_ok_alt6.res +++ b/tests/sav/error_expr_not_ok_alt6.res @@ -22,7 +22,7 @@ alt/error_expr_not_ok_alt6.nit:66,21: Type error: expected A, got Int alt/error_expr_not_ok_alt6.nit:67,1--18: Warning: use 'loop' instead of 'while true do'. alt/error_expr_not_ok_alt6.nit:69,24: Type error: expected A, got Int alt/error_expr_not_ok_alt6.nit:69,1--25: Type Error: 'for' expects a type providing 'iterator' method, got 'Int'. -alt/error_expr_not_ok_alt6.nit:69,1--25: Error: Method or variable 'iterator' unknown in Int. +alt/error_expr_not_ok_alt6.nit:69,1--25: Error: Method 'iterator' doesn't exists in Int. alt/error_expr_not_ok_alt6.nit:71,8--11: Type error: expected Bool, got Int alt/error_expr_not_ok_alt6.nit:72,7--15: Type error: expected A, got Int alt/error_expr_not_ok_alt6.nit:73,7--10: Type error: expected Bool, got Int diff --git a/tests/sav/error_for_coll.res b/tests/sav/error_for_coll.res index d507465..4aa3dcd 100644 --- a/tests/sav/error_for_coll.res +++ b/tests/sav/error_for_coll.res @@ -1,2 +1,2 @@ -error_for_coll.nit:17,1--18,3: Error: Method or variable 'iterator' unknown in Int. +error_for_coll.nit:17,1--18,3: Error: Method 'iterator' doesn't exists in Int. error_for_coll.nit:17,1--18,3: Type Error: 'for' expects a type providing 'iterator' method, got 'Int'. diff --git a/tests/sav/error_needed_method_alt2.res b/tests/sav/error_needed_method_alt2.res index 849db8b..8747eab 100644 --- a/tests/sav/error_needed_method_alt2.res +++ b/tests/sav/error_needed_method_alt2.res @@ -1,3 +1,3 @@ alt/error_needed_method_alt2.nit:47,10--27: Cannot instantiate interface Collection[Int]. -alt/error_needed_method_alt2.nit:47,1--40: Error: Method or variable 'iterator' unknown in Collection[Int]. +alt/error_needed_method_alt2.nit:47,1--40: Error: Method 'iterator' doesn't exists in Collection[Int]. alt/error_needed_method_alt2.nit:47,1--40: Type Error: 'for' expects a type providing 'iterator' method, got 'Collection[Int]'. diff --git a/tests/sav/error_needed_types_alt8.res b/tests/sav/error_needed_types_alt8.res index 2a2c208..f8c5a4f 100644 --- a/tests/sav/error_needed_types_alt8.res +++ b/tests/sav/error_needed_types_alt8.res @@ -1,2 +1,2 @@ -alt/error_needed_types_alt8.nit:21,1--22,3: Error: Method or variable 'iterator' unknown in L. +alt/error_needed_types_alt8.nit:21,1--22,3: Error: Method 'iterator' doesn't exists in L. alt/error_needed_types_alt8.nit:21,1--22,3: Type Error: 'for' expects a type providing 'iterator' method, got 'L'. diff --git a/tests/sav/error_toplevel.res b/tests/sav/error_toplevel.res new file mode 100644 index 0000000..f00464b --- /dev/null +++ b/tests/sav/error_toplevel.res @@ -0,0 +1,6 @@ +1 +0 +5 +0 +10 +50 diff --git a/tests/sav/error_toplevel_alt1.res b/tests/sav/error_toplevel_alt1.res new file mode 100644 index 0000000..b18282f --- /dev/null +++ b/tests/sav/error_toplevel_alt1.res @@ -0,0 +1 @@ +alt/error_toplevel_alt1.nit:25,3--10: Error: cannot call 'bar', a top-level method, with a receiver. diff --git a/tests/sav/error_toplevel_alt2.res b/tests/sav/error_toplevel_alt2.res new file mode 100644 index 0000000..8b3cf76 --- /dev/null +++ b/tests/sav/error_toplevel_alt2.res @@ -0,0 +1 @@ +alt/error_toplevel_alt2.nit:35,2--5: Error: self cannot be used in top-level method. diff --git a/tests/sav/error_toplevel_alt3.res b/tests/sav/error_toplevel_alt3.res new file mode 100644 index 0000000..acfd7bf --- /dev/null +++ b/tests/sav/error_toplevel_alt3.res @@ -0,0 +1 @@ +alt/error_toplevel_alt3.nit:36,6--9: Error: self cannot be used in top-level method. diff --git a/tests/sav/error_toplevel_alt4.res b/tests/sav/error_toplevel_alt4.res new file mode 100644 index 0000000..c1a37ee --- /dev/null +++ b/tests/sav/error_toplevel_alt4.res @@ -0,0 +1 @@ +alt/error_toplevel_alt4.nit:37,2--10: Error: cannot call 'bar', a top-level method, with a receiver. diff --git a/tests/sav/error_toplevel_alt5.res b/tests/sav/error_toplevel_alt5.res new file mode 100644 index 0000000..dff56d2 --- /dev/null +++ b/tests/sav/error_toplevel_alt5.res @@ -0,0 +1 @@ +alt/error_toplevel_alt5.nit:40,2--4: Error: 'baz' is not a top-level method, thus need a receiver.