Merge: More keep going
authorJean Privat <jean@pryen.org>
Mon, 8 Jun 2015 10:05:14 +0000 (06:05 -0400)
committerJean Privat <jean@pryen.org>
Mon, 8 Jun 2015 10:05:14 +0000 (06:05 -0400)
This improve the robustness of tools when given --keep-going.
Tools like nitpick, that have --keep-going by default, are more robust and collect more errors.

Moreover, the compiler can now compile simple programs with instructions that fail during the typing phase (most errors like unknown method or bad type).

These instructions are compiled with a run time error instead so the program is still expected to behave in an reliable way.

~~~nit
print 1
fail now
print 2
~~~

~~~sh
$ nitc kg.nit --keep-going
kg.nit:2,1--4: Error: method or variable `fail` unknown in `Sys`.
$ ./kg
1
Runtime error: FATAL: bad statement executed. (kg.nit:1)
~~~

One usage would be to force `c_src` to compile things even if it lags behind.

Pull-Request: #1440
Reviewed-by: Lucas Bajolet <r4pass@hotmail.com>
Reviewed-by: Alexis Laferrière <alexis.laf@xymus.net>
Reviewed-by: Romain Chanoir <chanoir.romain@courrier.uqam.ca>

1  2 
src/compiler/abstract_compiler.nit
src/compiler/separate_compiler.nit
src/rapid_type_analysis.nit
src/semantize/typing.nit

@@@ -63,8 -63,8 +63,8 @@@ redef class ToolContex
        var opt_invocation_metrics = new OptionBool("Enable static and dynamic count of all method invocations", "--invocation-metrics")
        # --isset-checks-metrics
        var opt_isset_checks_metrics = new OptionBool("Enable static and dynamic count of isset checks before attributes access", "--isset-checks-metrics")
 -      # --stacktrace
 -      var opt_stacktrace = new OptionString("Control the generation of stack traces", "--stacktrace")
 +      # --no-stacktrace
 +      var opt_no_stacktrace = new OptionBool("Disable the generation of stack traces", "--no-stacktrace")
        # --no-gcc-directives
        var opt_no_gcc_directive = new OptionArray("Disable a advanced gcc directives for optimization", "--no-gcc-directive")
        # --release
@@@ -76,7 -76,7 +76,7 @@@
                self.option_context.add_option(self.opt_output, self.opt_dir, self.opt_no_cc, self.opt_no_main, self.opt_make_flags, self.opt_compile_dir, self.opt_hardening)
                self.option_context.add_option(self.opt_no_check_covariance, self.opt_no_check_attr_isset, self.opt_no_check_assert, self.opt_no_check_autocast, self.opt_no_check_null, self.opt_no_check_all)
                self.option_context.add_option(self.opt_typing_test_metrics, self.opt_invocation_metrics, self.opt_isset_checks_metrics)
 -              self.option_context.add_option(self.opt_stacktrace)
 +              self.option_context.add_option(self.opt_no_stacktrace)
                self.option_context.add_option(self.opt_no_gcc_directive)
                self.option_context.add_option(self.opt_release)
                self.option_context.add_option(self.opt_max_c_lines, self.opt_group_c_files)
        do
                super
  
 -              var st = opt_stacktrace.value
 -              if st == "none" or st == "libunwind" or st == "nitstack" then
 -                      # Fine, do nothing
 -              else if st == "auto" or st == null then
 -                      # Default is nitstack
 -                      opt_stacktrace.value = "nitstack"
 -              else
 -                      print "Option Error: unknown value `{st}` for --stacktrace. Use `none`, `libunwind`, `nitstack` or `auto`."
 -                      exit(1)
 -              end
 -
                if opt_output.value != null and opt_dir.value != null then
                        print "Option Error: cannot use both --dir and --output"
                        exit(1)
  end
  
  redef class ModelBuilder
 -      # The compilation directory
 -      var compile_dir: String
 -
        # Simple indirection to `Toolchain::write_and_make`
        protected fun write_and_make(compiler: AbstractCompiler)
        do
                var platform = compiler.target_platform
                var toolchain = platform.toolchain(toolcontext, compiler)
 -              compile_dir = toolchain.compile_dir
 +              compiler.toolchain = toolchain
                toolchain.write_and_make
        end
  end
