compiler: accept `null` as a *maybenull* receiver
[nit.git] / src / compiler / separate_compiler.nit
index 43d06c2..e5f1bb9 100644 (file)
@@ -22,19 +22,19 @@ import rapid_type_analysis
 # Add separate compiler specific options
 redef class ToolContext
        # --separate
-       var opt_separate: OptionBool = new OptionBool("Use separate compilation", "--separate")
+       var opt_separate = new OptionBool("Use separate compilation", "--separate")
        # --no-inline-intern
-       var opt_no_inline_intern: OptionBool = new OptionBool("Do not inline call to intern methods", "--no-inline-intern")
+       var opt_no_inline_intern = new OptionBool("Do not inline call to intern methods", "--no-inline-intern")
        # --no-union-attribute
-       var opt_no_union_attribute: OptionBool = new OptionBool("Put primitive attibutes in a box instead of an union", "--no-union-attribute")
+       var opt_no_union_attribute = new OptionBool("Put primitive attibutes in a box instead of an union", "--no-union-attribute")
        # --no-shortcut-equate
-       var opt_no_shortcut_equate: OptionBool = new OptionBool("Always call == in a polymorphic way", "--no-shortcut-equal")
+       var opt_no_shortcut_equate = new OptionBool("Always call == in a polymorphic way", "--no-shortcut-equal")
        # --inline-coloring-numbers
-       var opt_inline_coloring_numbers: OptionBool = new OptionBool("Inline colors and ids (semi-global)", "--inline-coloring-numbers")
+       var opt_inline_coloring_numbers = new OptionBool("Inline colors and ids (semi-global)", "--inline-coloring-numbers")
        # --inline-some-methods
-       var opt_inline_some_methods: OptionBool = new OptionBool("Allow the separate compiler to inline some methods (semi-global)", "--inline-some-methods")
+       var opt_inline_some_methods = new OptionBool("Allow the separate compiler to inline some methods (semi-global)", "--inline-some-methods")
        # --direct-call-monomorph
-       var opt_direct_call_monomorph: OptionBool = new OptionBool("Allow the separate compiler to direct call monomorph sites (semi-global)", "--direct-call-monomorph")
+       var opt_direct_call_monomorph = new OptionBool("Allow the separate compiler to direct call monomorph sites (semi-global)", "--direct-call-monomorph")
        # --skip-dead-methods
        var opt_skip_dead_methods = new OptionBool("Do not compile dead methods (semi-global)", "--skip-dead-methods")
        # --semi-global
@@ -42,7 +42,7 @@ redef class ToolContext
        # --no-colo-dead-methods
        var opt_colo_dead_methods = new OptionBool("Force colorization of dead methods", "--colo-dead-methods")
        # --tables-metrics
-       var opt_tables_metrics: OptionBool = new OptionBool("Enable static size measuring of tables used for vft, typing and resolution", "--tables-metrics")
+       var opt_tables_metrics = new OptionBool("Enable static size measuring of tables used for vft, typing and resolution", "--tables-metrics")
 
        redef init
        do
@@ -92,33 +92,35 @@ redef class ModelBuilder
                var compiler = new SeparateCompiler(mainmodule, self, runtime_type_analysis)
                compiler.compile_header
 
+               var c_name = mainmodule.c_name
+
                # compile class structures
                self.toolcontext.info("Property coloring", 2)
-               compiler.new_file("{mainmodule.name}.classes")
+               compiler.new_file("{c_name}.classes")
                compiler.do_property_coloring
                for m in mainmodule.in_importation.greaters do
                        for mclass in m.intro_mclasses do
-                               if mclass.kind == abstract_kind or mclass.kind == interface_kind then continue
+                               #if mclass.kind == abstract_kind or mclass.kind == interface_kind then continue
                                compiler.compile_class_to_c(mclass)
                        end
                end
 
                # The main function of the C
-               compiler.new_file("{mainmodule.name}.main")
+               compiler.new_file("{c_name}.main")
                compiler.compile_nitni_global_ref_functions
                compiler.compile_main_function
                compiler.compile_finalizer_function
 
                # compile methods
                for m in mainmodule.in_importation.greaters do
-                       self.toolcontext.info("Generate C for module {m}", 2)
-                       compiler.new_file("{m.name}.sep")
+                       self.toolcontext.info("Generate C for module {m.full_name}", 2)
+                       compiler.new_file("{m.c_name}.sep")
                        compiler.compile_module_to_c(m)
                end
 
                # compile live & cast type structures
                self.toolcontext.info("Type coloring", 2)
