summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorHeiko Nickerl <dev@hnicke.de>2021-06-20 17:56:33 +0200
committerGitHub <noreply@github.com>2021-06-20 08:56:33 -0700
commit92cb765714325703d1a8e1b0409bfcd1b17af103 (patch)
tree42d0acf856e744f6105fb16c9b57bbbd0d065b6e
parenteb0b323f452f5f06d74a4f747c50ae5115e44eae (diff)
downloadNim-92cb765714325703d1a8e1b0409bfcd1b17af103.tar.gz
Raise IndexDefect when deleting element at out of bounds index (#17821)
Co-authored-by: Timothee Cour <timothee.cour2@gmail.com>
Co-authored-by: Heiko Nickerl <mail@hnicke.de>
Co-authored-by: Heiko Nickerl <heiko.nickerl@flipapp.de>
-rw-r--r--changelog.md3
-rw-r--r--lib/system.nim58
-rw-r--r--tests/gc/gcleak3.nim8
-rw-r--r--tests/stdlib/tsystem.nim32
-rw-r--r--tests/system/tsystem_misc.nim5
5 files changed, 70 insertions, 36 deletions
diff --git a/changelog.md b/changelog.md
index 80e38f420..5af195e59 100644
--- a/changelog.md
+++ b/changelog.md
@@ -28,6 +28,9 @@
 - `math.round` now is rounded "away from zero" in JS backend which is consistent
   with other backends. See #9125. Use `-d:nimLegacyJsRound` for previous behavior.
 
+- Instead of deleting the element at the last index,
+  `system.delete()` now raises `IndexDefect` when given index is out of bounds.
+
 - Changed the behavior of `uri.decodeQuery` when there are unencoded `=`
   characters in the decoded values. Prior versions would raise an error. This is
   no longer the case to comply with the HTML spec and other languages
diff --git a/lib/system.nim b/lib/system.nim
index cae0ec3e2..a4608997a 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -1325,30 +1325,6 @@ proc del*[T](x: var seq[T], i: Natural) {.noSideEffect.} =
   movingCopy(x[i], x[xl])
   setLen(x, xl)
 
-proc delete*[T](x: var seq[T], i: Natural) {.noSideEffect.} =
-  ## Deletes the item at index `i` by moving all `x[i+1..]` items by one position.
-  ##
-  ## This is an `O(n)` operation.
-  ##
-  ## See also:
-  ## * `del <#del,seq[T],Natural>`_ for O(1) operation
-  ##
-  ## .. code-block:: Nim
-  ##  var i = @[1, 2, 3, 4, 5]
-  ##  i.delete(2) # => @[1, 2, 4, 5]
-  template defaultImpl =
-    let xl = x.len
-    for j in i.int..xl-2: movingCopy(x[j], x[j+1])
-    setLen(x, xl-1)
-
-  when nimvm:
-    defaultImpl()
-  else:
-    when defined(js):
-      {.emit: "`x`.splice(`i`, 1);".}
-    else:
-      defaultImpl()
-
 proc insert*[T](x: var seq[T], item: sink T, i = 0.Natural) {.noSideEffect.} =
   ## Inserts `item` into `x` at position `i`.
   ##
@@ -2154,6 +2130,40 @@ const
 import system/dollars
 export dollars
 
+proc delete*[T](x: var seq[T], i: Natural) {.noSideEffect.} =
+  ## Deletes the item at index `i` by moving all `x[i+1..^1]` items by one position.
+  ##
+  ## This is an `O(n)` operation.
+  ##
+  ## See also:
+  ## * `del <#del,seq[T],Natural>`_ for O(1) operation
+  ##
+  runnableExamples:
+    var s = @[1, 2, 3, 4, 5]
+    s.delete(2)
+    doAssert s == @[1, 2, 4, 5]
+
+    doAssertRaises(IndexDefect):
+      s.delete(4)
+
+  if i > high(x):
+    # xxx this should call `raiseIndexError2(i, high(x))` after some refactoring
+    raise (ref IndexDefect)(msg: "index out of bounds: '" & $i & "' < '" & $x.len & "' failed")
+
+  template defaultImpl =
+    let xl = x.len
+    for j in i.int..xl-2: movingCopy(x[j], x[j+1])
+    setLen(x, xl-1)
+
+  when nimvm:
+    defaultImpl()
+  else:
+    when defined(js):
+      {.emit: "`x`.splice(`i`, 1);".}
+    else:
+      defaultImpl()
+
+
 const
   NimVersion*: string = $NimMajor & "." & $NimMinor & "." & $NimPatch
     ## is the version of Nim as a string.
diff --git a/tests/gc/gcleak3.nim b/tests/gc/gcleak3.nim
index 588e238e9..5e146d69f 100644
--- a/tests/gc/gcleak3.nim
+++ b/tests/gc/gcleak3.nim
@@ -17,14 +17,10 @@ for i in 0..1024:
   s.add(obj)
 
 proc limit*[t](a: var seq[t]) =
-  var loop = s.len() - 512
-  for i in 0..loop:
-    #echo i
-    #GC_fullCollect()
+  while s.len > 0:
     if getOccupiedMem() > 3000_000: quit("still a leak!")
-    s.delete(i)
+    s.delete(0)
 
 s.limit()
-
 echo "no leak: ", getOccupiedMem()
 
diff --git a/tests/stdlib/tsystem.nim b/tests/stdlib/tsystem.nim
index f8b172b44..b48034043 100644
--- a/tests/stdlib/tsystem.nim
+++ b/tests/stdlib/tsystem.nim
@@ -2,9 +2,10 @@ discard """
   targets: "c cpp js"
 """
 
+import stdtest/testutils
+
 # TODO: in future work move existing `system` tests here, where they belong
 
-import stdtest/testutils
 
 template main =
   block: # closure
@@ -42,5 +43,34 @@ template main =
         # doAssert rawEnv(inner3) != rawEnv(inner1) # because `a` vs `b` # this doesn't hold
     outer()
 
+  block: # system.delete
+    block:
+      var s = @[1]
+      s.delete(0)
+      doAssert s == @[]
+
+    block:
+      var s = @["foo", "bar"]
+      s.delete(1)
+      doAssert s == @["foo"]
+  
+    block:
+      var s: seq[string]
+      doAssertRaises(IndexDefect):
+        s.delete(0)
+
+    block:
+      doAssert not compiles(@["foo"].delete(-1))
+
+    block: # bug #6710
+      var s = @["foo"]
+      s.delete(0)
+      doAssert s == @[]
+  
+    block: # bug #16544: deleting out of bounds index should raise
+      var s = @["foo"]
+      doAssertRaises(IndexDefect):
+        s.delete(1)
+
 static: main()
 main()
diff --git a/tests/system/tsystem_misc.nim b/tests/system/tsystem_misc.nim
index cb879d3b3..13b8c18a9 100644
--- a/tests/system/tsystem_misc.nim
+++ b/tests/system/tsystem_misc.nim
@@ -59,11 +59,6 @@ doAssert high(float) > low(float)
 doAssert high(float32) > low(float32)
 doAssert high(float64) > low(float64)
 
-# bug #6710
-var s = @[1]
-s.delete(0)
-
-
 proc foo(a: openArray[int]) =
   for x in a: echo x