Merge: Autocast and literal arrays
authorJean Privat <jean@pryen.org>
Sat, 18 Apr 2015 09:47:17 +0000 (16:47 +0700)
committerJean Privat <jean@pryen.org>
Sat, 18 Apr 2015 09:47:17 +0000 (16:47 +0700)
Small bugfixes

* forbid autocasts in combined assignments and literal arrays
* keep autocast information in transform
* rta visits implicit methods of literal arrays

Only the first one was the original bug I wanted to fix, the two others where discovered and solved while writing the PR.

Pull-Request: #1272
Reviewed-by: Alexis Laferrière <alexis.laf@xymus.net>
Reviewed-by: Romain Chanoir <chanoir.romain@courrier.uqam.ca>

lib/standard/string_search.nit
src/metrics/detect_covariance.nit
src/rapid_type_analysis.nit
src/semantize/typing.nit
src/transform.nit
tests/base_autocast_array.nit [new file with mode: 0644]
tests/sav/base_autocast_array.res [new file with mode: 0644]
tests/sav/base_autocast_array_alt1.res [new file with mode: 0644]
tests/sav/base_autocast_array_alt2.res [new file with mode: 0644]
tests/sav/base_autocast_array_alt3.res [new file with mode: 0644]
tests/sav/nitg-e/base_autocast_array_alt2.res [new file with mode: 0644]

index 3a885ad..437341f 100644 (file)
@@ -388,8 +388,14 @@ redef class Text
        fun split_once_on(p: Pattern): Array[SELFTYPE]
        do
                var m = p.search_in(self, 0)
-               if m == null then return [self]
-               return new Array[SELFTYPE].with_items(substring(0, m.from), substring_from(m.after))
+               var res = new Array[SELFTYPE]
+               if m == null then
+                       res.add self
+               else
+                       res.add substring(0, m.from)
+                       res.add substring_from(m.after)
+               end
+               return res
        end
 
        # Replace all occurences of a pattern with a string
index 4a3437d..1ab719b 100644 (file)
@@ -343,7 +343,7 @@ redef class TypeVisitor
                return sub
        end
 
-       redef fun check_subtype(node: ANode, sub, sup: MType): nullable MType
+       redef fun check_subtype(node: ANode, sub, sup: MType, autocast: Bool): nullable MType
        do
                var res = super
 
@@ -361,6 +361,9 @@ redef class TypeVisitor
                        if node isa AAsCastExpr then
                                return res
                        end
+                       if not autocast then
+                               return res
+                       end
                        sup = supx.resolve_for(anchor.mclass.mclass_type, anchor, mmodule, true)
                        if self.is_subtype(sub, sup) then
                                dcp.cpt_autocast.inc("vt")
index 3f81bf8..81e14fa 100644 (file)
@@ -540,6 +540,8 @@ redef class AArrayExpr
                mtype = v.cleanup_type(mtype).as(not null)
                var prop = v.get_method(mtype, "with_native")
                v.add_monomorphic_send(mtype, prop)
+               v.add_callsite(with_capacity_callsite)
+               v.add_callsite(push_callsite)
        end
 end
 
index 8fe169d..97e200c 100644 (file)
@@ -105,13 +105,13 @@ private class TypeVisitor
        # If `sub` is a safe subtype of `sup` then return `sub`.
        # If `sub` is an unsafe subtype (ie an implicit cast is required), then return `sup`.
        #
-       # The point of the return type is to determinate the usable type on an expression:
+       # The point of the return type is to determinate the usable type on an expression when `autocast` is true:
        # If the suptype is safe, then the return type is the one on the expression typed by `sub`.
        # Is the subtype is unsafe, then the return type is the one of an implicit cast on `sup`.
-       fun check_subtype(node: ANode, sub, sup: MType): nullable MType
+       fun check_subtype(node: ANode, sub, sup: MType, autocast: Bool): nullable MType
        do
                if self.is_subtype(sub, sup) then return sub
-               if self.is_subtype(sub, self.anchor_to(sup)) then
+               if autocast and self.is_subtype(sub, self.anchor_to(sup)) then
                        # FIXME workaround to the current unsafe typing policy. To remove once fixed virtual types exists.
                        #node.debug("Unsafe typing: expected {sup}, got {sub}")
                        return sup