@@@ -131,21 -145,14 +131,21 @@@ class Toolchai
        # Compiler of the target program
        var compiler: AbstractCompiler
  
 -      # Directory where to generate all C files
 -      fun compile_dir: String
 +      # Directory where to generate all files
 +      #
 +      # The option `--compile_dir` change this directory.
 +      fun root_compile_dir: String
        do
                var compile_dir = toolcontext.opt_compile_dir.value
 -              if compile_dir == null then compile_dir = ".nit_compile"
 +              if compile_dir == null then compile_dir = "nit_compile"
                return compile_dir
        end
  
 +      # Directory where to generate all C files
 +      #
 +      # By default it is `root_compile_dir` but some platform may require that it is a subdirectory.
 +      fun compile_dir: String do return root_compile_dir
 +
        # Write all C files and compile them
        fun write_and_make is abstract
  end
@@@ -158,16 -165,12 +158,16 @@@ class MakefileToolchai
        do
                var compile_dir = compile_dir
  
 +              # Remove the compilation directory unless explicitly set
 +              var auto_remove = toolcontext.opt_compile_dir.value == null
 +
                # Generate the .h and .c files
                # A single C file regroups many compiled rumtime functions
                # Note that we do not try to be clever an a small change in a Nit source file may change the content of all the generated .c files
                var time0 = get_time
                self.toolcontext.info("*** WRITING C ***", 1)
  
 +              root_compile_dir.mkdir
                compile_dir.mkdir
  
                var cfiles = new Array[String]
  
                compile_c_code(compile_dir)
  
 +              if auto_remove then
 +                      sys.system("rm -r -- '{root_compile_dir.escape_to_sh}/'")
 +              end
 +
                time1 = get_time
                self.toolcontext.info("*** END COMPILING C: {time1-time0} ***", 2)
        end
        fun write_files(compile_dir: String, cfiles: Array[String])
        do
                var platform = compiler.target_platform
 -              if self.toolcontext.opt_stacktrace.value == "nitstack" and platform.supports_libunwind then compiler.build_c_to_nit_bindings
 +              if platform.supports_libunwind then compiler.build_c_to_nit_bindings
                var cc_opt_with_libgc = "-DWITH_LIBGC"
                if not platform.supports_libgc then cc_opt_with_libgc = ""
  
                var outpath = real_outpath.escape_to_mk
                if outpath != real_outpath then
                        # If the name is crazy and need escaping, we will do an indirection
 -                      # 1. generate the binary in the .nit_compile dir under an escaped name
 +                      # 1. generate the binary in the nit_compile dir under an escaped name
                        # 2. copy the binary at the right place in the `all` goal.
                        outpath = mainmodule.c_name
                end
  
                makefile.write("CC = ccache cc\nCXX = ccache c++\nCFLAGS = -g -O2 -Wno-unused-value -Wno-switch -Wno-attributes\nCINCL =\nLDFLAGS ?= \nLDLIBS  ?= -lm {linker_options.join(" ")}\n\n")
  
 -              var ost = toolcontext.opt_stacktrace.value
 -              if (ost == "libunwind" or ost == "nitstack") and platform.supports_libunwind then makefile.write("NEED_LIBUNWIND := YesPlease\n")
 +              makefile.write "\n# SPECIAL CONFIGURATION FLAGS\n"
 +              if platform.supports_libunwind then
 +                      if toolcontext.opt_no_stacktrace.value then
 +                              makefile.write "NO_STACKTRACE=True"
 +                      else
 +                              makefile.write "NO_STACKTRACE= # Set to `True` to enable"
 +                      end
 +              end
  
                # Dynamic adaptations
                # While `platform` enable complex toolchains, they are statically applied
                # For a dynamic adaptsation of the compilation, the generated Makefile should check and adapt things itself
 +              makefile.write "\n\n"
  
                # Check and adapt the targeted system
                makefile.write("uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')\n")
 -              makefile.write("ifeq ($(uname_S),Darwin)\n")
 -              # remove -lunwind since it is already included on macosx
 -              makefile.write("\tNEED_LIBUNWIND :=\n")
 -              makefile.write("endif\n\n")
  
                # Check and adapt for the compiler used
                # clang need an additionnal `-Qunused-arguments`
                makefile.write("clang_check := $(shell sh -c '$(CC) -v 2>&1 | grep -q clang; echo $$?')\nifeq ($(clang_check), 0)\n\tCFLAGS += -Qunused-arguments\nendif\n")
  
 -              makefile.write("ifdef NEED_LIBUNWIND\n\tLDLIBS += -lunwind\nendif\n")
 +              if platform.supports_libunwind then
 +                      makefile.write """
 +ifneq ($(NO_STACKTRACE), True)
 +  # Check and include lib-unwind in a portable way
 +  ifneq ($(uname_S),Darwin)
 +    # already included on macosx, but need to get the correct flags in other supported platforms.
 +    ifeq ($(shell pkg-config --exists 'libunwind'; echo $$?), 0)
 +      LDLIBS += `pkg-config --libs libunwind`
 +      CFLAGS += `pkg-config --cflags libunwind`
 +    else
 +      $(warning "[_] stack-traces disabled. Please install libunwind-dev.")
 +      CFLAGS += -D NO_STACKTRACE
 +    endif
 +  endif
 +else
 +  # Stacktraces disabled
 +  CFLAGS += -D NO_STACKTRACE
 +endif
 +
 +"""
 +              else
 +                      makefile.write("CFLAGS += -D NO_STACKTRACE\n\n")
 +              end
  
                makefile.write("all: {outpath}\n")
                if outpath != real_outpath then
