compile: casts ('isa' and 'as') with nullable info
[nit.git] / src / compiling / compiling_methods.nit
index 72b099c..ebbe750 100644 (file)
@@ -24,7 +24,8 @@ redef class CompilerVisitor
        # Compile a statment node
        meth compile_stmt(n: PExpr)
        do
-               add_instr("/* Compile stmt {n.locate} */")
+               if n == null then return
+               #add_instr("/* Compile stmt {n.locate} */")
                n.prepare_compile_stmt(self)
                var i = cfc._variable_index
                n.compile_stmt(self)
@@ -34,26 +35,27 @@ redef class CompilerVisitor
        # Compile is expression node
        meth compile_expr(n: PExpr): String
        do
-               add_instr("/* Compile expr {n.locate} */")
+               #add_instr("/* Compile expr {n.locate} */")
                var i = cfc._variable_index
                var s = n.compile_expr(self)
                cfc._variable_index = i
-               if s[0] == ' ' then
+               if s[0] == ' ' or cfc.is_valid_variable(s) then
                        return s
                end
-               var v = cfc.get_var
+               var v = cfc.get_var("Result")
                add_assignment(v, s)
                return v
        end
 
        # Ensure that a c expression is a var
-       meth ensure_var(s: String): String
+       meth ensure_var(s: String, comment: String): String
        do
-               if s.substring(0,3) == "variable" then
+               if cfc.is_valid_variable(s) then
+                       add_instr("/* Ensure var {s}: {comment}*/")
                        return s
                end
-               var v = cfc.get_var
-               add_assignment(v, s)
+               var v = cfc.get_var(null)
+               add_assignment(v, "{s} /* Ensure var: {comment}*/")
                return v
        end
 
@@ -83,11 +85,6 @@ redef class CompilerVisitor
                return s.to_s
        end
 
-       redef init(module: MMSrcModule)
-       do
-               super
-       end
-
        meth invoke_super_init_calls_after(start_prop: MMMethod)
        do
                var n = nmc.method.node
@@ -128,7 +125,7 @@ redef class CompilerVisitor
                                end
                        end
                        #s.append(" {p}")
-                       p.compile_call(self, cargs)
+                       p.compile_stmt_call(self, cargs)
                        i += 1
                end
                #s.append(" ]")
@@ -151,37 +148,40 @@ class CFunctionContext
        # Total number of variable
        attr _variable_index_max: Int = 0
 
-       # Association between nit variable and the corrsponding c variable
-       attr _varnames: Map[Variable, String] = new HashMap[Variable, String]
+       # Association between nit variable and the corrsponding c variable index
+       attr _varindexes: Map[Variable, Int] = new HashMap[Variable, Int]
 
        # Are we currenlty in a closure definition?
        readable writable attr _closure: NitMethodContext = null
 
+       # Return the cvariable of a Nit variable
        meth varname(v: Variable): String
        do
-               if _closure != null then
-                       return "closctx->{_varnames[v]}"
+               if v isa ClosureVariable then
+                       return closure_variable(_varindexes[v])
                else
-                       return _varnames[v]
+                       return variable(_varindexes[v])
                end
        end
 
        # Return the next available variable
-       meth get_var: String
+       meth get_var(comment: String): String
        do
                var v = variable(_variable_index)
                _variable_index = _variable_index + 1
                if _variable_index > _variable_index_max then
-                       #visitor.add_decl("val_t {v};")
                        _variable_index_max = _variable_index 
                end
+               if comment != null then
+                       visitor.add_instr("/* Register {v}: {comment} */")
+               end
                return v
        end
 
        meth register_variable(v: Variable): String
        do
-               var s = get_var
-               _varnames[v] = "variable[{_variable_index-1}]"
+               _varindexes[v] = _variable_index
+               var s = get_var("Local variable")
                return s
        end
 
@@ -191,8 +191,8 @@ class CFunctionContext
        meth register_closurevariable(v: ClosureVariable): String
        do
                var s = "closurevariable[{_closurevariable_index}]"
