summary refs log tree commit diff stats
path: root/lib
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2021-09-02 12:10:14 +0200
committerGitHub <noreply@github.com>2021-09-02 12:10:14 +0200
commite0ef859130f429df1891e31a85955daa753346b4 (patch)
tree49c680c4e93a321a319e38168dd14483c2a9b71e /lib
parent72fa5833adac590e3c78e2b774cd33f28827594b (diff)
downloadNim-e0ef859130f429df1891e31a85955daa753346b4.tar.gz
strict effects (#18777)
* fixes #17369
* megatest is green for --cpu:arm64
* docgen output includes more tags/raises
* implemented 'effectsOf' 
* algorithm.nim: uses new effectsOf annotation
* closes #18376
* closes #17475
* closes #13905
* allow effectsOf: [a, b]
* added a test case
* parameters that are not ours cannot be declared as .effectsOf
* documentation
* manual: added the 'sort' example
* bootstrap with the new better options
Diffstat (limited to 'lib')
-rw-r--r--lib/pure/algorithm.nim23
-rw-r--r--lib/pure/times.nim2
-rw-r--r--lib/std/private/globs.nim7
-rw-r--r--lib/system/io.nim2
-rw-r--r--lib/system/nimscript.nim6
5 files changed, 25 insertions, 15 deletions
diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim
index c96f599e8..1ddcc9843 100644
--- a/lib/pure/algorithm.nim
+++ b/lib/pure/algorithm.nim
@@ -147,8 +147,13 @@ proc reversed*[T](a: openArray[T], first: Natural, last: int): seq[T]
   {.inline, deprecated: "use: `reversed(toOpenArray(a, first, last))`".} =
   reversed(toOpenArray(a, first, last))
 
+when defined(nimHasEffectsOf):
+  {.experimental: "strictEffects".}
+else:
+  {.pragma: effectsOf.}
+
 proc binarySearch*[T, K](a: openArray[T], key: K,
-                         cmp: proc (x: T, y: K): int {.closure.}): int =
+                         cmp: proc (x: T, y: K): int {.closure.}): int {.effectsOf: cmp.} =
   ## Binary search for `key` in `a`. Return the index of `key` or -1 if not found.
   ## Assumes that `a` is sorted according to `cmp`.
   ##
@@ -210,7 +215,7 @@ const
   onlySafeCode = true
 
 proc lowerBound*[T, K](a: openArray[T], key: K,
-                       cmp: proc(x: T, k: K): int {.closure.}): int =
+                       cmp: proc(x: T, k: K): int {.closure.}): int {.effectsOf: cmp.} =
   ## Returns the index of the first element in `a` that is not less than
   ## (i.e. greater or equal to) `key`, or last if no such element is found.
   ## In other words if you have a sorted sequence and you call
@@ -260,7 +265,7 @@ proc lowerBound*[T](a: openArray[T], key: T): int = lowerBound(a, key, cmp[T])
   ## * `upperBound proc<#upperBound,openArray[T],T>`_
 
 proc upperBound*[T, K](a: openArray[T], key: K,
-                       cmp: proc(x: T, k: K): int {.closure.}): int =
+                       cmp: proc(x: T, k: K): int {.closure.}): int {.effectsOf: cmp.} =
   ## Returns the index of the first element in `a` that is greater than
   ## `key`, or last if no such element is found.
   ## In other words if you have a sorted sequence and you call
@@ -318,7 +323,7 @@ template `<-`(a, b) =
     copyMem(addr(a), addr(b), sizeof(T))
 
 proc mergeAlt[T](a, b: var openArray[T], lo, m, hi: int,
-              cmp: proc (x, y: T): int {.closure.}, order: SortOrder) =
+              cmp: proc (x, y: T): int {.closure.}, order: SortOrder) {.effectsOf: cmp.} =
   # Optimization: If max(left) <= min(right) there is nothing to do!
   # 1 2 3 4 ## 5 6 7 8
   # -> O(n) for sorted arrays.
@@ -358,7 +363,7 @@ proc mergeAlt[T](a, b: var openArray[T], lo, m, hi: int,
 
 func sort*[T](a: var openArray[T],
               cmp: proc (x, y: T): int {.closure.},
-              order = SortOrder.Ascending) =
+              order = SortOrder.Ascending) {.effectsOf: cmp.} =
   ## Default Nim sort (an implementation of merge sort). The sorting
   ## is guaranteed to be stable (that is, equal elements stay in the same order)
   ## and the worst case is guaranteed to be O(n log n).
@@ -420,7 +425,7 @@ proc sort*[T](a: var openArray[T], order = SortOrder.Ascending) = sort[T](a,
   ## * `sortedByIt template<#sortedByIt.t,untyped,untyped>`_
 
 proc sorted*[T](a: openArray[T], cmp: proc(x, y: T): int {.closure.},
-                order = SortOrder.Ascending): seq[T] =
+                order = SortOrder.Ascending): seq[T] {.effectsOf: cmp.} =
   ## Returns `a` sorted by `cmp` in the specified `order`.
   ##
   ## **See also:**
@@ -497,7 +502,7 @@ template sortedByIt*(seq1, op: untyped): untyped =
 
 func isSorted*[T](a: openArray[T],
                  cmp: proc(x, y: T): int {.closure.},
-                 order = SortOrder.Ascending): bool =
+                 order = SortOrder.Ascending): bool {.effectsOf: cmp.} =
   ## Checks to see whether `a` is already sorted in `order`
   ## using `cmp` for the comparison. The parameters are identical
   ## to `sort`. Requires O(n) time.
@@ -545,7 +550,7 @@ proc isSorted*[T](a: openArray[T], order = SortOrder.Ascending): bool =
 proc merge*[T](
   result: var seq[T],
   x, y: openArray[T], cmp: proc(x, y: T): int {.closure.}
-) {.since: (1, 5, 1).} =
+) {.since: (1, 5, 1), effectsOf: cmp.} =
   ## Merges two sorted `openArray`. `x` and `y` are assumed to be sorted.
   ## If you do not wish to provide your own `cmp`,
   ## you may use `system.cmp` or instead call the overloaded
@@ -638,7 +643,7 @@ proc product*[T](x: openArray[seq[T]]): seq[seq[T]] =
   ## Produces the Cartesian product of the array.
   ## Every element of the result is a combination of one element from each seq in `x`,
   ## with the ith element coming from `x[i]`.
-  ## 
+  ##
   ## .. warning:: complexity may explode.
   runnableExamples:
     assert product(@[@[1], @[2]]) == @[@[1, 2]]
diff --git a/lib/pure/times.nim b/lib/pure/times.nim
index b2a22250d..b41bb28b5 100644
--- a/lib/pure/times.nim
+++ b/lib/pure/times.nim
@@ -1333,7 +1333,7 @@ proc now*(): DateTime {.tags: [TimeEffect], benign.} =
   ##    `cpuTime` instead, depending on the use case.
   getTime().local
 
-proc dateTime*(year: int, month: Month, monthday: MonthdayRange, 
+proc dateTime*(year: int, month: Month, monthday: MonthdayRange,
                hour: HourRange = 0, minute: MinuteRange = 0, second: SecondRange = 0,
                nanosecond: NanosecondRange = 0,
                zone: Timezone = local()): DateTime =
diff --git a/lib/std/private/globs.nim b/lib/std/private/globs.nim
index b3726c9c3..190316f93 100644
--- a/lib/std/private/globs.nim
+++ b/lib/std/private/globs.nim
@@ -8,13 +8,18 @@ import os
 when defined(windows):
   from strutils import replace
 
+when defined(nimHasEffectsOf):
+  {.experimental: "strictEffects".}
+else:
+  {.pragma: effectsOf.}
+
 type
   PathEntry* = object
     kind*: PathComponent
     path*: string
 
 iterator walkDirRecFilter*(dir: string, follow: proc(entry: PathEntry): bool = nil,
-    relative = false, checkDir = true): PathEntry {.tags: [ReadDirEffect].} =
+    relative = false, checkDir = true): PathEntry {.tags: [ReadDirEffect], effectsOf: follow.} =
   ## Improved `os.walkDirRec`.
   #[
   note: a yieldFilter isn't needed because caller can filter at call site, without
diff --git a/lib/system/io.nim b/lib/system/io.nim
index d8b2ac741..59f070f73 100644
--- a/lib/system/io.nim
+++ b/lib/system/io.nim
@@ -78,7 +78,7 @@ proc c_fputs(c: cstring, f: File): cint {.
 proc c_fgets(c: cstring, n: cint, f: File): cstring {.
   importc: "fgets", header: "<stdio.h>", tags: [ReadIOEffect].}
 proc c_fgetc(stream: File): cint {.
-  importc: "fgetc", header: "<stdio.h>", tags: [ReadIOEffect].}
+  importc: "fgetc", header: "<stdio.h>", tags: [].}
 proc c_ungetc(c: cint, f: File): cint {.
   importc: "ungetc", header: "<stdio.h>", tags: [].}
 proc c_putc(c: cint, stream: File): cint {.
diff --git a/lib/system/nimscript.nim b/lib/system/nimscript.nim
index 9ece10e3e..b4554d778 100644
--- a/lib/system/nimscript.nim
+++ b/lib/system/nimscript.nim
@@ -261,7 +261,7 @@ proc cpDir*(`from`, to: string) {.raises: [OSError].} =
     checkOsError()
 
 proc exec*(command: string) {.
-  raises: [OSError], tags: [ExecIOEffect].} =
+  raises: [OSError], tags: [ExecIOEffect, WriteIOEffect].} =
   ## Executes an external process. If the external process terminates with
   ## a non-zero exit code, an OSError exception is raised.
   ##
@@ -274,7 +274,7 @@ proc exec*(command: string) {.
     checkOsError()
 
 proc exec*(command: string, input: string, cache = "") {.
-  raises: [OSError], tags: [ExecIOEffect].} =
+  raises: [OSError], tags: [ExecIOEffect, WriteIOEffect].} =
   ## Executes an external process. If the external process terminates with
   ## a non-zero exit code, an OSError exception is raised.
   log "exec: " & command:
@@ -284,7 +284,7 @@ proc exec*(command: string, input: string, cache = "") {.
     echo output
 
 proc selfExec*(command: string) {.
-  raises: [OSError], tags: [ExecIOEffect].} =
+  raises: [OSError], tags: [ExecIOEffect, WriteIOEffect].} =
   ## Executes an external command with the current nim/nimble executable.
   ## `Command` must not contain the "nim " part.
   let c = selfExe() & " " & command