Merge: Give top-level methods some rules
authorJean Privat <jean@pryen.org>
Tue, 17 Jun 2014 01:14:04 +0000 (21:14 -0400)
committerJean Privat <jean@pryen.org>
Tue, 17 Jun 2014 01:14:04 +0000 (21:14 -0400)
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 <alexandre@moz-code.org>
Reviewed-by: Lucas Bajolet <r4pass@hotmail.com>

15 files changed:
src/typing.nit
tests/error_toplevel.nit [new file with mode: 0644]
tests/sav/base_iterator3.res
tests/sav/error_expr_not_ok_alt4.res
tests/sav/error_expr_not_ok_alt5.res
tests/sav/error_expr_not_ok_alt6.res
tests/sav/error_for_coll.res
tests/sav/error_needed_method_alt2.res
tests/sav/error_needed_types_alt8.res
tests/sav/error_toplevel.res [new file with mode: 0644]
tests/sav/error_toplevel_alt1.res [new file with mode: 0644]
tests/sav/error_toplevel_alt2.res [new file with mode: 0644]
tests/sav/error_toplevel_alt3.res [new file with mode: 0644]
tests/sav/error_toplevel_alt4.res [new file with mode: 0644]
tests/sav/error_toplevel_alt5.res [new file with mode: 0644]

index edb1c89..5db0ada 100644 (file)
@@ -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 (file)
index 0000000..c33bcb0
--- /dev/null
@@ -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
index 7711bba..8163c32 100644 (file)
@@ -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'.
index ac5bee9..3919001 100644 (file)
@@ -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
index 7b7b730..d9dd373 100644 (file)
@@ -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
index 50c3b32..212ed6f 100644 (file)
@@ -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
index d507465..4aa3dcd 100644 (file)
@@ -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'.
index 849db8b..8747eab 100644 (file)
@@ -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]'.
index 2a2c208..f8c5a4f 100644 (file)
@@ -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 (file)
index 0000000..f00464b
--- /dev/null
@@ -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 (file)
index 0000000..b18282f
--- /dev/null
@@ -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 (file)
index 0000000..8b3cf76
--- /dev/null
@@ -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 (file)
index 0000000..acfd7bf
--- /dev/null
@@ -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 (file)
index 0000000..c1a37ee
--- /dev/null
@@ -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 (file)
index 0000000..dff56d2
--- /dev/null
@@ -0,0 +1 @@
+alt/error_toplevel_alt5.nit:40,2--4: Error: 'baz' is not a top-level method, thus need a receiver.