@@@ -522,11 -496,6 +522,11 @@@ abstract class AbstractCompile
        # The modelbuilder used to know the model and the AST
        var modelbuilder: ModelBuilder is protected writable
  
 +      # The associated toolchain
 +      #
 +      # Set by `modelbuilder.write_and_make` and permit sub-routines to access the current toolchain if required.
 +      var toolchain: Toolchain is noinit
 +
        # Is hardening asked? (see --hardening)
        fun hardening: Bool do return self.modelbuilder.toolcontext.opt_hardening.value
  
        # Binds the generated C function names to Nit function names
        fun build_c_to_nit_bindings
        do
 -              var compile_dir = modelbuilder.compile_dir
 +              var compile_dir = toolchain.compile_dir
  
                var stream = new FileWriter.open("{compile_dir}/c_functions_hash.c")
                stream.write("#include <string.h>\n")
                self.header.add_decl("#include <string.h>")
                self.header.add_decl("#include <sys/types.h>\n")
                self.header.add_decl("#include <unistd.h>\n")
 +              self.header.add_decl("#include <stdint.h>\n")
                self.header.add_decl("#include \"gc_chooser.h\"")
                self.header.add_decl("#ifdef ANDROID")
                self.header.add_decl("  #include <android/log.h>")
@@@ -745,16 -713,19 +745,16 @@@ extern void nitni_global_ref_decr( stru
        do
                var v = self.new_visitor
                v.add_decl("#include <signal.h>")
 -              var ost = modelbuilder.toolcontext.opt_stacktrace.value
                var platform = target_platform
  
 -              if not platform.supports_libunwind then ost = "none"
 -
                var no_main = platform.no_main or modelbuilder.toolcontext.opt_no_main.value
  
 -              if ost == "nitstack" or ost == "libunwind" then
 +              if platform.supports_libunwind then
 +                      v.add_decl("#ifndef NO_STACKTRACE")
                        v.add_decl("#define UNW_LOCAL_ONLY")
                        v.add_decl("#include <libunwind.h>")
 -                      if ost == "nitstack" then
 -                              v.add_decl("#include \"c_functions_hash.h\"")
 -                      end
 +                      v.add_decl("#include \"c_functions_hash.h\"")
 +                      v.add_decl("#endif")
                end
                v.add_decl("int glob_argc;")
                v.add_decl("char **glob_argv;")
                end
  
                v.add_decl("static void show_backtrace(void) \{")
 -              if ost == "nitstack" or ost == "libunwind" then
 +              if platform.supports_libunwind then
 +                      v.add_decl("#ifndef NO_STACKTRACE")
                        v.add_decl("char* opt = getenv(\"NIT_NO_STACK\");")
                        v.add_decl("unw_cursor_t cursor;")
                        v.add_decl("if(opt==NULL)\{")
                        v.add_decl("PRINT_ERROR(\"-------------------------------------------------\\n\");")
                        v.add_decl("while (unw_step(&cursor) > 0) \{")
                        v.add_decl("    unw_get_proc_name(&cursor, procname, 100, &ip);")
 -                      if ost == "nitstack" then
                        v.add_decl("    const char* recv = get_nit_name(procname, strlen(procname));")
                        v.add_decl("    if (recv != NULL)\{")
                        v.add_decl("            PRINT_ERROR(\"` %s\\n\", recv);")
                        v.add_decl("    \}else\{")
                        v.add_decl("            PRINT_ERROR(\"` %s\\n\", procname);")
                        v.add_decl("    \}")
 -                      else
 -                      v.add_decl("    PRINT_ERROR(\"` %s \\n\",procname);")
 -                      end
                        v.add_decl("\}")
                        v.add_decl("PRINT_ERROR(\"-------------------------------------------------\\n\");")
                        v.add_decl("free(procname);")
                        v.add_decl("\}")
 +                      v.add_decl("#endif /* NO_STACKTRACE */")
                end
                v.add_decl("\}")
  
@@@ -1482,14 -1455,6 +1482,14 @@@ abstract class AbstractCompilerVisito
                return res
        end
  
 +      # Generate a byte value
 +      fun byte_instance(value: Byte): RuntimeVariable
 +      do
 +              var t = mmodule.byte_type
 +              var res = new RuntimeVariable("((unsigned char){value.to_s})", t, t)
 +              return res
 +      end
 +
        # Generate a char value
        fun char_instance(value: Char): RuntimeVariable
        do
                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
  
        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
@@@ -1870,13 -1838,11 +1873,13 @@@ redef class MClassTyp
                else if mclass.name == "Bool" then
                        return "short int"
                else if mclass.name == "Char" then
 -                      return "char"
 +                      return "uint32_t"
                else if mclass.name == "Float" then
                        return "double"
 +              else if mclass.name == "Byte" then
 +                      return "unsigned char"
                else if mclass.name == "NativeString" then
 -                      return "char*"
 +                      return "unsigned char*"
                else if mclass.name == "NativeArray" then
                        return "val*"
                else
                        return "c"
                else if mclass.name == "Float" then
                        return "d"
 +              else if mclass.name == "Byte" then
 +                      return "b"
                else if mclass.name == "NativeString" then
                        return "str"
                else if mclass.name == "NativeArray" then
@@@ -2137,16 -2101,13 +2140,16 @@@ redef class AMethPropde
                        else if pname == "to_f" then
                                v.ret(v.new_expr("(double){arguments[0]}", ret.as(not null)))
                                return true
 +                      else if pname == "to_b" then
 +                              v.ret(v.new_expr("(unsigned char){arguments[0]}", ret.as(not null)))
 +                              return true
                        else if pname == "ascii" then
 -                              v.ret(v.new_expr("{arguments[0]}", ret.as(not null)))
 +                              v.ret(v.new_expr("(uint32_t){arguments[0]}", ret.as(not null)))
                                return true
                        end
                else if cname == "Char" then
                        if pname == "output" then
 -                              v.add("printf(\"%c\", {arguments.first});")
 +                              v.add("printf(\"%c\", ((unsigned char){arguments.first}));")
                                return true
                        else if pname == "object_id" then
                                v.ret(v.new_expr("(long){arguments.first}", ret.as(not null)))
                                v.ret(v.new_expr("{arguments[0]}-'0'", ret.as(not null)))
                                return true
                        else if pname == "ascii" then
 -                              v.ret(v.new_expr("(unsigned char){arguments[0]}", ret.as(not null)))
 +                              v.ret(v.new_expr("(long){arguments[0]}", ret.as(not null)))
 +                              return true
 +                      end
 +              else if cname == "Byte" then
 +                      if pname == "output" then
 +                              v.add("printf(\"%x\\n\", {arguments.first});")
 +                              return true
 +                      else if pname == "object_id" then
 +                              v.ret(v.new_expr("(long){arguments.first}", ret.as(not null)))
 +                              return true
 +                      else if pname == "+" then
 +                              v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
 +                              return true
 +                      else if pname == "-" then
 +                              v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
 +                              return true
 +                      else if pname == "unary -" then
 +                              v.ret(v.new_expr("-{arguments[0]}", ret.as(not null)))
 +                              return true
 +                      else if pname == "unary +" then
 +                              v.ret(arguments[0])
 +                              return true
 +                      else if pname == "*" then
 +                              v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null)))
 +                              return true
 +                      else if pname == "/" then
 +                              v.ret(v.new_expr("{arguments[0]} / {arguments[1]}", ret.as(not null)))
 +                              return true
 +                      else if pname == "%" then
 +                              v.ret(v.new_expr("{arguments[0]} % {arguments[1]}", ret.as(not null)))
 +                              return true
 +                      else if pname == "lshift" then
 +                              v.ret(v.new_expr("{arguments[0]} << {arguments[1]}", ret.as(not null)))
 +                              return true
 +                      else if pname == "rshift" then
 +                              v.ret(v.new_expr("{arguments[0]} >> {arguments[1]}", ret.as(not null)))
 +                              return true
 +                      else if pname == "==" then
 +                              v.ret(v.equal_test(arguments[0], arguments[1]))
 +                              return true
 +                      else if pname == "!=" then
 +                              var res = v.equal_test(arguments[0], arguments[1])
 +                              v.ret(v.new_expr("!{res}", ret.as(not null)))
 +                              return true
 +                      else if pname == "<" then
 +                              v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
 +                              return true
 +                      else if pname == ">" then
 +                              v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
 +                              return true
 +                      else if pname == "<=" then
 +                              v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
 +                              return true
 +                      else if pname == ">=" then
 +                              v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
 +                              return true
 +                      else if pname == "to_i" then
 +                              v.ret(v.new_expr("(long){arguments[0]}", ret.as(not null)))
 +                              return true
 +                      else if pname == "to_f" then
 +                              v.ret(v.new_expr("(double){arguments[0]}", ret.as(not null)))
 +                              return true
 +                      else if pname == "ascii" then
 +                              v.ret(v.new_expr("{arguments[0]}", ret.as(not null)))
                                return true
                        end
                else if cname == "Bool" then
                        else if pname == "to_i" then
                                v.ret(v.new_expr("(long){arguments[0]}", ret.as(not null)))
                                return true
 +                      else if pname == "to_b" then
 +                              v.ret(v.new_expr("(unsigned char){arguments[0]}", ret.as(not null)))
 +                              return true
                        end
                else if cname == "NativeString" then
                        if pname == "[]" then
 -                              v.ret(v.new_expr("{arguments[0]}[{arguments[1]}]", ret.as(not null)))
 +                              v.ret(v.new_expr("(uint32_t){arguments[0]}[{arguments[1]}]", ret.as(not null)))
                                return true
                        else if pname == "[]=" then
 -                              v.add("{arguments[0]}[{arguments[1]}]={arguments[2]};")
 +                              v.add("{arguments[0]}[{arguments[1]}]=(unsigned char){arguments[2]};")
                                return true
                        else if pname == "copy_to" then
                                v.add("memmove({arguments[1]}+{arguments[4]},{arguments[0]}+{arguments[3]},{arguments[2]});")
                                v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
                                return true
                        else if pname == "new" then
 -                              v.ret(v.new_expr("(char*)nit_alloc({arguments[1]})", ret.as(not null)))
 +                              v.ret(v.new_expr("(unsigned char*)nit_alloc({arguments[1]})", ret.as(not null)))
                                return true
                        end
                else if cname == "NativeArray" then
                        v.ret(v.new_expr("glob_sys", ret.as(not null)))
                        return true
                else if pname == "calloc_string" then
 -                      v.ret(v.new_expr("(char*)nit_alloc({arguments[1]})", ret.as(not null)))
 +                      v.ret(v.new_expr("(unsigned char*)nit_alloc({arguments[1]})", ret.as(not null)))
                        return true
                else if pname == "calloc_array" then
                        v.calloc_array(ret.as(not null), arguments)