@@ -166,7 +166,7 @@ private class TypeVisitor
 
                if sup == null then return null # Forward error
 
-               var res = check_subtype(nexpr, sub, sup)
+               var res = check_subtype(nexpr, sub, sup, true)
                if res != sub then
                        nexpr.implicit_cast_to = res
                end
@@ -868,7 +868,7 @@ redef class AReassignFormExpr
                var value_type = v.visit_expr_subtype(self.n_value, msignature.mparameters.first.mtype)
                if value_type == null then return null # Skip error
 
-               v.check_subtype(self, rettype, writetype)
+               v.check_subtype(self, rettype, writetype, false)
                return rettype
        end
 end
@@ -1360,7 +1360,7 @@ redef class AArrayExpr
                        end
                        set_comprehension(e)
                        if mtype != null then
-                               if v.check_subtype(e, t, mtype) == null then return # Skip error
+                               if v.check_subtype(e, t, mtype, false) == null then return # Forward error
                                if t == mtype then useless = true
                        else
                                mtypes.add(t)
index 118142a..4fa28c0 100644 (file)
@@ -20,6 +20,7 @@ import astbuilder
 import astvalidation
 import semantize
 intrude import semantize::scope
+intrude import semantize::typing
 
 redef class ToolContext
        var transform_phase: Phase = new TransformPhase(self, [typing_phase, auto_super_init_phase])
@@ -105,6 +106,14 @@ redef class AExpr
                end
                super
        end
+
+       redef fun replace_with(other)
+       do
+               super
+               if other isa AExpr then
+                       if other.implicit_cast_to == null then other.implicit_cast_to = implicit_cast_to
+               end
+       end
 end
 
 redef class AVardeclExpr
diff --git a/tests/base_autocast_array.nit b/tests/base_autocast_array.nit
new file mode 100644 (file)
index 0000000..9beb291
--- /dev/null
@@ -0,0 +1,45 @@
+# 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 standard::collection::array
+
+class A
+       type V: nullable Object
+       var v: V
+
+       fun test_array: Array[V]
+       do
+               #alt3#v = 10
+               return [v] #alt1-2#
+               #alt1#return [10:V]
+               #alt2#return [10]
+       end
+end
+
+class B
+       super A
+       redef type V: Bool
+end
+
+var a = new A(1)
+
+a.test_array.first.output
+
+var ab = new A(true)
+
+ab.test_array.first.output
+
+var b = new B(true)
+
+b.test_array.first.output
diff --git a/tests/sav/base_autocast_array.res b/tests/sav/base_autocast_array.res
new file mode 100644 (file)
index 0000000..9acd049
--- /dev/null
@@ -0,0 +1,3 @@
+1
+true
+true
diff --git a/tests/sav/base_autocast_array_alt1.res b/tests/sav/base_autocast_array_alt1.res
new file mode 100644 (file)
index 0000000..0c8e503
--- /dev/null
@@ -0,0 +1 @@
+alt/base_autocast_array_alt1.nit:25,11--12: Type Error: expected `V`, got `Int`.
diff --git a/tests/sav/base_autocast_array_alt2.res b/tests/sav/base_autocast_array_alt2.res
new file mode 100644 (file)
index 0000000..f8e020c
--- /dev/null
@@ -0,0 +1,3 @@
+Runtime error: Cast failed. Expected `Array[V]`, got `Array[Int]` (alt/base_autocast_array_alt2.nit:26)
+10
+10
diff --git a/tests/sav/base_autocast_array_alt3.res b/tests/sav/base_autocast_array_alt3.res
new file mode 100644 (file)
index 0000000..a93fcc4
--- /dev/null
@@ -0,0 +1,3 @@
+Runtime error: Cast failed. Expected `V`, got `Int` (alt/base_autocast_array_alt3.nit:23)
+10
+10
diff --git a/tests/sav/nitg-e/base_autocast_array_alt2.res b/tests/sav/nitg-e/base_autocast_array_alt2.res
new file mode 100644 (file)
index 0000000..91b441c
--- /dev/null
@@ -0,0 +1,3 @@
+Runtime error: Cast failed (alt/base_autocast_array_alt2.nit:45)
+10
+10