icode: ITypeCheck requires a receiver
[nit.git] / src / icode / icode_tools.nit
index 33b0010..6316748 100644 (file)
@@ -92,22 +92,11 @@ class ICodeVisitor
 end
 
 redef class ICodeBuilder
-       # IRoutine currently inlining
-       # Used to avoid recursive inlining
-       var _current_inlining: Array[IRoutine] = new Array[IRoutine]
-
-       # Return false if routine can be saflely inlined
-       fun is_currently_inlining_routine(routine: IRoutine): Bool
-       do
-               return routine == iroutine or _current_inlining.has(routine)
-       end
-
        # Inline an iroutine in the current icode sequence
-       # Require not is_currently_inlining
+       # Require that routine != self.iroutine
        fun inline_routine(routine: IRoutine, args: Sequence[IRegister], closdefs: nullable Sequence[nullable IClosureDef]): nullable IRegister
        do
-               assert not is_currently_inlining_routine(routine)
-               _current_inlining.add(routine)
+               assert routine != self.iroutine
                var d = new ICodeDupContext(self)
                assert args.length == routine.params.length
                var closdecls = routine.closure_decls
@@ -154,7 +143,6 @@ redef class ICodeBuilder
 
                # Process inlining
                routine.body.dup_with(d)
-               _current_inlining.pop
                return res
        end
 end
@@ -175,7 +163,7 @@ private class ICodeDupContext
        end
 
        # Return a correct bunch of registers
-       fun dup_iregs(regs: Sequence[IRegister]): Sequence[IRegister]
+       fun dup_iregs(regs: Sequence[IRegister]): Array[IRegister]
        do
                var a = new Array[IRegister].with_capacity(regs.length)
                for r in regs do
@@ -224,7 +212,23 @@ redef class ICode
                var c = inner_dup_with(d)
                if self isa ICodeN then
                        assert c isa ICodeN
-                       c.closure_defs = closure_defs
+                       var cdecl = closure_defs
+                       if cdecl != null then
+                               # Duplicate the colsure definitions
+                               var cdecl2 = new Array[nullable IClosureDef].with_capacity(cdecl.length)
+                               for cd in cdecl do
+                                       if cd == null then
+                                               cdecl2.add(null)
+                                       else
+                                               var r = cd.result
+                                               if r != null then r = d.dup_ireg(r)
+                                               var cd2 = new IClosureDef(d.dup_iregs(cd.params), r)
+                                               cdecl2.add(cd2)
+                                               cd.body.dup_seq_to(d, cd2.body)
+                                       end
+                               end
+                               c.closure_defs = cdecl2
+                       end
                end
                var r = result
                if r != null then c.result = d.dup_ireg(r)
@@ -350,30 +354,77 @@ end
 redef class IClosCall
        redef fun dup_with(d)
        do
-               var closdef = d._closures[closure_decl]
-               if closdef == null then
-                       # Default is already guarded and inlined
-                       return
-               end
-               # Break sequence cannot be inlined :/
-               assert break_seq == null
-               var res = d._icb.inline_routine(closdef, d.dup_iregs(exprs), null)
-               if result != null then
-                       assert res != null
-                       d._icb.stmt(new IMove(d.dup_ireg(result.as(not null)), res))
+               if d._closures.has_key(closure_decl) then
+                       # The icloscall need to be replaced with an inlined closdef
+                       var closdef = d._closures[closure_decl]
+                       if closdef == null then
+                               # Default is already guarded and inlined
+                               return
+                       end
+                       # Break sequence cannot be inlined :/
+                       assert break_seq == null
+                       # Inline the closdef
+                       var res = d._icb.inline_routine(closdef, d.dup_iregs(exprs), null)
+                       if result != null then
+                               assert res != null
+                               d._icb.stmt(new IMove(d.dup_ireg(result.as(not null)), res))
+                       end
+               else
+                       # Standard icloscall duplication
+                       super
                end
        end
+
+       redef fun inner_dup_with(d)
+       do
+               return new IClosCall(closure_decl, exprs)
+       end
 end
 
 redef class INative
        redef fun inner_dup_with(d)
        do
-               var c2 = new INative(code, d.dup_iregs(exprs))
+               var c2 = new INative(method, d.dup_iregs(exprs))
                c2.is_pure = is_pure
                return c2
        end
 end
 
+redef class IIntValue
+       redef fun inner_dup_with(d)
+       do
+               return new IIntValue(value)
+       end
+end
+
+redef class IBoolValue
+       redef fun inner_dup_with(d)
+       do
+               return new IBoolValue(value)
+       end
+end
+
+redef class IStringValue
+       redef fun inner_dup_with(d)
+       do
+               return new IStringValue(value)
+       end
+end
+
+redef class IFloatValue
+       redef fun inner_dup_with(d)
+       do
+               return new IFloatValue(value)
+       end
+end
+
+redef class ICharValue
+       redef fun inner_dup_with(d)
+       do
+               return new ICharValue(value)
+       end
+end
+
 redef class IMove
        redef fun inner_dup_with(d)
        do
@@ -405,7 +456,7 @@ end
 redef class ITypeCheck
        redef fun inner_dup_with(d)
        do
-               return new ITypeCheck(d.dup_ireg(expr), stype)
+               return new ITypeCheck(d.dup_ireg(expr1), d.dup_ireg(expr2), stype)
        end
 end
 
@@ -435,13 +486,18 @@ end
 redef class IHasClos
        redef fun inner_dup_with(d)
        do
-               var closdef = d._closures[closure_decl]
-               var res: IRegister
-               if closdef != null then
-                       res = d._icb.lit_true_reg
+               if d._closures.has_key(closure_decl) then
+                       # closdef will be inlined
+                       var closdef = d._closures[closure_decl]
+                       var res: IRegister
+                       if closdef != null then
+                               res = d._icb.lit_true_reg
+                       else
+                               res = d._icb.lit_false_reg
+                       end
+                       return new IMove(d.dup_ireg(result.as(not null)), res)
                else
-                       res = d._icb.lit_false_reg
+                       return new IHasClos(closure_decl)
                end
-               return new IMove(d.dup_ireg(result.as(not null)), res)
        end
 end