-               compiler.new_file("{mainmodule.name}.types")
+               compiler.new_file("{c_name}.types")
                var mtypes = compiler.do_type_coloring
                for t in mtypes do
                        compiler.compile_type_to_c(t)
@@ -156,17 +158,15 @@ class SeparateCompiler
        private var undead_types: Set[MType] = new HashSet[MType]
        private var live_unresolved_types: Map[MClassDef, Set[MType]] = new HashMap[MClassDef, HashSet[MType]]
 
-       private var type_ids: Map[MType, Int]
-       private var type_colors: Map[MType, Int]
-       private var opentype_colors: Map[MType, Int]
-       protected var method_colors: Map[PropertyLayoutElement, Int]
-       protected var attr_colors: Map[MAttribute, Int]
+       private var type_ids: Map[MType, Int] is noinit
+       private var type_colors: Map[MType, Int] is noinit
+       private var opentype_colors: Map[MType, Int] is noinit
+       protected var method_colors: Map[PropertyLayoutElement, Int] is noinit
+       protected var attr_colors: Map[MAttribute, Int] is noinit
 
-       init(mainmodule: MModule, mmbuilder: ModelBuilder, runtime_type_analysis: nullable RapidTypeAnalysis) do
-               super(mainmodule, mmbuilder)
+       init do
                var file = new_file("nit.common")
                self.header = new CodeWriter(file)
-               self.runtime_type_analysis = runtime_type_analysis
                self.compile_box_kinds
        end
 
@@ -418,13 +418,12 @@ class SeparateCompiler
                var live_cast_types = runtime_type_analysis.live_cast_types
                var mtypes = new HashSet[MType]
                mtypes.add_all(live_types)
-               mtypes.add_all(live_cast_types)
                for c in self.box_kinds.keys do
                        mtypes.add(c.mclass_type)
                end
 
                # Compute colors
-               var poset = poset_from_mtypes(mtypes)
+               var poset = poset_from_mtypes(mtypes, live_cast_types)
                var colorer = new POSetColorer[MType]
                colorer.colorize(poset)
                type_ids = colorer.ids
@@ -437,12 +436,13 @@ class SeparateCompiler
                return poset
        end
 
-       private fun poset_from_mtypes(mtypes: Set[MType]): POSet[MType] do
+       private fun poset_from_mtypes(mtypes, cast_types: Set[MType]): POSet[MType] do
                var poset = new POSet[MType]
                for e in mtypes do
                        poset.add_node(e)
-                       for o in mtypes do
+                       for o in cast_types do
                                if e == o then continue
+                               poset.add_node(o)
                                if e.is_subtype(mainmodule, null, o) then
                                        poset.add_edge(e, o)
                                end
@@ -963,7 +963,6 @@ class SeparateCompilerVisitor
        redef fun unbox_signature_extern(m, args)
        do
                var msignature = m.msignature.resolve_for(m.mclassdef.bound_mtype, m.mclassdef.bound_mtype, m.mclassdef.mmodule, true)
-               var recv = args.first
                if not m.mproperty.is_init and m.is_extern then
                        args.first = self.unbox_extern(args.first, m.mclassdef.mclass.mclass_type)
                end
@@ -1063,14 +1062,12 @@ class SeparateCompilerVisitor
        redef fun compile_callsite(callsite, args)
        do
                var rta = compiler.runtime_type_analysis
-               var recv = args.first.mtype
                var mmethod = callsite.mproperty
                # TODO: Inlining of new-style constructors
                if compiler.modelbuilder.toolcontext.opt_direct_call_monomorph.value and rta != null and not mmethod.is_root_init then
                        var tgs = rta.live_targets(callsite)
                        if tgs.length == 1 then
                                # DIRECT CALL
-                               self.varargize(mmethod.intro, mmethod.intro.msignature.as(not null), args)
                                var res0 = before_send(mmethod, args)
                                var res = call(tgs.first, tgs.first.mclassdef.bound_mtype, args)
                                if res0 != null then
@@ -1086,8 +1083,6 @@ class SeparateCompilerVisitor
        end
        redef fun send(mmethod, arguments)
        do
-               self.varargize(mmethod.intro, mmethod.intro.msignature.as(not null), arguments)
-
                if arguments.first.mcasttype.ctype != "val*" then
                        # In order to shortcut the primitive, we need to find the most specific method
                        # Howverr, because of performance (no flattening), we always work on the realmainmodule
@@ -1101,13 +1096,13 @@ class SeparateCompilerVisitor
                return table_send(mmethod, arguments, mmethod.const_color)
        end
 
