abstract_compiler: Add import contract
[nit.git] / src / compiler / abstract_compiler.nit
index e3132da..e10be39 100644 (file)
@@ -26,6 +26,7 @@ import mixin
 import counter
 import pkgconfig
 private import explain_assert_api
+import contracts
 
 # Add compiling options
 redef class ToolContext
@@ -1353,29 +1354,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
 
@@ -1392,7 +1370,7 @@ abstract class AbstractCompilerVisitor
        fun native_array_set(native_array: RuntimeVariable, index: Int, value: RuntimeVariable) is abstract
 
        # Instantiate a new routine pointer
-       fun routine_ref_instance(routine_mclass_type: MClassType, recv: RuntimeVariable, mmethoddef: MMethodDef): RuntimeVariable is abstract
+       fun routine_ref_instance(routine_mclass_type: MClassType, recv: RuntimeVariable, callsite: CallSite): RuntimeVariable is abstract
 
        # Call the underlying referenced function
        fun routine_ref_call(mmethoddef: MMethodDef, args: Array[RuntimeVariable]) is abstract
@@ -1412,7 +1390,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)
 
@@ -3710,6 +3688,31 @@ redef class AClassdef
                                v.supercall(mpropdef, arguments.first.mtype.as(MClassType), arguments)
                        end
                        return
+               else if mclassdef.default_init == mpropdef then
+                       var recv = arguments.first
+                       var initializers = mpropdef.initializers
+                       var no_init = false
+                       if not initializers.is_empty and not mpropdef.is_old_style_init 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
@@ -4390,9 +4393,25 @@ redef class ASendExpr
                var res = v.compile_callsite(callsite, args)
                if is_safe then
                        if res != null then
-                               var orig_res = res
+                               # `callsite.mpropdef` may reference a method whose
+                               # return type is a primitive type in C. If it is
+                               # the case, we must convert the primitive type to
+                               # a `val*` to support nullable assignment.
+                               # Autobox's job is to convert primitive type to
+                               # nullable type, eg from `Int` to `nullable `Int`.
+                               # The target type reside in `self.mtype`.
+                               var original_res = v.autobox(res, self.mtype.as(not null))
+
+                               # Here we must create a new_var in case the original
+                               # type is not nullable. We can't call `autobox` to
+                               # convert a complex type to its nullable version.
+                               # eg if we have a type `A`, calling autobox like
+                               # `autobox(A, nullable A)` will return `A` since
+                               # `A` and `nullable A` have the same primitive
+                               # type. The nullable qualifier is only used at
+                               # compile time to add appropriate null checks.
                                res = v.new_var(self.mtype.as(not null))
-                               v.add("{res} = {orig_res};")
+                               v.add("{res} = {original_res};")
                                v.add("\} else \{")
                                v.add("{res} = NULL;")
                        end
@@ -4406,7 +4425,7 @@ redef class ACallrefExpr
        redef fun expr(v)
        do
                var recv = v.expr(self.n_expr, null)
-               var res = v.routine_ref_instance(mtype.as(MClassType), recv, callsite.as(not null).mpropdef)
+               var res = v.routine_ref_instance(mtype.as(MClassType), recv, callsite.as(not null))
                return res
        end
 end