summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2015-08-21 12:31:55 +0200
committerAraq <rumpf_a@web.de>2015-08-21 21:34:14 +0200
commitbfd2fd67f948f6a5ee8815ee866d55d147f53c73 (patch)
treed03fdbac18566c26c4a9dffd74c270949889a8c9
parent2733c508ef2681fe8eddfe9c73419ef3226e479d (diff)
downloadNim-bfd2fd67f948f6a5ee8815ee866d55d147f53c73.tar.gz
tuple unpacking works in a non-var/let context
-rw-r--r--compiler/lowerings.nim26
-rw-r--r--compiler/semexprs.nim8
-rw-r--r--tests/tuples/tunpack_asgn.nim32
-rw-r--r--todo.txt2
-rw-r--r--web/news.txt3
5 files changed, 69 insertions, 2 deletions
diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim
index 647ea59d6..20800b809 100644
--- a/compiler/lowerings.nim
+++ b/compiler/lowerings.nim
@@ -63,6 +63,32 @@ proc lowerTupleUnpacking*(n: PNode; owner: PSym): PNode =
     if n.sons[i].kind == nkSym: v.addVar(n.sons[i])
     result.add newAsgnStmt(n.sons[i], newTupleAccess(tempAsNode, i))
 
+proc newTupleAccessRaw*(tup: PNode, i: int): PNode =
+  result = newNodeI(nkBracketExpr, tup.info)
+  addSon(result, copyTree(tup))
+  var lit = newNodeI(nkIntLit, tup.info)
+  lit.intVal = i
+  addSon(result, lit)
+
+proc lowerTupleUnpackingForAsgn*(n: PNode; owner: PSym): PNode =
+  let value = n.lastSon
+  result = newNodeI(nkStmtList, n.info)
+
+  var temp = newSym(skTemp, getIdent(genPrefix), owner, value.info)
+  var v = newNodeI(nkLetSection, value.info)
+  let tempAsNode = newIdentNode(getIdent(genPrefix & $temp.id), value.info)
+
+  var vpart = newNodeI(nkIdentDefs, tempAsNode.info, 3)
+  vpart.sons[0] = tempAsNode
+  vpart.sons[1] = ast.emptyNode
+  vpart.sons[2] = value
+  addSon(v, vpart)
+  result.add(v)
+
+  let lhs = n.sons[0]
+  for i in 0 .. lhs.len-1:
+    result.add newAsgnStmt(lhs.sons[i], newTupleAccessRaw(tempAsNode, i))
+
 proc lowerSwap*(n: PNode; owner: PSym): PNode =
   result = newNodeI(nkStmtList, n.info)
   # note: cannot use 'skTemp' here cause we really need the copy for the VM :-(
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index bb3ec9df0..d6f6e3a2c 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -1282,6 +1282,14 @@ proc semAsgn(c: PContext, n: PNode): PNode =
     result = buildOverloadedSubscripts(n.sons[0], getIdent"{}=")
     add(result, n[1])
     return semExprNoType(c, result)
+  of nkPar:
+    if a.len >= 2:
+      # unfortunately we need to rewrite ``(x, y) = foo()`` already here so
+      # that overloading of the assignment operator still works. Usually we
+      # prefer to do these rewritings in transf.nim:
+      return semStmt(c, lowerTupleUnpackingForAsgn(n, c.p.owner))
+    else:
+      a = semExprWithType(c, a, {efLValue})
   else:
     a = semExprWithType(c, a, {efLValue})
   n.sons[0] = a
diff --git a/tests/tuples/tunpack_asgn.nim b/tests/tuples/tunpack_asgn.nim
new file mode 100644
index 000000000..a48fcff5d
--- /dev/null
+++ b/tests/tuples/tunpack_asgn.nim
@@ -0,0 +1,32 @@
+discard """
+  output: '''2 4
+4
+2 0'''
+"""
+
+proc foobar(): (int, int) = (2, 4)
+
+# test within a proc:
+proc pp(x: var int) =
+  var y: int
+  (y, x) = foobar()
+
+template pt(x) =
+  var y: int
+  (x, y) = foobar()
+
+# test within a generic:
+proc pg[T](x, y: var T) =
+  pt(x)
+
+# test as a top level statement:
+var x, y, a, b: int
+(x, y) = fooBar()
+
+echo x, " ", y
+
+pp(a)
+echo a
+
+pg(a, b)
+echo a, " ", b
diff --git a/todo.txt b/todo.txt
index 37e82e230..8962e3ca0 100644
--- a/todo.txt
+++ b/todo.txt
@@ -1,8 +1,6 @@
 version 0.11.4
 ==============
 
-- make tuple unpacking work in a non-var/let context
-
 - document special cased varargs[untyped] and varargs[typed]
 
 - The remaining bugs of the lambda lifting pass that is responsible to enable
diff --git a/web/news.txt b/web/news.txt
index fce77a0bf..46867ac4c 100644
--- a/web/news.txt
+++ b/web/news.txt
@@ -72,6 +72,9 @@ News
   - Added ``macros.getImpl`` that can be used to access the implementation of
     a routine or a constant. This allows for example for user-defined inlining
     of function calls.
+  - Tuple unpacking finally works in a non-var/let context: ``(x, y) == f()``
+    is allowed. Note that this doesn't declare ``x`` and ``y`` variables, for
+    this ``let (x, y) == f()`` still needs to be used.
 
 
   Bugfixes