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
This commit is contained in:
parent
72fa5833ad
commit
e0ef859130
35 changed files with 482 additions and 203 deletions
|
|
@ -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]]
|
||||
|
|
|
|||
|
|
@ -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 =
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue