summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/sem.nim20
-rw-r--r--compiler/semexprs.nim5
-rw-r--r--compiler/vmdef.nim3
-rw-r--r--compiler/vmgen.nim13
4 files changed, 33 insertions, 8 deletions
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 91adcac5e..9ac7ad139 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -67,12 +67,25 @@ proc fitNode(c: PContext, formal: PType, arg: PNode): PNode =
       # error correction:
       result = copyTree(arg)
       result.typ = formal
+    else:
+      let x = result.skipConv
+      if x.kind == nkPar and formal.kind != tyExpr:
+        changeType(x, formal, check=true)
 
 proc inferWithMetatype(c: PContext, formal: PType,
                        arg: PNode, coerceDistincts = false): PNode
 
 var commonTypeBegin = PType(kind: tyExpr)
 
+proc isEmptyContainer(t: PType): bool =
+  case t.kind
+  of tyExpr, tyNil: result = true
+  of tyArray, tyArrayConstr: result = t.sons[1].kind == tyEmpty
+  of tySet, tySequence, tyOpenArray, tyVarargs:
+    result = t.sons[0].kind == tyEmpty
+  of tyGenericInst: result = isEmptyContainer(t.lastSon)
+  else: result = false
+
 proc commonType*(x, y: PType): PType =
   # new type relation that is used for array constructors,
   # if expressions, etc.:
@@ -96,6 +109,13 @@ proc commonType*(x, y: PType): PType =
     # check for seq[empty] vs. seq[int]
     let idx = ord(b.kind in {tyArray, tyArrayConstr})
     if a.sons[idx].kind == tyEmpty: return y
+  elif a.kind == tyTuple and b.kind == tyTuple and a.len == b.len:
+    var nt: PType
+    for i in 0.. <a.len:
+      if isEmptyContainer(a.sons[i]) and not isEmptyContainer(b.sons[i]):
+        if nt.isNil: nt = copyType(a, a.owner, false)
+        nt.sons[i] = b.sons[i]
+    if not nt.isNil: result = nt
     #elif b.sons[idx].kind == tyEmpty: return x
   elif a.kind == tyRange and b.kind == tyRange:
     # consider:  (range[0..3], range[0..4]) here. We should make that
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 25113aa5a..b11e8cb61 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -429,7 +429,8 @@ proc changeType(n: PNode, newType: PType, check: bool) =
     for i in countup(0, sonsLen(n) - 1):
       changeType(n.sons[i], elemType(newType), check)
   of nkPar:
-    if newType.kind != tyTuple:
+    let tup = newType.skipTypes({tyGenericInst})
+    if tup.kind != tyTuple:
       internalError(n.info, "changeType: no tuple type for constructor")
     else:
       for i in countup(0, sonsLen(n) - 1):
@@ -437,7 +438,7 @@ proc changeType(n: PNode, newType: PType, check: bool) =
         if m.kind == nkExprColonExpr:
           m = m.sons[1]
           n.sons[i] = m
-        changeType(m, newType.sons[i], check)
+        changeType(m, tup.sons[i], check)
   of nkCharLit..nkUInt64Lit:
     if check:
       let value = n.intVal
diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim
index c06606318..3d49cb130 100644
--- a/compiler/vmdef.nim
+++ b/compiler/vmdef.nim
@@ -164,7 +164,8 @@ type
     slotTempInt,      # some temporary int
     slotTempFloat,    # some temporary float
     slotTempStr,      # some temporary string
-    slotTempComplex   # some complex temporary (s.node field is used)
+    slotTempComplex,  # some complex temporary (s.node field is used)
+    slotTempPerm      # slot is temporary but permanent (hack)
 
   PProc* = ref object
     blocks*: seq[TBlock]    # blocks; temp data structure
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index c4101874c..9a3fc260a 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -16,7 +16,7 @@
 #   types that use the 'node' field; the reason is that slots are
 #   re-used in a register based VM. Example:
 # 
-# .. code-block:: nimrod
+# .. code-block:: nim
 #   let s = a & b  # no matter what, create fresh node
 #   s = a & b  # no matter what, keep the node
 #
@@ -28,7 +28,7 @@
 # this copy depends on the involved types.
 
 import
-  unsigned, strutils, ast, astalgo, types, msgs, renderer, vmdef, 
+  unsigned, strutils, ast, astalgo, types, msgs, renderer, vmdef,
   trees, intsets, rodread, magicsys, options, lowerings
 
 from os import splitFile
@@ -58,6 +58,7 @@ proc codeListing(c: PCtx, result: var string, start=0; last = -1) =
     if i in jumpTargets: result.addf("L$1:\n", i)
     let x = c.code[i]
 
+    result.add($i)
     let opc = opcode(x)
     if opc in {opcConv, opcCast}:
       let y = c.code[i+1]
@@ -188,7 +189,7 @@ proc getTemp(c: PCtx; typ: PType): TRegister =
 
 proc freeTemp(c: PCtx; r: TRegister) =
   let c = c.prc
-  if c.slots[r].kind >= slotSomeTemp: c.slots[r].inUse = false
+  if c.slots[r].kind in {slotSomeTemp..slotTempComplex}: c.slots[r].inUse = false
 
 proc getTempRange(c: PCtx; n: int; kind: TSlotKind): TRegister =
   # if register pressure is high, we re-use more aggressively:
@@ -1074,8 +1075,10 @@ proc genAddrDeref(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
         c.gABC(n, opcNodeToReg, dest, dest)
     elif c.prc.slots[tmp].kind >= slotTempUnknown:
       gABC(c, n, opcAddrNode, dest, tmp)
-      # XXX this can still be wrong sometimes; hopefully it's only generated
-      # in call contexts, where it is safe
+      # hack ahead; in order to fix bug #1781 we mark the temporary as
+      # permanent, so that it's not used for anything else:
+      c.prc.slots[tmp].kind = slotTempPerm
+      # XXX this is still a hack
       #message(n.info, warnUser, "suspicious opcode used")
     else:
       gABC(c, n, opcAddrReg, dest, tmp)