diff options
author | Araq <rumpf_a@web.de> | 2015-08-21 12:31:55 +0200 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2015-08-21 21:34:14 +0200 |
commit | bfd2fd67f948f6a5ee8815ee866d55d147f53c73 (patch) | |
tree | d03fdbac18566c26c4a9dffd74c270949889a8c9 | |
parent | 2733c508ef2681fe8eddfe9c73419ef3226e479d (diff) | |
download | Nim-bfd2fd67f948f6a5ee8815ee866d55d147f53c73.tar.gz |
tuple unpacking works in a non-var/let context
-rw-r--r-- | compiler/lowerings.nim | 26 | ||||
-rw-r--r-- | compiler/semexprs.nim | 8 | ||||
-rw-r--r-- | tests/tuples/tunpack_asgn.nim | 32 | ||||
-rw-r--r-- | todo.txt | 2 | ||||
-rw-r--r-- | web/news.txt | 3 |
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 |