summary refs log tree commit diff stats
path: root/compiler/ccgcalls.nim
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/ccgcalls.nim')
-rw-r--r--compiler/ccgcalls.nim395
1 files changed, 302 insertions, 93 deletions
diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim
index b01a81c5e..2dacc25e9 100644
--- a/compiler/ccgcalls.nim
+++ b/compiler/ccgcalls.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2013 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -19,13 +19,13 @@ proc hasNoInit(call: PNode): bool {.inline.} =
   result = call.sons[0].kind == nkSym and sfNoInit in call.sons[0].sym.flags
 
 proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
-               callee, params: PRope) =
-  var pl = con(callee, ~"(", params)
+               callee, params: Rope) =
+  var pl = callee & ~"(" & params
   # getUniqueType() is too expensive here:
   var typ = skipTypes(ri.sons[0].typ, abstractInst)
   if typ.sons[0] != nil:
     if isInvalidReturnType(typ.sons[0]):
-      if params != nil: pl.app(~", ")
+      if params != nil: pl.add(~", ")
       # beware of 'result = p(result)'. We may need to allocate a temporary:
       if d.k in {locTemp, locNone} or not leftAppearsOnRightSide(le, ri):
         # Great, we can use 'd':
@@ -33,26 +33,34 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
         elif d.k notin {locExpr, locTemp} and not hasNoInit(ri):
           # reset before pass as 'result' var:
           resetLoc(p, d)
-        app(pl, addrLoc(d))
-        app(pl, ~");$n")
+        add(pl, addrLoc(d))
+        add(pl, ~");$n")
         line(p, cpsStmts, pl)
       else:
         var tmp: TLoc
         getTemp(p, typ.sons[0], tmp, needsInit=true)
-        app(pl, addrLoc(tmp))
-        app(pl, ~");$n")
+        add(pl, addrLoc(tmp))
+        add(pl, ~");$n")
         line(p, cpsStmts, pl)
         genAssignment(p, d, tmp, {}) # no need for deep copying
     else:
-      app(pl, ~")")
-      if d.k == locNone: getTemp(p, typ.sons[0], d)
-      assert(d.t != nil)        # generate an assignment to d:
-      var list: TLoc
-      initLoc(list, locCall, d.t, OnUnknown)
-      list.r = pl
-      genAssignment(p, d, list, {}) # no need for deep copying
+      add(pl, ~")")
+      if p.module.compileToCpp and lfSingleUse in d.flags:
+        # do not generate spurious temporaries for C++! For C we're better off
+        # with them to prevent undefined behaviour and because the codegen
+        # is free to emit expressions multiple times!
+        d.k = locCall
+        d.r = pl
+        excl d.flags, lfSingleUse
+      else:
+        if d.k == locNone: getTemp(p, typ.sons[0], d)
+        assert(d.t != nil)        # generate an assignment to d:
+        var list: TLoc
+        initLoc(list, locCall, d.t, OnUnknown)
+        list.r = pl
+        genAssignment(p, d, list, {}) # no need for deep copying
   else:
-    app(pl, ~");$n")
+    add(pl, ~");$n")
     line(p, cpsStmts, pl)
 
 proc isInCurrentFrame(p: BProc, n: PNode): bool =
@@ -75,7 +83,7 @@ proc isInCurrentFrame(p: BProc, n: PNode): bool =
     result = isInCurrentFrame(p, n.sons[0])
   else: discard
 
-proc openArrayLoc(p: BProc, n: PNode): PRope =
+proc openArrayLoc(p: BProc, n: PNode): Rope =
   var a: TLoc
 
   let q = skipConv(n)
@@ -90,33 +98,34 @@ proc openArrayLoc(p: BProc, n: PNode): PRope =
       of tyOpenArray, tyVarargs, tyArray, tyArrayConstr:
         "($1)+($2), ($3)-($2)+1"
       of tyString, tySequence:
-        if skipTypes(n.typ, abstractInst).kind == tyVar:
+        if skipTypes(n.typ, abstractInst).kind == tyVar and
+            not compileToCpp(p.module):
           "(*$1)->data+($2), ($3)-($2)+1"
         else:
           "$1->data+($2), ($3)-($2)+1"
       else: (internalError("openArrayLoc: " & typeToString(a.t)); "")