@@@ -2893,10 -2788,6 +2896,10 @@@ redef class AIntExp
        redef fun expr(v) do return v.int_instance(self.value.as(not null))
  end
  
 +redef class AByteExpr
 +      redef fun expr(v) do return v.byte_instance(self.value.as(not null))
 +end
 +
  redef class AFloatExpr
        redef fun expr(v) do return v.float_instance("{self.n_float.text}") # FIXME use value, not n_float
  end
@@@ -252,7 -252,7 +252,7 @@@ class SeparateCompile
        do
                # Collect all bas box class
                # FIXME: this is not completely fine with a separate compilation scheme
 -              for classname in ["Int", "Bool", "Char", "Float", "NativeString", "Pointer"] do
 +              for classname in ["Int", "Bool", "Byte", "Char", "Float", "NativeString", "Pointer"] do
                        var classes = self.mainmodule.model.get_mclasses_by_name(classname)
                        if classes == null then continue
                        assert classes.length == 1 else print classes.join(", ")
                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}"
                        end
                        v.add_decl("\},")
                else
 -                      v.add_decl("0, \{\}, /*DEAD TYPE*/")
 +                      # Use -1 to indicate dead type, the info is used by --hardening
 +                      v.add_decl("-1, \{\}, /*DEAD TYPE*/")
                end
                v.add_decl("\};")
        end
                v.add("if({t} == NULL) \{")
                v.add_abort("type null")
                v.add("\}")
 -              v.add("if({t}->table_size == 0) \{")
 +              v.add("if({t}->table_size < 0) \{")
                v.add("PRINT_ERROR(\"Insantiation of a dead type: %s\\n\", {t}->name);")
                v.add_abort("type dead")
                v.add("\}")
