summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorringabout <43030857+ringabout@users.noreply.github.com>2024-04-03 22:59:35 +0800
committerGitHub <noreply@github.com>2024-04-03 16:59:35 +0200
commit9e1b170a09d2228214807a8c01fe37b874f77d58 (patch)
tree72acf23b56a05eabfd21e52f740e2b4505eb3f8b
parentdee55f587f4e3cfc8ffe28e4a41eba9c8ed7f2f8 (diff)
downloadNim-9e1b170a09d2228214807a8c01fe37b874f77d58.tar.gz
fixes #16771; lower `swap` for JS backend (#23473)
fixes #16771

follow up https://github.com/nim-lang/Nim/pull/16536

Ideally it should be handled in the IR part in the future

I have also checked the double evaluation of `swap` in the JS runtime
https://github.com/nim-lang/Nim/issues/16779, that might be solved by a
copy flag or something. Well, it should be best solved in the IR so that
it doesn't bother backends anymore.
-rw-r--r--compiler/jsgen.nim17
-rw-r--r--lib/pure/collections/lists.nim4
-rw-r--r--tests/stdlib/tmisc_issues.nim19
3 files changed, 24 insertions, 16 deletions
diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim
index 25871b8d3..2e03bae80 100644
--- a/compiler/jsgen.nim
+++ b/compiler/jsgen.nim
@@ -1322,19 +1322,10 @@ proc genFastAsgn(p: PProc, n: PNode) =
   genAsgnAux(p, n[0], n[1], noCopyNeeded=noCopy)
 
 proc genSwap(p: PProc, n: PNode) =
-  var a, b: TCompRes = default(TCompRes)
-  gen(p, n[1], a)
-  gen(p, n[2], b)
-  var tmp = p.getTemp(false)
-  if mapType(p, skipTypes(n[1].typ, abstractVar)) == etyBaseIndex:
-    let tmp2 = p.getTemp(false)
-    if a.typ != etyBaseIndex or b.typ != etyBaseIndex:
-      internalError(p.config, n.info, "genSwap")
-    lineF(p, "var $1 = $2; $2 = $3; $3 = $1;$n",
-             [tmp, a.address, b.address])
-    tmp = tmp2
-  lineF(p, "var $1 = $2; $2 = $3; $3 = $1;",
-           [tmp, a.res, b.res])
+  let stmtList = lowerSwap(p.module.graph, n, p.module.idgen, if p.prc != nil: p.prc else: p.module.module)
+  assert stmtList.kind == nkStmtList
+  for i in 0..<stmtList.len:
+    genStmt(p, stmtList[i])
 
 proc getFieldPosition(p: PProc; f: PNode): int =
   case f.kind
diff --git a/lib/pure/collections/lists.nim b/lib/pure/collections/lists.nim
index 9b89fe9f8..6b88747ef 100644
--- a/lib/pure/collections/lists.nim
+++ b/lib/pure/collections/lists.nim
@@ -384,9 +384,7 @@ proc prependMoved*[T: SomeLinkedList](a, b: var T) {.since: (1, 5, 1).} =
     assert s == [0, 1, 0, 1, 0, 1]
 
   b.addMoved(a)
-  when defined(js): # XXX: swap broken in js; bug #16771
-    (b, a) = (a, b)
-  else: swap a, b
+  swap a, b
 
 proc add*[T](L: var SinglyLinkedList[T], n: SinglyLinkedNode[T]) {.inline.} =
   ## Appends (adds to the end) a node `n` to `L`. Efficiency: O(1).
diff --git a/tests/stdlib/tmisc_issues.nim b/tests/stdlib/tmisc_issues.nim
index 33eb9655d..86dcf4162 100644
--- a/tests/stdlib/tmisc_issues.nim
+++ b/tests/stdlib/tmisc_issues.nim
@@ -18,3 +18,22 @@ type
 
 var x: Object = Object(data: Test(Data(id: 12)))
 doAssert Data(x.data).id == 12
+
+block: # bug #16771
+  type A = object
+    n: int
+
+  proc foo(a, b: var A) =
+    swap a, b
+
+  var a, b: A
+  a.n = 42
+  b.n = 1
+  doAssert a.n == 42
+  doAssert b.n == 1
+  a.swap b
+  doAssert a.n == 1
+  doAssert b.n == 42
+  a.foo b
+  doAssert a.n == 42
+  doAssert b.n == 1