Merge: FFI clean up
authorJean Privat <jean@pryen.org>
Mon, 8 Jun 2015 15:03:10 +0000 (11:03 -0400)
committerJean Privat <jean@pryen.org>
Mon, 8 Jun 2015 15:03:10 +0000 (11:03 -0400)
Pull-Request: #1442
Reviewed-by: Jean Privat <jean@pryen.org>
Reviewed-by: Romain Chanoir <chanoir.romain@courrier.uqam.ca>
Reviewed-by: Alexandre Terrasa <alexandre@moz-code.org>

20 files changed:
src/compiler/abstract_compiler.nit
src/compiler/separate_compiler.nit
src/frontend/simple_misc_analysis.nit
src/loader.nit
src/nitni/nitni_base.nit
src/phase.nit
src/rapid_type_analysis.nit
src/semantize/typing.nit
src/transform.nit
tests/base_adaptive_loop3.nit
tests/base_adaptive_loop_null.nit
tests/base_do_block.nit [new file with mode: 0644]
tests/sav/base_do_block.res [new file with mode: 0644]
tests/sav/base_import_alt3.res
tests/sav/error_mod_unk.res
tests/sav/test_ffi_c_primitives.res
tests/sav/test_keep_going.res [new file with mode: 0644]
tests/sav/xymus_net.res
tests/test_ffi_c_primitives.nit
tests/test_keep_going.nit [new file with mode: 0755]

index a095201..9d3b0f3 100644 (file)
@@ -1672,8 +1672,9 @@ abstract class AbstractCompilerVisitor
                if nexpr == null then return
                if nexpr.mtype == null and not nexpr.is_typed then
                        # Untyped expression.
-                       # Might mean dead code
-                       # So just return
+                       # Might mean dead code or invalid code
+                       # so aborts
+                       add_abort("FATAL: bad statement executed.")
                        return
                end
 
@@ -1697,8 +1698,10 @@ abstract class AbstractCompilerVisitor
        do
                if nexpr.mtype == null then
                        # Untyped expression.
-                       # Might mean dead code
-                       # so return a placebo result
+                       # Might mean dead code or invalid code.
+                       # so aborts
+                       add_abort("FATAL: bad expression executed.")
+                       # and return a placebo result to please the C compiler
                        if mtype == null then mtype = compiler.mainmodule.object_type
                        return new_var(mtype)
                end
index f50a2a7..e07f125 100644 (file)
@@ -625,6 +625,7 @@ class SeparateCompiler
                for cd in mmodule.mclassdefs do
                        for pd in cd.mpropdefs do
                                if not pd isa MMethodDef then continue
+                               if pd.msignature == null then continue # Skip broken method
                                var rta = runtime_type_analysis
                                if modelbuilder.toolcontext.opt_skip_dead_methods.value and rta != null and not rta.live_methoddefs.has(pd) then continue
                                #print "compile {pd} @ {cd} @ {mmodule}"
index 885d794..f61b10a 100644 (file)
@@ -65,6 +65,14 @@ private class SimpleMiscVisitor
        do
                toolcontext.warning(node.hot_location, tag, msg)
        end
+
+       # Issue a warning if `sub` is a standalone `do` block.
+       fun check_do_expr(sub: nullable AExpr)
+       do
+               if sub isa ADoExpr then
+                       warning(sub, "useless-do", "Warning: superfluous `do` block.")
+               end
+       end
 end
 
 
@@ -143,6 +151,21 @@ redef class AWhileExpr
                else
                        n_expr.warn_parentheses(v)
                end
+               v.check_do_expr(n_block)
+       end
+end
+
+redef class ADoExpr
+       redef fun after_simple_misc(v)
+       do
+               v.check_do_expr(n_block)
+       end
+end
+
+redef class ALoopExpr
+       redef fun after_simple_misc(v)
+       do
+               v.check_do_expr(n_block)
        end
 end
 
@@ -150,6 +173,14 @@ redef class AForExpr
        redef fun after_simple_misc(v)
        do
                n_expr.warn_parentheses(v)
+               v.check_do_expr(n_block)
+       end
+end
+
+redef class AWithExpr
+       redef fun after_simple_misc(v)
+       do
+               v.check_do_expr(n_block)
        end
 end
 
index 0e6878b..d78ac71 100644 (file)
@@ -50,7 +50,9 @@ redef class ModelBuilder
                end
 
                var nit_dir = toolcontext.nit_dir
-               var libname = "{nit_dir}/lib"
+               var libname = nit_dir/"lib"
+               if libname.file_exists then paths.add(libname)
+               libname = nit_dir/"contrib"
                if libname.file_exists then paths.add(libname)
        end
 
@@ -222,6 +224,14 @@ redef class ModelBuilder
                                return res
                        end
 