@@@ -1193,7 -1193,7 +1194,7 @@@ class SeparateCompilerVisito
                                if mtype.name == "Int" then
                                        return self.new_expr("(long)({value})>>2", mtype)
                                else if mtype.name == "Char" then
 -                                      return self.new_expr("(char)((long)({value})>>2)", mtype)
 +                                      return self.new_expr("(uint32_t)((long)({value})>>2)", mtype)
                                else if mtype.name == "Bool" then
                                        return self.new_expr("(short int)((long)({value})>>2)", mtype)
                                else
@@@ -213,18 -213,20 +213,21 @@@ class RapidTypeAnalysi
                force_alive("Float")
                force_alive("Char")
                force_alive("Pointer")
 +              force_alive("Byte")
  
                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)
                        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
                                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
  
                        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
                                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(", ")}"
                #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 -454,14 +455,14 @@@ class RapidTypeVisito
  
        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
@@@ -517,13 -525,6 +526,13 @@@ redef class AIntExp
        end
  end
  
 +redef class AByteExpr
 +      redef fun accept_rapid_type_visitor(v)
 +      do
 +              v.add_type(self.mtype.as(MClassType))
 +      end
 +end
 +
  redef class AFloatExpr
        redef fun accept_rapid_type_visitor(v)
        do