+               _varindexes[v] = _closurevariable_index
                _closurevariable_index += 1
-               _varnames[v] = s
                if _closure != null then
                        return "(closctx->{s})"
                else
@@ -200,16 +200,47 @@ class CFunctionContext
                end
        end
 
-       # Return the ith variable
+       # Return the ith cvariable
        protected meth variable(i: Int): String
        do
-               if _closure != null then
-                       return "(closctx->variable[{i}])"
+               if closure != null then
+                       var vn = once new Array[String]
+                       if vn.length <= i then
+                               for j in [vn.length..i] do
+                                       vn[j] = "(closctx->variable[{j}])"
+                               end
+                       end
+                       return vn[i]
                else
-                       return "variable[{i}]"
+                       var vn = once new Array[String]
+                       if vn.length <= i then
+                               for j in [vn.length..i] do
+                                       vn[j] = "variable[{j}]"
+                               end
+                       end
+                       return vn[i]
                end
        end
 
+       # Return the ith closurevariable
+       protected meth closure_variable(i: Int): String
+       do
+               if closure != null then
+                       return "(closctx->closurevariable[{i}])"
+               else
+                       return "closurevariable[{i}]"
+               end
+       end
+
+       # Is s a valid variable
+       protected meth is_valid_variable(s: String): Bool
+       do
+               for i in [0.._variable_index[ do
+                       if s == variable(i) then return true
+               end
+               return false
+       end
+
        # Mark the variable available
        meth free_var(v: String)
        do
@@ -277,11 +308,30 @@ redef class ClosureVariable
 end
 
 redef class MMMethod
+       # Compile as an expression.
+       # require that signature.return_type != null
+       meth compile_expr_call(v: CompilerVisitor, cargs: Array[String]): String
+       do
+               assert signature.return_type != null
+               var s = intern_compile_call(v, cargs)
+               assert s != null
+               return s
+       end
+
+       # Compile as a statement.
+       # require that signature.return_type == null
+       meth compile_stmt_call(v: CompilerVisitor, cargs: Array[String])
+       do
+               assert signature.return_type == null
+               var s = intern_compile_call(v, cargs)
+               assert s == null
+       end
+
        # Compile a call on self for given arguments
        # Most calls are compiled with a table access,
        # primitive calles are inlined
        # == and != are guarded and possibly inlined
-       meth compile_call(v: CompilerVisitor, cargs: Array[String]): String
+       private meth intern_compile_call(v: CompilerVisitor, cargs: Array[String]): String
        do
                var i = self
                if i isa MMSrcMethod then
@@ -296,7 +346,7 @@ redef class MMMethod
                var ne = once "!=".to_symbol
                if name == ne then
                        var eqp = signature.recv.local_class.select_method(ee)
-                       var eqcall = eqp.compile_call(v, cargs)
+                       var eqcall = eqp.compile_expr_call(v, cargs)
                        return "TAG_Bool(!UNTAG_Bool({eqcall}))"
                end
                if global.is_init then
@@ -332,7 +382,7 @@ redef class MMMethod
                # Prepare result value.
                # In case of procedure, the return value is still used to intercept breaks
                var old_bv = v.nmc.break_value
-               ve = v.cfc.get_var
+               ve = v.cfc.get_var("Closure return value and escape marker")
                v.nmc.break_value = ve
 
                # Compile closure to c function
@@ -351,7 +401,7 @@ redef class MMMethod
                v.nmc.break_value = old_bv
 
                # Call
-               var e = compile_call(v, realcargs)
+               var e = intern_compile_call(v, realcargs)
                if e != null then
                        v.add_assignment(ve, e)
                        e = ve
@@ -385,9 +435,7 @@ redef class MMMethod
        # Compile a call as constructor with given args
        meth compile_constructor_call(v: CompilerVisitor, recvtype: MMType, cargs: Array[String]): String
        do
-               var recv = v.cfc.get_var
-               v.add_instr("{recv} = NEW_{recvtype.local_class}_{global.intro.cname}({cargs.join(", ")}); /*new {recvtype}*/")
-               return recv
+               return "NEW_{recvtype.local_class}_{global.intro.cname}({cargs.join(", ")}) /*new {recvtype}*/"
        end
 
        # Compile a call as call-next-method on self with given args
@@ -551,9 +599,9 @@ redef class MMImplicitInit
                                for i in [1..f[ do
                                        args.add(params[i])
                                end
-                               sp.compile_call(v, args)
+                               sp.compile_stmt_call(v, args)
                        else
-                               sp.compile_call(v, args_recv)
+                               sp.compile_stmt_call(v, args_recv)
                        end
                end
                for i in [f..params.length[ do
@@ -567,19 +615,49 @@ end
 redef class MMType
        # Compile a subtype check to self
        # Return a NIT Bool
-       meth compile_cast(v: CompilerVisitor, recv: String): String
+       meth compile_cast(v: CompilerVisitor, recv: String, fromtype: MMType): String
        do
                # Fixme: handle formaltypes
                var g = local_class.global
-               return "TAG_Bool(({recv}==NIT_NULL) || VAL_ISA({recv}, {g.color_id}, {g.id_id})) /*cast {self}*/"
+               var s = ""
+               if fromtype.is_nullable then
+                       if self.is_nullable then
+                               s = "({recv}==NIT_NULL) || "
+                       else
+                               s = "({recv}!=NIT_NULL) && "
+                       end
+               else
+                       # FIXME This is used to not break code without the nullable KW
+                       s = "({recv}==NIT_NULL) || "
+               end
+               return "TAG_Bool({s}VAL_ISA({recv}, {g.color_id}, {g.id_id})) /*cast {self}*/"
        end
 
        # Compile a cast assertion
-       meth compile_type_check(v: CompilerVisitor, recv: String, n: PNode)
+       meth compile_type_check(v: CompilerVisitor, recv: String, n: PNode, fromtype: MMType)
        do
                # Fixme: handle formaltypes
                var g = local_class.global
-               v.add_instr("if (({recv}!=NIT_NULL) && !VAL_ISA({recv}, {g.color_id}, {g.id_id})) \{ fprintf(stderr, \"Cast failled\"); {v.printf_locate_error(n)} nit_exit(1); } /*cast {self}*/;")
+               var s = ""
+               if fromtype.is_nullable then
+                       if self.is_nullable then
+                               s = "({recv}!=NIT_NULL) && "
+                       else
+                               s = "({recv}==NIT_NULL) || "
+                       end
+               else
+                       # FIXME This is used to not break code without the nullable KW
+                       s = "({recv}!=NIT_NULL) && "
+               end
+               v.add_instr("if ({s}!VAL_ISA({recv}, {g.color_id}, {g.id_id})) \{ fprintf(stderr, \"Cast failled\"); {v.printf_locate_error(n)} nit_exit(1); } /*cast {self}*/;")
+       end
+
+       # Compile a notnull cast assertion
+       meth compile_notnull_check(v: CompilerVisitor, recv: String, n: PNode)
+       do
+               if is_nullable then
+                       v.add_instr("if (({recv}==NIT_NULL)) \{ fprintf(stderr, \"Cast failled\"); {v.printf_locate_error(n)} nit_exit(1); } /*cast {self}*/;")
+               end
        end
 end
 
@@ -605,7 +683,7 @@ redef class ASignature
                                # FIXME: do not test always
                                # FIXME: handle formal types
                                v.add_instr("/* check if p<{ap.variable.stype} with p:{orig_type} */")
-                               ap.variable.stype.compile_type_check(v, params[ap.position], ap)
+                               ap.variable.stype.compile_type_check(v, params[ap.position], ap, orig_type)
                        end
                        v.add_assignment(cname, params[ap.position])
                end
@@ -643,13 +721,11 @@ redef class AConcreteMethPropdef
                end
 
                v.nmc.return_label = "return_label{v.new_number}"
-               v.nmc.return_value = v.cfc.get_var
+               v.nmc.return_value = v.cfc.get_var("Method return value and escape marker")
                if self isa AConcreteInitPropdef then
                        v.invoke_super_init_calls_after(null)
                end
-               if n_block != null then
-                       v.compile_stmt(n_block)
-               end
+               v.compile_stmt(n_block)
                v.add_instr("{v.nmc.return_label}: while(false);")
                if self isa AConcreteInitPropdef then
                        v.add_instr("init_table[{itpos}] = 1;")
@@ -968,9 +1044,7 @@ end
 redef class ADoExpr
        redef meth compile_stmt(v)
        do
-                if n_block != null then
-                        v.compile_stmt(n_block)
-                end
+               v.compile_stmt(n_block)
        end
 end
 
@@ -1002,12 +1076,12 @@ redef class AIfexprExpr
                v.add_instr("if (UNTAG_Bool({e})) \{ /*if*/")
                v.cfc.free_var(e)
                v.indent
-               var e = v.ensure_var(v.compile_expr(n_then))
+               var e = v.ensure_var(v.compile_expr(n_then), "Then value")
                v.unindent
                v.add_instr("} else \{ /*if*/")
                v.cfc.free_var(e)
                v.indent
-               var e2 = v.ensure_var(v.compile_expr(n_else))
+               var e2 = v.ensure_var(v.compile_expr(n_else), "Else value")
                v.add_assignment(e, e2)
                v.unindent
                v.add_instr("}")
@@ -1015,7 +1089,8 @@ redef class AIfexprExpr
        end
 end
 
-redef class AControlableBlock
+class AControlableBlock
+special PExpr
        meth compile_inside_block(v: CompilerVisitor) is abstract
        redef meth compile_stmt(v)
        do
@@ -1034,6 +1109,7 @@ redef class AControlableBlock
 end
 
 redef class AWhileExpr
+special AControlableBlock
        redef meth compile_inside_block(v)
        do
                v.add_instr("while (true) \{ /*while*/")
@@ -1041,9 +1117,7 @@ redef class AWhileExpr
                var e = v.compile_expr(n_expr)
                v.add_instr("if (!UNTAG_Bool({e})) break; /* while*/")
                v.cfc.free_var(e)
-               if n_block != null then
-                       v.compile_stmt(n_block)
-               end
+               v.compile_stmt(n_block)
                v.add_instr("{v.nmc.continue_label}: while(0);")
                v.unindent
                v.add_instr("}")
@@ -1052,30 +1126,27 @@ redef class AWhileExpr
 end
 
 redef class AForExpr
+special AControlableBlock
        redef meth compile_inside_block(v)
        do
                var e = v.compile_expr(n_expr)
                var ittype = meth_iterator.signature.return_type
                v.cfc.free_var(e)
-               var iter = v.cfc.get_var
-               v.add_assignment(iter, meth_iterator.compile_call(v, [e]))
+               var iter = v.cfc.get_var("For iterator")
+               v.add_assignment(iter, meth_iterator.compile_expr_call(v, [e]))
                v.add_instr("while (true) \{ /*for*/")
                v.indent
-               var ok = v.cfc.get_var
-               v.add_assignment(ok, meth_is_ok.compile_call(v, [iter]))
+               var ok = v.cfc.get_var("For 'is_ok' result")
+               v.add_assignment(ok, meth_is_ok.compile_expr_call(v, [iter]))
                v.add_instr("if (!UNTAG_Bool({ok})) break; /*for*/")
                v.cfc.free_var(ok)
-               var e = meth_item.compile_call(v, [iter])
-               e = v.ensure_var(e)
+               var e = meth_item.compile_expr_call(v, [iter])
+               e = v.ensure_var(e, "For item")
                var cname = v.cfc.register_variable(variable)
                v.add_assignment(cname, e)
-               var n_block = n_block
-               if n_block != null then
-                       v.compile_stmt(n_block)
-               end
+               v.compile_stmt(n_block)
                v.add_instr("{v.nmc.continue_label}: while(0);")
-               e = meth_next.compile_call(v, [iter])
-               assert e == null
+               meth_next.compile_stmt_call(v, [iter])
                v.unindent
                v.add_instr("}")
                v.add_instr("{v.nmc.break_label}: while(0);")
@@ -1114,7 +1185,7 @@ redef class AVarReassignExpr
        do
                var e1 = v.cfc.varname(variable)
                var e2 = v.compile_expr(n_value)
-               var e3 = assign_method.compile_call(v, [e1, e2])
+               var e3 = assign_method.compile_expr_call(v, [e1, e2])
                v.add_assignment(v.cfc.varname(variable), "{e3} /*{variable.name}*/")
        end
 end
@@ -1129,7 +1200,7 @@ end
 redef class AOrExpr
        redef meth compile_expr(v)
        do
-               var e = v.ensure_var(v.compile_expr(n_expr))
+               var e = v.ensure_var(v.compile_expr(n_expr), "Left 'or' operand")
                v.add_instr("if (!UNTAG_Bool({e})) \{ /* or */")
                v.cfc.free_var(e)
                v.indent
@@ -1144,7 +1215,7 @@ end
 redef class AAndExpr
        redef meth compile_expr(v)
        do
-               var e = v.ensure_var(v.compile_expr(n_expr))
+               var e = v.ensure_var(v.compile_expr(n_expr), "Left 'and' operand")
                v.add_instr("if (UNTAG_Bool({e})) \{ /* and */")
                v.cfc.free_var(e)
                v.indent
@@ -1176,7 +1247,7 @@ redef class AIsaExpr
        redef meth compile_expr(v)
        do
                var e = v.compile_expr(n_expr)
-               return n_type.stype.compile_cast(v, e)
+               return n_type.stype.compile_cast(v, e, n_expr.stype)
        end
 end
 
@@ -1184,7 +1255,16 @@ redef class AAsCastExpr
        redef meth compile_expr(v)
        do
                var e = v.compile_expr(n_expr)
-               n_type.stype.compile_type_check(v, e, self)
+               n_type.stype.compile_type_check(v, e, self, n_expr.stype)
+               return e
+       end
+end
+
+redef class AAsNotnullExpr
+       redef meth compile_expr(v)
+       do
+               var e = v.compile_expr(n_expr)
+               n_expr.stype.compile_notnull_check(v, e, self)
                return e
        end
 end
@@ -1229,7 +1309,7 @@ redef class AStringFormExpr
        do
                compute_string_info
                var i = v.new_number
-               var cvar = v.cfc.get_var
+               var cvar = v.cfc.get_var("Once String constant")
                v.add_decl("static val_t once_value_{i} = NIT_NULL; /* Once value for string {cvar}*/")
                v.add_instr("if (once_value_{i} != NIT_NULL) {cvar} = once_value_{i};")
                v.add_instr("else \{")
@@ -1295,16 +1375,19 @@ redef class ASuperstringExpr
        redef meth compile_expr(v)
        do
                var array = meth_with_capacity.compile_constructor_call(v, atype, ["TAG_Int({n_exprs.length})"])
+               array = v.ensure_var(array, "Array (for super-string)")
 
                for ne in n_exprs do
-                       var e = v.ensure_var(v.compile_expr(ne))
+                       var e = v.ensure_var(v.compile_expr(ne), "super-string element")
                        if ne.stype != stype then
-                               v.add_assignment(e, meth_to_s.compile_call(v, [e]))
+                               v.cfc.free_var(e)
+                               e = meth_to_s.compile_expr_call(v, [e])
                        end
-                       meth_add.compile_call(v, [array, e])
+                       v.cfc.free_var(e)
+                       meth_add.compile_stmt_call(v, [array, e])
                end
 
-               return meth_to_s.compile_call(v, [array])
+               return meth_to_s.compile_expr_call(v, [array])
        end
 end
 
@@ -1319,10 +1402,11 @@ redef class AArrayExpr
        redef meth compile_expr(v)
        do
                var recv = meth_with_capacity.compile_constructor_call(v, stype, ["TAG_Int({n_exprs.length})"])
+               recv = v.ensure_var(recv, "Literal array")
 
                for ne in n_exprs do
                        var e = v.compile_expr(ne)
-                       meth_add.compile_call(v, [recv, e])
+                       meth_add.compile_stmt_call(v, [recv, e])
                end
                return recv
        end
@@ -1340,12 +1424,21 @@ end
 redef class ASuperExpr
        redef meth compile_stmt(v)
        do
-               var e = compile_expr(v)
-               if e != null then v.add_instr("{e};")
+               var e = intern_compile_call(v)
+               if e != null then
+                       v.add_instr(e + ";")
+               end
        end
 
        redef meth compile_expr(v)
        do
+               var e = intern_compile_call(v)
+               assert e != null
+               return e
+       end
+
+       private meth intern_compile_call(v: CompilerVisitor): String
+       do
                var arity = v.nmc.method_params.length - 1
                if init_in_superclass != null then
                        arity = init_in_superclass.signature.arity
@@ -1363,7 +1456,7 @@ redef class ASuperExpr
                end
                #return "{prop.cname}({args.join(", ")}) /*super {prop.local_class}::{prop.name}*/"
                if init_in_superclass != null then
-                       return init_in_superclass.compile_call(v, args)
+                       return init_in_superclass.intern_compile_call(v, args)
                else
                        if prop.global.is_init then args.add("init_table")
                        return prop.compile_super_call(v, args)
@@ -1393,24 +1486,33 @@ redef class AAttrReassignExpr
                var e1 = v.compile_expr(n_expr)
                var e2 = prop.compile_access(v, e1)
                var e3 = v.compile_expr(n_value)
-               var e4 = assign_method.compile_call(v, [e2, e3])
+               var e4 = assign_method.compile_expr_call(v, [e2, e3])
                v.add_assignment(e2, e4)
        end
 end
 
+redef class AAbsAbsSendExpr
+       # Compile each argument and add them to the array
+       meth compile_arguments_in(v: CompilerVisitor, cargs: Array[String])
+       do
+               for a in arguments do
+                       cargs.add(v.compile_expr(a))
+               end
+       end
+
+end
+
 redef class ASendExpr
-       redef meth compile_expr(v)
+       private meth intern_compile_call(v: CompilerVisitor): String
        do
                var recv = v.compile_expr(n_expr)
                var cargs = new Array[String]
                cargs.add(recv)
-               for a in arguments do
-                       cargs.add(v.compile_expr(a))
-               end
+               compile_arguments_in(v, cargs)
 
                var e: String
                if prop_signature.closures.is_empty then
-                       e = prop.compile_call(v, cargs)
+                       e = prop.intern_compile_call(v, cargs)
                else
                        e = prop.compile_call_and_closures(v, cargs, closure_defs)
                end
@@ -1421,9 +1523,16 @@ redef class ASendExpr
                return e
        end
 
+       redef meth compile_expr(v)
+       do
+               var e = intern_compile_call(v)
+               assert e != null
+               return e
+       end
+
        redef meth compile_stmt(v)
        do
-               var e = compile_expr(v)
+               var e = intern_compile_call(v)
                if e != null then
                        v.add_instr(e + ";")
                end
@@ -1431,20 +1540,20 @@ redef class ASendExpr
 end
 
 redef class ASendReassignExpr
-       redef meth compile_expr(v)
+       redef meth compile_expr(v) do abort
+
+       redef meth compile_stmt(v)
        do
                var recv = v.compile_expr(n_expr)
                var cargs = new Array[String]
                cargs.add(recv)
-               for a in arguments do
-                       cargs.add(v.compile_expr(a))
-               end
+               compile_arguments_in(v, cargs)
 
-               var e2 = read_prop.compile_call(v, cargs)
+               var e2 = read_prop.compile_expr_call(v, cargs)
                var e3 = v.compile_expr(n_value)
-               var e4 = assign_method.compile_call(v, [e2, e3])
+               var e4 = assign_method.compile_expr_call(v, [e2, e3])
                cargs.add(e4)
-               return prop.compile_call(v, cargs)
+               prop.compile_stmt_call(v, cargs)
        end
 end
 
@@ -1452,11 +1561,11 @@ redef class ANewExpr
        redef meth compile_expr(v)
        do
                var cargs = new Array[String]
-               for a in arguments do
-                       cargs.add(v.compile_expr(a))
-               end
+               compile_arguments_in(v, cargs)
                return prop.compile_constructor_call(v, stype, cargs) 
        end
+
+       redef meth compile_stmt(v) do abort
 end
 
 redef class PClosureDef
@@ -1574,11 +1683,11 @@ redef class AClosureDef
                var old_cl = v.nmc.continue_label
                var old_bl = v.nmc.break_label
 
-               v.nmc.continue_value = v.cfc.get_var
+               v.nmc.continue_value = v.cfc.get_var("Continue value and escape marker")
                v.nmc.continue_label = "continue_label{v.new_number}"
                v.nmc.break_label = v.nmc.return_label
 
-               if n_expr != null then v.compile_stmt(n_expr)
+               v.compile_stmt(n_expr)
 
                v.add_instr("{v.nmc.continue_label}: while(false);")
 
@@ -1605,11 +1714,11 @@ redef class AClosureDecl
                var old_cl = v.nmc.continue_label
                var old_bl = v.nmc.break_label
 
-               v.nmc.continue_value = v.cfc.get_var
+               v.nmc.continue_value = v.cfc.get_var("Continue value and escape marker")
                v.nmc.continue_label = "continue_label{v.new_number}"
                v.nmc.break_label = v.nmc.return_label
 
-               if n_expr != null then v.compile_stmt(n_expr)
+               v.compile_stmt(n_expr)
 
                v.add_instr("{v.nmc.continue_label}: while(false);")
 
@@ -1625,12 +1734,12 @@ redef class AClosureDecl
 end
 
 redef class AClosureCallExpr
-       redef meth compile_expr(v)
+       meth intern_compile_call(v: CompilerVisitor): String
        do
                var cargs = new Array[String]
-               for a in arguments do cargs.add(v.compile_expr(a))
+               compile_arguments_in(v, cargs)
                var va: String = null
-               if variable.closure.signature.return_type != null then va = v.cfc.get_var
+               if variable.closure.signature.return_type != null then va = v.cfc.get_var("Closure call result value")
 
                if variable.closure.is_optional then
                        v.add_instr("if({v.cfc.varname(variable)}==NULL) \{")
@@ -1669,6 +1778,21 @@ redef class AClosureCallExpr
                end
                return va
        end
+
+       redef meth compile_expr(v)
+       do
+               var e = intern_compile_call(v)
+               assert e != null
+               return e
+       end
+
+       redef meth compile_stmt(v)
+       do
+               var e = intern_compile_call(v)
+               if e != null then
+                       v.add_instr(e + ";")
+               end
+       end
 end
 
 redef class AProxyExpr
@@ -1682,7 +1806,7 @@ redef class AOnceExpr
        redef meth compile_expr(v)
        do
                var i = v.new_number
-               var cvar = v.cfc.get_var
+               var cvar = v.cfc.get_var("Once expression result")
                v.add_decl("static val_t once_value_{i}; static int once_bool_{i}; /* Once value for {cvar}*/")
                v.add_instr("if (once_bool_{i}) {cvar} = once_value_{i};")
                v.add_instr("else \{")