+                       # Fourth, try if the requested module is itself a group with a src
+                       try_file = dirname + "/" + name + "/src/" + name + ".nit"
+                       if try_file.file_exists then
+                               var res = self.identify_file(try_file.simplify_path)
+                               assert res != null
+                               return res
+                       end
+
                        c = c.parent
                end
 
@@ -301,6 +311,19 @@ redef class ModelBuilder
                                        end
                                end
                        end
+                       try_file = (dirname + "/" + name + "/src/" + name + ".nit").simplify_path
+                       if try_file.file_exists then
+                               if candidate == null then
+                                       candidate = try_file
+                               else if candidate != try_file then
+                                       # try to disambiguate conflicting modules
+                                       var abs_candidate = module_absolute_path(candidate)
+                                       var abs_try_file = module_absolute_path(try_file)
+                                       if abs_candidate != abs_try_file then
+                                               toolcontext.error(location, "Error: conflicting module file for `{name}`: `{candidate}` `{try_file}`")
+                                       end
+                               end
+                       end
                end
                if candidate == null then return null
                return identify_file(candidate)
index 846f944..f5cccc0 100644 (file)
@@ -121,7 +121,7 @@ redef class MClassType
        redef fun mangled_cname do return mclass.name
 
        redef fun is_cprimitive do return mclass.kind == extern_kind or
-                       (once ["Bool", "Char", "Float", "Int", "NativeString"]).has(mclass.name)
+                       (once ["Bool", "Char", "Float", "Int", "NativeString", "Byte"]).has(mclass.name)
 end
 
 redef class MNullableType
index 5f0faf1..682d23e 100644 (file)
@@ -115,7 +115,6 @@ redef class ToolContext
                                phase.process_nmodule(nmodule)
                                if errcount != self.error_count then
                                        self.check_errors
-                                       break
                                end
                                errcount = self.error_count
                                for nclassdef in nmodule.n_classdefs do
@@ -128,7 +127,6 @@ redef class ToolContext
                                end
                                if errcount != self.error_count then
                                        self.check_errors
-                                       break
                                end
                                for na in vannot.annotations do
                                        var p = na.parent
@@ -138,7 +136,6 @@ redef class ToolContext
                                end
                                if errcount != self.error_count then
                                        self.check_errors
-                                       break
                                end
                        end
                        self.check_errors
index e27a98e..d81d1c7 100644 (file)
@@ -218,13 +218,16 @@ class RapidTypeAnalysis
                while not todo.is_empty do
                        var mmethoddef = todo.shift
                        var mmeth = mmethoddef.mproperty
+                       var msignature = mmethoddef.msignature
+                       if msignature == null then continue # Skip broken method
+
                        #print "# visit {mmethoddef}"
                        var v = new RapidTypeVisitor(self, mmethoddef.mclassdef.bound_mtype, mmethoddef)
 
-                       var vararg_rank = mmethoddef.msignature.vararg_rank
+                       var vararg_rank = msignature.vararg_rank
                        if vararg_rank > -1 then
                                var node = self.modelbuilder.mpropdef2node(mmethoddef)
-                               var elttype = mmethoddef.msignature.mparameters[vararg_rank].mtype
+                               var elttype = msignature.mparameters[vararg_rank].mtype
                                #elttype = elttype.anchor_to(self.mainmodule, v.receiver)
                                var vararg = self.mainmodule.array_type(elttype)
                                v.add_type(vararg)
@@ -234,7 +237,7 @@ class RapidTypeAnalysis
                        end
 
                        # TODO? new_msignature