-    result = ropef(fmt, [rdLoc(a), rdLoc(b), rdLoc(c)])
+    result = fmt % [rdLoc(a), rdLoc(b), rdLoc(c)]
   else:
     initLocExpr(p, n, a)
     case skipTypes(a.t, abstractVar).kind
     of tyOpenArray, tyVarargs:
-      result = ropef("$1, $1Len0", [rdLoc(a)])
+      result = "$1, $1Len0" % [rdLoc(a)]
     of tyString, tySequence:
-      if skipTypes(n.typ, abstractInst).kind == tyVar:
-        result = ropef("(*$1)->data, (*$1)->$2", [a.rdLoc, lenField(p)])
+      if skipTypes(n.typ, abstractInst).kind == tyVar and
+            not compileToCpp(p.module):
+        result = "(*$1)->data, (*$1)->$2" % [a.rdLoc, lenField(p)]
       else:
-        result = ropef("$1->data, $1->$2", [a.rdLoc, lenField(p)])
+        result = "$1->data, $1->$2" % [a.rdLoc, lenField(p)]
     of tyArray, tyArrayConstr:
-      result = ropef("$1, $2", [rdLoc(a), toRope(lengthOrd(a.t))])
+      result = "$1, $2" % [rdLoc(a), rope(lengthOrd(a.t))]
     else: internalError("openArrayLoc: " & typeToString(a.t))
 
-proc genArgStringToCString(p: BProc, 
-                           n: PNode): PRope {.inline.} =
+proc genArgStringToCString(p: BProc, n: PNode): Rope {.inline.} =
   var a: TLoc
   initLocExpr(p, n.sons[0], a)
-  result = ropef("$1->data", [a.rdLoc])
-  
-proc genArg(p: BProc, n: PNode, param: PSym): PRope =
+  result = "$1->data" % [a.rdLoc]
+
+proc genArg(p: BProc, n: PNode, param: PSym; call: PNode): Rope =
   var a: TLoc
   if n.kind == nkStringToCString:
     result = genArgStringToCString(p, n)
@@ -126,23 +135,35 @@ proc genArg(p: BProc, n: PNode, param: PSym): PRope =
   elif ccgIntroducedPtr(param):
     initLocExpr(p, n, a)
     result = addrLoc(a)
+  elif p.module.compileToCpp and param.typ.kind == tyVar and
+      n.kind == nkHiddenAddr:
+    initLocExprSingleUse(p, n.sons[0], a)
+    # if the proc is 'importc'ed but not 'importcpp'ed then 'var T' still
+    # means '*T'. See posix.nim for lots of examples that do that in the wild.
+    let callee = call.sons[0]
+    if callee.kind == nkSym and
+        {sfImportC, sfInfixCall, sfCompilerProc} * callee.sym.flags == {sfImportC} and
+        {lfHeader, lfNoDecl} * callee.sym.loc.flags != {}:
+      result = addrLoc(a)
+    else:
+      result = rdLoc(a)
   else:
-    initLocExpr(p, n, a)
+    initLocExprSingleUse(p, n, a)
     result = rdLoc(a)
 
-proc genArgNoParam(p: BProc, n: PNode): PRope =
+proc genArgNoParam(p: BProc, n: PNode): Rope =
   var a: TLoc
   if n.kind == nkStringToCString:
     result = genArgStringToCString(p, n)
   else:
-    initLocExpr(p, n, a)
+    initLocExprSingleUse(p, n, a)
     result = rdLoc(a)
 
 proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
   var op: TLoc
   # this is a hotspot in the compiler
   initLocExpr(p, ri.sons[0], op)
-  var params: PRope
+  var params: Rope
   # getUniqueType() is too expensive here:
   var typ = skipTypes(ri.sons[0].typ, abstractInst)
   assert(typ.kind == tyProc)
@@ -150,48 +171,49 @@ proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
   var length = sonsLen(ri)
   for i in countup(1, length - 1):
     if ri.sons[i].typ.isCompileTimeOnly: continue
-    if params != nil: app(params, ~", ")
+    if params != nil: add(params, ~", ")
     if i < sonsLen(typ):
       assert(typ.n.sons[i].kind == nkSym)
-      app(params, genArg(p, ri.sons[i], typ.n.sons[i].sym))
+      add(params, genArg(p, ri.sons[i], typ.n.sons[i].sym, ri))
     else:
-      app(params, genArgNoParam(p, ri.sons[i]))
+      add(params, genArgNoParam(p, ri.sons[i]))
   fixupCall(p, le, ri, d, op.r, params)
 
 proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
 