@@@ -567,7 -568,7 +576,7 @@@ redef class ASuperstringExp
        redef fun accept_rapid_type_visitor(v)
        do
                var mmodule = v.analysis.mainmodule
 -              var object_type = mmodule.object_type
 +              var object_type = mmodule.string_type
                var arraytype = mmodule.array_type(object_type)
                v.add_type(arraytype)
                var nattype = mmodule.native_array_type(object_type)
diff --combined src/semantize/typing.nit
@@@ -301,9 -301,15 +301,9 @@@ private class TypeVisito
  
                #debug("recv: {recvtype} (aka {unsafe_type})")
                if recvtype isa MNullType then
 -                      # `null` only accepts some methods of object.
 -                      if name == "==" or name == "!=" or name == "is_same_instance" then
 -                              var objclass = get_mclass(node, "Object")
 -                              if objclass == null then return null # Forward error
 -                              unsafe_type = objclass.mclass_type
 -                      else
 -                              self.error(node, "Error: method `{name}` called on `null`.")
 -                              return null
 -                      end
 +                      var objclass = get_mclass(node, "Object")
 +                      if objclass == null then return null # Forward error
 +                      unsafe_type = objclass.mclass_type
                end
  
                var mproperty = self.try_get_mproperty_by_name2(node, unsafe_type, name)
  
                assert mproperty isa MMethod
  
 +              # `null` only accepts some methods of object.
 +              if recvtype isa MNullType and not mproperty.is_null_safe then
 +                      self.error(node, "Error: method `{name}` called on `null`.")
 +                      return null
 +              else if unsafe_type isa MNullableType and not mproperty.is_null_safe then
 +                      modelbuilder.advice(node, "call-on-nullable", "Warning: method call on a nullable receiver `{recvtype}`.")
 +              end
 +
                if is_toplevel_context and recv_is_self and not mproperty.is_toplevel then
                        error(node, "Error: `{name}` is not a top-level method, thus need a receiver.")
                end
@@@ -960,7 -958,7 +960,7 @@@ redef class AVarReassignExp
  
                v.set_variable(self, variable, rettype)
  
-               self.is_typed = true
+               self.is_typed = rettype != null
        end
  end
  
@@@ -1006,9 -1004,11 +1006,11 @@@ redef class AReturnExp
                        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
@@@ -1344,15 -1344,6 +1346,15 @@@ redef class AIntExp
        end
  end
  
 +redef class AByteExpr
 +      redef fun accept_typing(v)
 +      do
 +              var mclass = v.get_mclass(self, "Byte")
 +              if mclass == null then return # Forward error
 +              self.mtype = mclass.mclass_type
 +      end
 +end
 +
  redef class AFloatExpr
        redef fun accept_typing(v)
        do
@@@ -2061,7 -2052,7 +2063,7 @@@ redef class AAttrAssignExp
                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 -2063,9 +2074,9 @@@ redef class AAttrReassignExp
                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