Merge remote-tracking branch 'origin/master' into init_auto
[nit.git] / src / compiler / abstract_compiler.nit
index 3cba054..d2f0b11 100644 (file)
@@ -668,7 +668,9 @@ abstract class AbstractCompiler
                self.header.add_decl("  #define be32toh(val) ((be16toh((val) << 16) | (be16toh((val) >> 16))))")
                self.header.add_decl("#endif")
                self.header.add_decl("#ifdef ANDROID")
-               self.header.add_decl("  #define be32toh(val) betoh32(val)")
+               self.header.add_decl("  #ifndef be32toh")
+               self.header.add_decl("          #define be32toh(val) betoh32(val)")
+               self.header.add_decl("  #endif")
                self.header.add_decl("  #include <android/log.h>")
                self.header.add_decl("  #define PRINT_ERROR(...) (void)__android_log_print(ANDROID_LOG_WARN, \"Nit\", __VA_ARGS__)")
                self.header.add_decl("#else")
@@ -1162,29 +1164,6 @@ abstract class AbstractCompilerVisitor
        fun compile_callsite(callsite: CallSite, arguments: Array[RuntimeVariable]): nullable RuntimeVariable
        do
                if callsite.is_broken then return null
-               var initializers = callsite.mpropdef.initializers
-               if not initializers.is_empty then
-                       var recv = arguments.first
-
-                       var i = 1
-                       for p in initializers do
-                               if p isa MMethod then
-                                       var args = [recv]
-                                       for x in p.intro.msignature.mparameters do
-                                               args.add arguments[i]
-                                               i += 1
-                                       end
-                                       self.send(p, args)
-                               else if p isa MAttribute then
-                                       self.write_attribute(p, recv, arguments[i])
-                                       i += 1
-                               else abort
-                       end
-                       assert i == arguments.length
-
-                       return self.send(callsite.mproperty, [recv])
-               end
-
                return self.send(callsite.mproperty, arguments)
        end
 
@@ -1207,7 +1186,7 @@ abstract class AbstractCompilerVisitor
        # of runtime variables to use in the call.
        fun varargize(mpropdef: MMethodDef, map: nullable SignatureMap, recv: RuntimeVariable, args: SequenceRead[AExpr]): Array[RuntimeVariable]
        do
-               var msignature = mpropdef.new_msignature or else mpropdef.msignature.as(not null)
+               var msignature = mpropdef.msignature.as(not null)
                var res = new Array[RuntimeVariable]
                res.add(recv)
 
@@ -1271,17 +1250,21 @@ abstract class AbstractCompilerVisitor
        do
                mtype = self.anchor(mtype)
                var valmtype = value.mcasttype
+
+               # Do nothing if useless autocast
                if valmtype.is_subtype(self.compiler.mainmodule, null, mtype) then
                        return value
                end
 
+               # Just as_not_null if the target is not nullable.
+               #
+               # eg `nullable PreciseType` adapted to `Object` gives precisetype.
                if valmtype isa MNullableType and valmtype.mtype.is_subtype(self.compiler.mainmodule, null, mtype) then
-                       var res = new RuntimeVariable(value.name, valmtype, valmtype.mtype)
-                       return res
-               else
-                       var res = new RuntimeVariable(value.name, valmtype, mtype)
-                       return res
+                       mtype = valmtype.mtype
                end
+
+               var res = new RuntimeVariable(value.name, value.mtype, mtype)
+               return res
        end
 
        # Generate a super call from a method definition
@@ -1349,13 +1332,18 @@ abstract class AbstractCompilerVisitor
 
        # Checks
 
+       # Can value be null? (according to current knowledge)
+       fun maybenull(value: RuntimeVariable): Bool
+       do
+               return value.mcasttype isa MNullableType or value.mcasttype isa MNullType
+       end
+
        # Add a check and an abort for a null receiver if needed
        fun check_recv_notnull(recv: RuntimeVariable)
        do
                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
+               if maybenull(recv) then
                        self.add("if (unlikely({recv} == NULL)) \{")
                        self.add_abort("Receiver is null")
                        self.add("\}")
@@ -2044,6 +2032,8 @@ redef class MMethodDef
                else if node isa AClassdef then
                        # Automatic free init is always inlined since it is empty or contains only attribtes assigments
                        return true
+               else if node == null then
+                       return true
                else
                        abort
                end
@@ -3092,7 +3082,18 @@ redef class AAttrPropdef
                        v.assign(v.frame.returnvar.as(not null), res)
                else if mpropdef == mwritepropdef then
                        assert arguments.length == 2
-                       v.write_attribute(self.mpropdef.mproperty, arguments.first, arguments[1])
+                       var recv = arguments.first
+                       var arg = arguments[1]
+                       if is_optional and v.maybenull(arg) then
+                               var value = v.new_var(self.mpropdef.static_mtype.as(not null))
+                               v.add("if ({arg} == NULL) \{")
+                               v.assign(value, evaluate_expr(v, recv))
+                               v.add("\} else \{")
+                               v.assign(value, arg)
+                               v.add("\}")
+                               arg = value
+                       end
+                       v.write_attribute(self.mpropdef.mproperty, arguments.first, arg)
                        if is_lazy then
                                var ret = self.mtype
                                var useiset = not ret.is_c_primitive and not ret isa MNullableType
@@ -3173,6 +3174,32 @@ redef class AClassdef
                                v.supercall(mpropdef, arguments.first.mtype.as(MClassType), arguments)
                        end
                        return
+               else if mclassdef.auto_init == mpropdef then
+                       var recv = arguments.first
+                       var initializers = mpropdef.initializers
+                       var no_init = false
+                       if not initializers.is_empty then
+
+                               var i = 1
+                               for p in initializers do
+                                       if p isa MMethod then
+                                               var args = [recv]
+                                               for x in p.intro.msignature.mparameters do
+                                                       args.add arguments[i]
+                                                       i += 1
+                                               end
+                                               v.send(p, args)
+                                               if p.intro.is_calling_init then no_init = true
+                                       else if p isa MAttribute then
+                                               v.write_attribute(p, recv, arguments[i])
+                                               i += 1
+                                       else abort
+                               end
+                               assert i == arguments.length
+
+                       end
+                       if not no_init then v.send(mclass.the_root_init_mmethod.as(not null), [recv])
+                       return
                else
                        abort
                end
@@ -3505,6 +3532,9 @@ redef class AOrElseExpr
        do
                var res = v.new_var(self.mtype.as(not null))
                var i1 = v.expr(self.n_expr, null)
+
+               if not v.maybenull(i1) then return i1
+
                v.add("if ({i1}!=NULL) \{")
                v.assign(res, i1)
                v.add("\} else \{")
@@ -3534,7 +3564,11 @@ redef class AFloatExpr
 end
 
 redef class ACharExpr
-       redef fun expr(v) do return v.char_instance(self.value.as(not null))
+       redef fun expr(v) do
+               if is_ascii then return v.byte_instance(value.as(not null).ascii)
+               if is_code_point then return v.int_instance(value.as(not null).code_point)
+               return v.char_instance(self.value.as(not null))
+       end
 end
 
 redef class AArrayExpr
@@ -3687,7 +3721,7 @@ redef class AAsNotnullExpr
                var i = v.expr(self.n_expr, null)
                if v.compiler.modelbuilder.toolcontext.opt_no_check_assert.value then return i
 
-               if i.mtype.is_c_primitive then return i
+               if not v.maybenull(i) then return i
 
                v.add("if (unlikely({i} == NULL)) \{")
                v.add_abort("Cast failed")