-  proc getRawProcType(p: BProc, t: PType): PRope =
+  proc getRawProcType(p: BProc, t: PType): Rope =
     result = getClosureType(p.module, t, clHalf)
 
-  proc addComma(r: PRope): PRope =
-    result = if r == nil: r else: con(r, ~", ")
+  proc addComma(r: Rope): Rope =
+    result = if r == nil: r else: r & ~", "
 
   const PatProc = "$1.ClEnv? $1.ClPrc($3$1.ClEnv):(($4)($1.ClPrc))($2)"
   const PatIter = "$1.ClPrc($3$1.ClEnv)" # we know the env exists
   var op: TLoc
   initLocExpr(p, ri.sons[0], op)
-  var pl: PRope
-  
+  var pl: Rope
+
   var typ = skipTypes(ri.sons[0].typ, abstractInst)
   assert(typ.kind == tyProc)
   var length = sonsLen(ri)
   for i in countup(1, length - 1):
     assert(sonsLen(typ) == sonsLen(typ.n))
+    if ri.sons[i].typ.isCompileTimeOnly: continue
     if i < sonsLen(typ):
       assert(typ.n.sons[i].kind == nkSym)
-      app(pl, genArg(p, ri.sons[i], typ.n.sons[i].sym))
+      add(pl, genArg(p, ri.sons[i], typ.n.sons[i].sym, ri))
     else:
-      app(pl, genArgNoParam(p, ri.sons[i]))
-    if i < length - 1: app(pl, ~", ")
-  
+      add(pl, genArgNoParam(p, ri.sons[i]))
+    if i < length - 1: add(pl, ~", ")
+
   template genCallPattern {.dirty.} =
-    lineF(p, cpsStmts, callPattern & ";$n", op.r, pl, pl.addComma, rawProc)
+    lineF(p, cpsStmts, callPattern & ";$n", [op.r, pl, pl.addComma, rawProc])
 
   let rawProc = getRawProcType(p, typ)
   let callPattern = if tfIterator in typ.flags: PatIter else: PatProc
   if typ.sons[0] != nil:
     if isInvalidReturnType(typ.sons[0]):
-      if sonsLen(ri) > 1: app(pl, ~", ")
+      if sonsLen(ri) > 1: add(pl, ~", ")
       # beware of 'result = p(result)'. We may need to allocate a temporary:
       if d.k in {locTemp, locNone} or not leftAppearsOnRightSide(le, ri):
         # Great, we can use 'd':
@@ -200,12 +222,12 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
         elif d.k notin {locExpr, locTemp} and not hasNoInit(ri):
           # reset before pass as 'result' var:
           resetLoc(p, d)
-        app(pl, addrLoc(d))
+        add(pl, addrLoc(d))
         genCallPattern()
       else:
         var tmp: TLoc
         getTemp(p, typ.sons[0], tmp, needsInit=true)
-        app(pl, addrLoc(tmp))
+        add(pl, addrLoc(tmp))
         genCallPattern()
         genAssignment(p, d, tmp, {}) # no need for deep copying
     else:
@@ -213,37 +235,214 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
       assert(d.t != nil)        # generate an assignment to d:
       var list: TLoc
       initLoc(list, locCall, d.t, OnUnknown)
-      list.r = ropef(callPattern, op.r, pl, pl.addComma, rawProc)
+      list.r = callPattern % [op.r, pl, pl.addComma, rawProc]
       genAssignment(p, d, list, {}) # no need for deep copying
   else:
     genCallPattern()