-                       var sig = mmethoddef.msignature.as(not null)
+                       var sig = msignature
                        var osig = mmeth.intro.msignature.as(not null)
                        for i in [0..sig.arity[ do
                                var origtype = osig.mparameters[i].mtype
@@ -255,7 +258,7 @@ class RapidTypeAnalysis
                                continue
                        else if mmethoddef.constant_value != null then
                                # Make the return type live
-                               v.add_type(mmethoddef.msignature.return_mtype.as(MClassType))
+                               v.add_type(msignature.return_mtype.as(MClassType))
                                continue
                        else if npropdef == null then
                                abort
@@ -275,7 +278,7 @@ class RapidTypeAnalysis
 
                        if mmethoddef.is_intern or mmethoddef.is_extern then
                                # UGLY: We force the "instantation" of the concrete return type if any
-                               var ret = mmethoddef.msignature.return_mtype
+                               var ret = msignature.return_mtype
                                if ret != null and ret isa MClassType and ret.mclass.kind != abstract_kind and ret.mclass.kind != interface_kind then
                                        v.add_type(ret)
                                end
@@ -297,10 +300,10 @@ class RapidTypeAnalysis
                                if not ot.can_resolve_for(t, t, mainmodule) then continue
                                var rt = ot.anchor_to(mainmodule, t)
                                if live_types.has(rt) then continue
+                               if not check_depth(rt) then continue
                                #print "{ot}/{t} -> {rt}"
                                live_types.add(rt)
                                todo_types.add(rt)
-                               check_depth(rt)
                        end
                end
                #print "MType {live_types.length}: {live_types.join(", ")}"
@@ -318,12 +321,14 @@ class RapidTypeAnalysis
                #print "cast MType {live_cast_types.length}: {live_cast_types.join(", ")}"
        end
 
-       private fun check_depth(mtype: MClassType)
+       private fun check_depth(mtype: MClassType): Bool
        do
                var d = mtype.length
                if d > 255 then
                        self.modelbuilder.toolcontext.fatal_error(null, "Fatal Error: limitation in the rapidtype analysis engine: a type depth of {d} is too important, the problematic type is `{mtype}`.")
+                       return false
                end
+               return true
        end
 
        fun add_new(recv: MClassType, mtype: MClassType)
@@ -450,10 +455,14 @@ class RapidTypeVisitor
 
        redef fun visit(n)
        do
-               n.accept_rapid_type_visitor(self)
                if n isa AExpr then
-                       var implicit_cast_to = n.implicit_cast_to
-                       if implicit_cast_to != null then self.add_cast_type(implicit_cast_to)
+                       if n.mtype != null or n.is_typed then
+                               n.accept_rapid_type_visitor(self)
+                               var implicit_cast_to = n.implicit_cast_to
+                               if implicit_cast_to != null then self.add_cast_type(implicit_cast_to)
+                       end
+               else
+                       n.accept_rapid_type_visitor(self)
                end
 
                # RTA does not enter in AAnnotations
index 44ed320..4aad2d2 100644 (file)
@@ -960,7 +960,7 @@ redef class AVarReassignExpr
 
                v.set_variable(self, variable, rettype)
 
-               self.is_typed = true
+               self.is_typed = rettype != null
        end
 end
 
@@ -1006,9 +1006,11 @@ redef class AReturnExpr
                        else
                                v.visit_expr(nexpr)
                                v.error(nexpr, "Error: `return` with value in a procedure.")
+                               return
                        end
                else if ret_type != null then
                        v.error(self, "Error: `return` without value in a function.")
+                       return
                end
                self.is_typed = true
        end
@@ -2061,7 +2063,7 @@ redef class AAttrAssignExpr
                var mtype = self.attr_type
 
                v.visit_expr_subtype(self.n_value, mtype)
-               self.is_typed = true
+               self.is_typed = mtype != null
        end
 end
 
@@ -2072,9 +2074,9 @@ redef class AAttrReassignExpr
                var mtype = self.attr_type
                if mtype == null then return # Skip error
 
-               self.resolve_reassignment(v, mtype, mtype)
+               var rettype = self.resolve_reassignment(v, mtype, mtype)
 
-               self.is_typed = true
+               self.is_typed = rettype != null
        end
 end
 
index ebe2c73..838b9bc 100644 (file)
@@ -104,7 +104,12 @@ redef class AExpr
                        var nadd = v.builder.make_call(recv, na.push_callsite.as(not null), [self])
                        place.replace_with(nadd)
                end
-               super
+
+               visit_all(v)
+
+               if mtype == null and not is_typed then return # Skip broken
+
+               accept_transform_visitor(v)
        end
 
        redef fun replace_with(other)
index 33f4c8d..42e331a 100644 (file)
@@ -27,4 +27,5 @@ while t2 != null do
                t2 = t2.next #alt2# t2 = null
        end
        #alt3#t2 = t2.next
+       #alt3#exit(0)
 end
index cfbb80f..e342e07 100644 (file)
@@ -48,6 +48,6 @@ loop
        if i != null then
                bar(i)
        else
-               break #alt4#
+               break #alt4# exit(0)
        end
 end
diff --git a/tests/base_do_block.nit b/tests/base_do_block.nit
new file mode 100644 (file)
index 0000000..b9fdad4
--- /dev/null
@@ -0,0 +1,41 @@
+# 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.
+
+class Foo
+       fun start do end
+       fun finish do end
+end
+fun foo: Foo do return new Foo
+
+do do
+       1.output
+end
+while false do do
+       2.output
+end
+if true then do
+       3.output
+end else do
+       4.output
+end
+for i in [0..1] do do
+       5.output
+end
+with foo do do
+       6.output
+end
+loop do
+       7.output
+       return
+end
diff --git a/tests/sav/base_do_block.res b/tests/sav/base_do_block.res
new file mode 100644 (file)
index 0000000..f99d451
--- /dev/null
@@ -0,0 +1,11 @@
+base_do_block.nit:21,4--23,3: Warning: superfluous `do` block.
+base_do_block.nit:24,16--26,3: Warning: superfluous `do` block.
+base_do_block.nit:32,20--34,3: Warning: superfluous `do` block.
+base_do_block.nit:35,13--37,3: Warning: superfluous `do` block.
+base_do_block.nit:38,6--41,3: Warning: superfluous `do` block.
+1
+3
+5
+5
+6
+7
index 4fcab0a..debc62f 100644 (file)
@@ -1 +1 @@
-alt/base_import_alt3.nit:1,8--21: Error: cannot find module `fail` from `project1`. Tried: ., ../lib/standard, ../lib/standard/collection, alt, ../lib.
+alt/base_import_alt3.nit:1,8--21: Error: cannot find module `fail` from `project1`. Tried: ., ../lib/standard, ../lib/standard/collection, alt, ../lib, ../contrib.
index 20bc8ca..29ce68b 100644 (file)
@@ -1 +1 @@
-error_mod_unk.nit:17,8--11: Error: cannot find module `dfgd` from `error_mod_unk`. Tried: ., ../lib/standard, ../lib/standard/collection, alt, ../lib.
+error_mod_unk.nit:17,8--11: Error: cannot find module `dfgd` from `error_mod_unk`. Tried: ., ../lib/standard, ../lib/standard/collection, alt, ../lib, ../contrib.
diff --git a/tests/sav/test_keep_going.res b/tests/sav/test_keep_going.res
new file mode 100644 (file)
index 0000000..346b309
--- /dev/null
@@ -0,0 +1 @@
+test_keep_going.nit:15,11--14: Error: class `Fail` not found in module `test_keep_going`.
index 112bdb0..64d374b 100644 (file)
@@ -1,3 +1,2 @@
-../examples/nitcorn/src/xymus_net.nit:24,8--14: Error: cannot find module `tnitter` from `nitcorn`. Tried: alt, ../lib, ../examples/nitcorn.
-../examples/nitcorn/src/xymus_net.nit:25,8--26: Error: cannot find module `benitlux_controller` from `nitcorn`. Tried: alt, ../lib, ../examples/nitcorn.
-../examples/nitcorn/src/xymus_net.nit:26,8--29: Error: cannot find module `opportunity_controller` from `nitcorn`. Tried: alt, ../lib, ../examples/nitcorn.
+../examples/nitcorn/src/xymus_net.nit:25,8--26: Error: cannot find module `benitlux_controller` from `nitcorn`. Tried: alt, ../lib, ../contrib, ../examples/nitcorn.
+../examples/nitcorn/src/xymus_net.nit:26,8--29: Error: cannot find module `opportunity_controller` from `nitcorn`. Tried: alt, ../lib, ../contrib, ../examples/nitcorn.
index ffac1cd..2295927 100644 (file)
@@ -1,7 +1,5 @@
 # This file is part of NIT ( http://www.nitlanguage.org ).
 #
-# Copyright 2011-2013 Alexis Laferrière <alexis.laf@xymus.net>
-#
 # 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
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-fun opposite( v : Bool ) : Bool `{
+fun opposite(v: Bool): Bool `{
        return v == 0;
 `}
-fun plus_10( v : Char ) : Char `{
+
+fun plus_10(v: Char): Char `{
        return v + 10;
 `}
-fun plus_1000( v : Int ) : Int `{
+
+fun plus_1000(v: Int): Int `{
        return v + 1000;
 `}
-fun multiply_by_100( v : Float ) : Float `{
+
+fun multiply_by_100(v: Float): Float `{
        return v * 100;
 `}
-fun print_ns( s : NativeString ) `{
-       printf( "%s\n", s );
+
+fun plus_0x10(v: Byte): Byte `{
+       return v + 0x10;
+`}
+
+fun print_ns(s: NativeString) `{
+       printf("%s\n", s);
 `}
 
-print opposite( true )
-print opposite( false )
+print opposite(true)
+print opposite(false)
+
+print plus_10('a')
 
-print plus_10( 'a' )
+print plus_1000(1234)
 
-print plus_1000( 1234 )
+print multiply_by_100(123.45)
 
-print multiply_by_100( 123.45 )
+print plus_0x10(0x2u8)
 
-print_ns( "hello world".to_cstring )
+print_ns("hello world".to_cstring)
diff --git a/tests/test_keep_going.nit b/tests/test_keep_going.nit
new file mode 100755 (executable)
index 0000000..b3bedaa
--- /dev/null
@@ -0,0 +1,47 @@
+# 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.
+
+fun plop: Fail
+do
+       print 1
+end
+
+1.output
+if false then
+       plop
+end
+2.output
+if false then
+       fail
+end
+3.output
+if false then
+       var x = new Fail
+       x.output
+end
+4.output
+if false then
+       if 1 then abort
+end
+5.output
+if false then
+       abort
+       999.output
+end
+6.output
+if false then
+       var a = new Sys.fail
+       a.output
+end
+7.output