-       # Handel common special cases before doing the effective method invocation
+       # Handle common special cases before doing the effective method invocation
        # This methods handle the `==` and `!=` methods and the case of the null receiver.
        # Note: a { is open in the generated C, that enclose and protect the effective method invocation.
        # Client must not forget to close the } after them.
        #
        # The value returned is the result of the common special cases.
-       # If not null, client must compine it with the result of their own effective method invocation.
+       # If not null, client must compile it with the result of their own effective method invocation.
        #
        # If `before_send` can shortcut the whole message sending, a dummy `if(0){`
        # is generated to cancel the effective method invocation that will follow
@@ -1117,7 +1112,7 @@ class SeparateCompilerVisitor
                var res: nullable RuntimeVariable = null
                var recv = arguments.first
                var consider_null = not self.compiler.modelbuilder.toolcontext.opt_no_check_null.value or mmethod.name == "==" or mmethod.name == "!="
-               var maybenull = recv.mcasttype isa MNullableType and consider_null
+               var maybenull = (recv.mcasttype isa MNullableType or recv.mcasttype isa MNullType) and consider_null
                if maybenull then
                        self.add("if ({recv} == NULL) \{")
                        if mmethod.name == "==" then
@@ -1148,10 +1143,10 @@ class SeparateCompilerVisitor
                        self.add("\{")
                end
                if not self.compiler.modelbuilder.toolcontext.opt_no_shortcut_equate.value and (mmethod.name == "==" or mmethod.name == "!=") then
-                       if res == null then res = self.new_var(bool_type)
-                       # Recv is not null, thus is arg is, it is easy to conclude (and respect the invariants)
+                       # Recv is not null, thus if arg is, it is easy to conclude (and respect the invariants)
                        var arg = arguments[1]
                        if arg.mcasttype isa MNullType then
+                               if res == null then res = self.new_var(bool_type)
                                if mmethod.name == "==" then
                                        self.add("{res} = 0; /* arg is null but recv is not */")
                                else
@@ -1177,10 +1172,7 @@ class SeparateCompilerVisitor
                var res: nullable RuntimeVariable
                var msignature = mmethod.intro.msignature.resolve_for(mmethod.intro.mclassdef.bound_mtype, mmethod.intro.mclassdef.bound_mtype, mmethod.intro.mclassdef.mmodule, true)
                var ret = msignature.return_mtype
-               if mmethod.is_new then
-                       ret = arguments.first.mtype
-                       res = self.new_var(ret)
-               else if ret == null then
+               if ret == null then
                        res = null
                else
                        res = self.new_var(ret)
@@ -1231,10 +1223,7 @@ class SeparateCompilerVisitor
 
                var res: nullable RuntimeVariable
                var ret = mmethoddef.msignature.return_mtype
-               if mmethoddef.mproperty.is_new then
-                       ret = arguments.first.mtype
-                       res = self.new_var(ret)
-               else if ret == null then
+               if ret == null then
                        res = null
                else
                        ret = ret.resolve_for(mmethoddef.mclassdef.bound_mtype, mmethoddef.mclassdef.bound_mtype, mmethoddef.mclassdef.mmodule, true)
@@ -1762,7 +1751,7 @@ class SeparateCompilerVisitor
        redef fun calloc_array(ret_type, arguments)
        do
                var mclass = self.get_class("ArrayCapable")
-               var ft = mclass.mclass_type.arguments.first.as(MParameterType)
+               var ft = mclass.mparameters.first
                var res = self.native_array_instance(ft, arguments[1])
                self.ret(res)
        end
@@ -1827,9 +1816,6 @@ class SeparateRuntimeFunction
                var ret = msignature.return_mtype
                if ret != null then
                        sig.append("{ret.ctype} ")
-               else if mmethoddef.mproperty.is_new then
-                       ret = recv
-                       sig.append("{ret.ctype} ")
                else
                        sig.append("void ")
                end
@@ -1904,9 +1890,6 @@ class VirtualRuntimeFunction
                var ret = msignature.return_mtype
                if ret != null then
                        sig.append("{ret.ctype} ")
-               else if mmethoddef.mproperty.is_new then
-                       ret = recv
-                       sig.append("{ret.ctype} ")
                else
                        sig.append("void ")
                end
@@ -1972,7 +1955,12 @@ redef class MPropDef
        fun const_color: String do return "COLOR_{c_name}"
 end
 
-redef class AExternInitPropdef
+redef class AMethPropdef
        # The semi-global compilation does not support inlining calls to extern news
-       redef fun can_inline do return false
+       redef fun can_inline
+       do
+               var m = mpropdef
+               if m != null and m.mproperty.is_init and m.is_extern then return false
+               return super
+       end
 end