-  
+
+proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): Rope =
+  if ri.sons[i].typ.isCompileTimeOnly:
+    result = nil
+  elif i < sonsLen(typ):
+    # 'var T' is 'T&' in C++. This means we ignore the request of
+    # any nkHiddenAddr when it's a 'var T'.
+    assert(typ.n.sons[i].kind == nkSym)
+    if typ.sons[i].kind == tyVar and ri.sons[i].kind == nkHiddenAddr:
+      result = genArgNoParam(p, ri.sons[i][0])
+    else:
+      result = genArgNoParam(p, ri.sons[i]) #, typ.n.sons[i].sym)
+  else:
+    result = genArgNoParam(p, ri.sons[i])
+
+discard """
+Dot call syntax in C++
+======================
+
+so c2nim translates 'this' sometimes to 'T' and sometimes to 'var T'
+both of which are wrong, but often more convenient to use.
+For manual wrappers it can also be 'ptr T'
+
+Fortunately we know which parameter is the 'this' parameter and so can fix this
+mess in the codegen.
+now ... if the *argument* is a 'ptr' the codegen shall emit -> and otherwise .
+but this only depends on the argument and not on how the 'this' was declared
+however how the 'this' was declared affects whether we end up with
+wrong 'addr' and '[]' ops...
+
+Since I'm tired I'll enumerate all the cases here:
+
+var
+  x: ptr T
+  y: T
+
+proc t(x: T)
+x[].t()  --> (*x).t()  is correct.
+y.t()    --> y.t()  is correct
+
+proc u(x: ptr T)
+x.u()          --> needs to become  x->u()
+(addr y).u()   --> needs to become  y.u()
+
+proc v(x: var T)
+--> first skip the implicit 'nkAddr' node
+x[].v()        --> (*x).v()  is correct, but might have been eliminated due
+                   to the nkAddr node! So for this case we need to generate '->'
+y.v()          --> y.v() is correct
+
+"""
+
+proc skipAddrDeref(node: PNode): PNode =
+  var n = node
+  var isAddr = false
+  case n.kind
+  of nkAddr, nkHiddenAddr:
+    n = n.sons[0]
+    isAddr = true
+  of nkDerefExpr, nkHiddenDeref:
+    n = n.sons[0]
+  else: return n
+  if n.kind == nkObjDownConv: n = n.sons[0]
+  if isAddr and n.kind in {nkDerefExpr, nkHiddenDeref}:
+    result = n.sons[0]
+  elif n.kind in {nkAddr, nkHiddenAddr}:
+    result = n.sons[0]
+  else:
+    result = node
+
+proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType): Rope =
+  # for better or worse c2nim translates the 'this' argument to a 'var T'.
+  # However manual wrappers may also use 'ptr T'. In any case we support both
+  # for convenience.
+  internalAssert i < sonsLen(typ)
+  assert(typ.n.sons[i].kind == nkSym)
+  # if the parameter is lying (tyVar) and thus we required an additional deref,
+  # skip the deref:
+  var ri = ri[i]
+  while ri.kind == nkObjDownConv: ri = ri[0]
+  let t = typ.sons[i].skipTypes({tyGenericInst})
+  if t.kind == tyVar:
+    let x = if ri.kind == nkHiddenAddr: ri[0] else: ri
+    if x.typ.kind == tyPtr:
+      result = genArgNoParam(p, x)
+      result.add("->")
+    elif x.kind in {nkHiddenDeref, nkDerefExpr} and x[0].typ.kind == tyPtr:
+      result = genArgNoParam(p, x[0])
+      result.add("->")
+    else:
+      result = genArgNoParam(p, x)
+      result.add(".")
+  elif t.kind == tyPtr:
+    if ri.kind in {nkAddr, nkHiddenAddr}:
+      result = genArgNoParam(p, ri[0])
+      result.add(".")
+    else:
+      result = genArgNoParam(p, ri)
+      result.add("->")
+  else:
+    ri = skipAddrDeref(ri)
+    if ri.kind in {nkAddr, nkHiddenAddr}: ri = ri[0]
+    result = genArgNoParam(p, ri) #, typ.n.sons[i].sym)
+    result.add(".")
+
+proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): Rope =
+  var i = 0
+  var j = 1
+  while i < pat.len:
+    case pat[i]
+    of '@':
+      if j < ri.len:
+        result.add genOtherArg(p, ri, j, typ)
+        for k in j+1 .. < ri.len:
+          result.add(~", ")
+          result.add genOtherArg(p, ri, k, typ)
+      inc i
+    of '#':
+      if pat[i+1] in {'+', '@'}:
+        let ri = ri[j]
+        if ri.kind in nkCallKinds:
+          let typ = skipTypes(ri.sons[0].typ, abstractInst)
+          if pat[i+1] == '+': result.add genArgNoParam(p, ri.sons[0])
+          result.add(~"(")
+          if 1 < ri.len:
+            result.add genOtherArg(p, ri, 1, typ)
+          for k in j+1 .. < ri.len:
+            result.add(~", ")
+            result.add genOtherArg(p, ri, k, typ)
+          result.add(~")")
+        else:
+          localError(ri.info, "call expression expected for C++ pattern")
+        inc i
+      elif pat[i+1] == '.':
+        result.add genThisArg(p, ri, j, typ)
+        inc i
+      elif pat[i+1] == '[':
+        var arg = ri.sons[j].skipAddrDeref
+        while arg.kind in {nkAddr, nkHiddenAddr, nkObjDownConv}: arg = arg[0]
+        result.add genArgNoParam(p, arg)
+        #result.add debugTree(arg, 0, 10)
+      else:
+        result.add genOtherArg(p, ri, j, typ)
+      inc j
+      inc i
+    of '\'':
+      var idx, stars: int
+      if scanCppGenericSlot(pat, i, idx, stars):
+        var t = resolveStarsInCppType(typ, idx, stars)
+        if t == nil: result.add(~"void")
+        else: result.add(getTypeDesc(p.module, t))
+    else:
+      let start = i
+      while i < pat.len:
+        if pat[i] notin {'@', '#', '\''}: inc(i)
+        else: break
+      if i - 1 >= start:
+        add(result, substr(pat, start, i - 1))
+
 proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
   var op, a: TLoc
   initLocExpr(p, ri.sons[0], op)
