src: add some asserts on `super` related things
[nit.git] / src / abstract_compiler.nit
index 720be46..6656d5b 100644 (file)
@@ -51,8 +51,10 @@ redef class ToolContext
        var opt_no_check_assert: OptionBool = new OptionBool("Disable the evaluation of explicit 'assert' and 'as' (dangerous)", "--no-check-assert")
        # --no-check-autocast
        var opt_no_check_autocast: OptionBool = new OptionBool("Disable implicit casts on unsafe expression usage (dangerous)", "--no-check-autocast")
-       # --no-check-other
-       var opt_no_check_other: OptionBool = new OptionBool("Disable implicit tests: unset attribute, null receiver (dangerous)", "--no-check-other")
+       # --no-check-null
+       var opt_no_check_null: OptionBool = new OptionBool("Disable tests of null receiver (dangerous)", "--no-check-null")
+       # --no-check-all
+       var opt_no_check_all: OptionBool = new OptionBool("Disable all tests (dangerous)", "--no-check-all")
        # --typing-test-metrics
        var opt_typing_test_metrics: OptionBool = new OptionBool("Enable static and dynamic count of all type tests", "--typing-test-metrics")
        # --invocation-metrics
@@ -70,7 +72,7 @@ redef class ToolContext
        do
                super
                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.opt_no_shortcut_range)
-               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_other)
+               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_gcc_directive)
@@ -96,6 +98,14 @@ redef class ToolContext
                        print "Error: cannot use both --dir and --output"
                        exit(1)
                end
+
+               if opt_no_check_all.value then
+                       opt_no_check_covariance.value = true
+                       opt_no_check_attr_isset.value = true
+                       opt_no_check_assert.value = true
+                       opt_no_check_autocast.value = true
+                       opt_no_check_null.value = true
+               end
        end
 end
 
@@ -613,6 +623,25 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref );
 """
        end
 
+       fun compile_finalizer_function
+       do
+               var finalizable_type = mainmodule.finalizable_type
+               if finalizable_type == null then return
+
+               var finalize_meth = mainmodule.try_get_primitive_method("finalize", finalizable_type.mclass)
+
+               if finalize_meth == null then
+                       modelbuilder.toolcontext.error(null, "The `Finalizable` class doesn't declare the `finalize` method.")
+                       return
+               end
+
+               var v = self.new_visitor
+               v.add_decl "void gc_finalize (void *obj, void *client_data) \{"
+               var recv = v.new_expr("obj", finalizable_type)
+               v.send(finalize_meth, [recv])
+               v.add "\}"
+       end
+
        # Generate the main C function.
        # This function:
        #       * allocate the Sys object if it exists
@@ -1155,7 +1184,7 @@ abstract class AbstractCompilerVisitor
        # Add a check and an abort for a null reciever if needed
        fun check_recv_notnull(recv: RuntimeVariable)
        do
-               if self.compiler.modelbuilder.toolcontext.opt_no_check_other.value then return
+               if self.compiler.modelbuilder.toolcontext.opt_no_check_null.value then return
 
                var maybenull = recv.mcasttype isa MNullableType or recv.mcasttype isa MNullType
                if maybenull then
@@ -1259,6 +1288,17 @@ abstract class AbstractCompilerVisitor
        # Generate a alloc-instance + init-attributes
        fun init_instance(mtype: MClassType): RuntimeVariable is abstract
 
+       # Set a GC finalizer on `recv`, only if `recv` isa Finalizable
+       fun set_finalizer(recv: RuntimeVariable)
+       do
+               var mtype = recv.mtype
+               var finalizable_type = compiler.mainmodule.finalizable_type
+               if finalizable_type != null and not mtype.need_anchor and
+                  mtype.is_subtype(compiler.mainmodule, null, finalizable_type) then
+                       add "gc_register_finalizer({recv});"
+               end
+       end
+
        # Generate an integer value
        fun int_instance(value: Int): RuntimeVariable
        do
@@ -1789,6 +1829,7 @@ redef class AMethPropdef
                if auto_super_inits != null then
                        var args = [arguments.first]
                        for auto_super_init in auto_super_inits do
+                               assert auto_super_init.mproperty != mpropdef.mproperty
                                args.clear
                                for i in [0..auto_super_init.msignature.arity+1[ do
                                        args.add(arguments[i])
@@ -1812,6 +1853,8 @@ redef class AMethPropdef
                        else
                                compile_externmeth_to_c(v, mpropdef, arguments)
                        end
+               else
+                       abort
                end
        end
 
@@ -2008,7 +2051,7 @@ redef class AMethPropdef
                                v.add("{arguments[0]}[{arguments[1]}]={arguments[2]};")
                                return
                        else if pname == "copy_to" then
-                               v.add("memcpy({arguments[1]}+{arguments[4]},{arguments[0]}+{arguments[3]},{arguments[2]});")
+                               v.add("memmove({arguments[1]}+{arguments[4]},{arguments[0]}+{arguments[3]},{arguments[2]});")
                                return
                        else if pname == "atoi" then
                                v.ret(v.new_expr("atoi({arguments[0]});", ret.as(not null)))