-  var pl: PRope = nil
   # getUniqueType() is too expensive here:
   var typ = skipTypes(ri.sons[0].typ, abstractInst)
   assert(typ.kind == tyProc)
   var length = sonsLen(ri)
   assert(sonsLen(typ) == sonsLen(typ.n))
-  
-  var param = typ.n.sons[1].sym
-  app(pl, genArg(p, ri.sons[1], param))
-  
-  if skipTypes(param.typ, {tyGenericInst}).kind == tyPtr: app(pl, ~"->")
-  else: app(pl, ~".")
-  app(pl, op.r)
-  var params: PRope
-  for i in countup(2, length - 1):
-    if params != nil: params.app(~", ")
-    assert(sonsLen(typ) == sonsLen(typ.n))
-    if i < sonsLen(typ):
-      assert(typ.n.sons[i].kind == nkSym)
-      app(params, genArg(p, ri.sons[i], typ.n.sons[i].sym))
+  # don't call '$' here for efficiency:
+  let pat = ri.sons[0].sym.loc.r.data
+  internalAssert pat != nil
+  if pat.contains({'#', '(', '@', '\''}):
+    var pl = genPatternCall(p, ri, pat, typ)
+    # simpler version of 'fixupCall' that works with the pl+params combination:
+    var typ = skipTypes(ri.sons[0].typ, abstractInst)
+    if typ.sons[0] != nil:
+      if p.module.compileToCpp and lfSingleUse in d.flags:
+        # do not generate spurious temporaries for C++! For C we're better off
+        # with them to prevent undefined behaviour and because the codegen
+        # is free to emit expressions multiple times!
+        d.k = locCall
+        d.r = pl
+        excl d.flags, lfSingleUse
+      else:
+        if d.k == locNone: getTemp(p, typ.sons[0], d)
+        assert(d.t != nil)        # generate an assignment to d:
+        var list: TLoc
+        initLoc(list, locCall, d.t, OnUnknown)
+        list.r = pl
+        genAssignment(p, d, list, {}) # no need for deep copying
     else:
-      app(params, genArgNoParam(p, ri.sons[i]))
-  fixupCall(p, le, ri, d, pl, params)
+      add(pl, ~";$n")
+      line(p, cpsStmts, pl)
+  else:
+    var pl: Rope = nil
+    #var param = typ.n.sons[1].sym
+    if 1 < ri.len:
+      add(pl, genThisArg(p, ri, 1, typ))
+    add(pl, op.r)
+    var params: Rope
+    for i in countup(2, length - 1):
+      if params != nil: params.add(~", ")
+      assert(sonsLen(typ) == sonsLen(typ.n))
+      add(params, genOtherArg(p, ri, i, typ))
+    fixupCall(p, le, ri, d, pl, params)
 
 proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
   # generates a crappy ObjC call
@@ -255,44 +454,56 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
   assert(typ.kind == tyProc)
   var length = sonsLen(ri)
   assert(sonsLen(typ) == sonsLen(typ.n))
-  
-  if length > 1:
-    app(pl, genArg(p, ri.sons[1], typ.n.sons[1].sym))
-    app(pl, ~" ")
-  app(pl, op.r)
-  if length > 2:
-    app(pl, ~": ")
-    app(pl, genArg(p, ri.sons[2], typ.n.sons[2].sym))
-  for i in countup(3, length-1):
+
+  # don't call '$' here for efficiency:
+  let pat = ri.sons[0].sym.loc.r.data
+  internalAssert pat != nil
+  var start = 3
+  if ' ' in pat:
+    start = 1
+    add(pl, op.r)
+    if length > 1:
+      add(pl, ~": ")
+      add(pl, genArg(p, ri.sons[1], typ.n.sons[1].sym, ri))
+      start = 2
+  else:
+    if length > 1:
+      add(pl, genArg(p, ri.sons[1], typ.n.sons[1].sym, ri))
+      add(pl, ~" ")
+    add(pl, op.r)
+    if length > 2:
+      add(pl, ~": ")
+      add(pl, genArg(p, ri.sons[2], typ.n.sons[2].sym, ri))
+  for i in countup(start, length-1):
     assert(sonsLen(typ) == sonsLen(typ.n))
     if i >= sonsLen(typ):
       internalError(ri.info, "varargs for objective C method?")
     assert(typ.n.sons[i].kind == nkSym)
     var param = typ.n.sons[i].sym
-    app(pl, ~" ")
-    app(pl, param.name.s)
-    app(pl, ~": ")
-    app(pl, genArg(p, ri.sons[i], param))
+    add(pl, ~" ")
+    add(pl, param.name.s)
+    add(pl, ~": ")
+    add(pl, genArg(p, ri.sons[i], param, ri))
   if typ.sons[0] != nil:
     if isInvalidReturnType(typ.sons[0]):
-      if sonsLen(ri) > 1: app(pl, ~" ")
+      if sonsLen(ri) > 1: add(pl, ~" ")
       # beware of 'result = p(result)'. We always allocate a temporary:
       if d.k in {locTemp, locNone}:
         # We already got a temp. Great, special case it:
         if d.k == locNone: getTemp(p, typ.sons[0], d, needsInit=true)
-        app(pl, ~"Result: ")
-        app(pl, addrLoc(d))
-        app(pl, ~"];$n")
+        add(pl, ~"Result: ")
+        add(pl, addrLoc(d))
+        add(pl, ~"];$n")
         line(p, cpsStmts, pl)
       else:
         var tmp: TLoc
         getTemp(p, typ.sons[0], tmp, needsInit=true)
-        app(pl, addrLoc(tmp))
-        app(pl, ~"];$n")
+        add(pl, addrLoc(tmp))
+        add(pl, ~"];$n")
         line(p, cpsStmts, pl)
         genAssignment(p, d, tmp, {}) # no need for deep copying
     else:
-      app(pl, ~"]")
+      add(pl, ~"]")
       if d.k == locNone: getTemp(p, typ.sons[0], d)
       assert(d.t != nil)        # generate an assignment to d:
       var list: TLoc
@@ -300,14 +511,13 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
       list.r = pl
       genAssignment(p, d, list, {}) # no need for deep copying
   else:
-    app(pl, ~"];$n")
+    add(pl, ~"];$n")
     line(p, cpsStmts, pl)
 
 proc genCall(p: BProc, e: PNode, d: var TLoc) =
   if e.sons[0].typ.callConv == ccClosure:
     genClosureCall(p, nil, e, d)
-  elif e.sons[0].kind == nkSym and sfInfixCall in e.sons[0].sym.flags and
-      e.len >= 2:
+  elif e.sons[0].kind == nkSym and sfInfixCall in e.sons[0].sym.flags:
     genInfixCall(p, nil, e, d)
   elif e.sons[0].kind == nkSym and sfNamedParamCall in e.sons[0].sym.flags:
     genNamedParamCall(p, e, d)
@@ -320,8 +530,7 @@ proc genCall(p: BProc, e: PNode, d: var TLoc) =
 proc genAsgnCall(p: BProc, le, ri: PNode, d: var TLoc) =
   if ri.sons[0].typ.callConv == ccClosure:
     genClosureCall(p, le, ri, d)
-  elif ri.sons[0].kind == nkSym and sfInfixCall in ri.sons[0].sym.flags and
-      ri.len >= 2:
+  elif ri.sons[0].kind == nkSym and sfInfixCall in ri.sons[0].sym.flags:
     genInfixCall(p, le, ri, d)
   elif ri.sons[0].kind == nkSym and sfNamedParamCall in ri.sons[0].sym.flags:
     genNamedParamCall(p, ri, d)