diff options
author | Timothee Cour <timothee.cour2@gmail.com> | 2021-01-22 11:04:48 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-01-22 20:04:48 +0100 |
commit | 8f62cd512c0c5ae9a27087ccf8b4f666611709e6 (patch) | |
tree | 0e2eb7135212d1ff130a00d29016381ec0057d60 | |
parent | aca97250eae891c87e0c98f02bd7db9687bab5b0 (diff) | |
download | Nim-8f62cd512c0c5ae9a27087ccf8b4f666611709e6.tar.gz |
fix manual to reflect reality for .nosideeffect (#16781)
-rw-r--r-- | doc/manual.rst | 31 | ||||
-rw-r--r-- | tests/effects/tnosideeffect.nim | 24 |
2 files changed, 49 insertions, 6 deletions
diff --git a/doc/manual.rst b/doc/manual.rst index 90d2579b5..df591701c 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -6141,13 +6141,13 @@ This pragma can also take in an optional warning string to relay to developers. noSideEffect pragma ------------------- -The ``noSideEffect`` pragma is used to mark a proc/iterator to have no side -effects. This means that the proc/iterator only changes locations that are +The ``noSideEffect`` pragma is used to mark a proc/iterator that can have only +side effects through parameters. This means that the proc/iterator only changes locations that are reachable from its parameters and the return value only depends on the -arguments. If none of its parameters have the type ``var T`` or ``ref T`` -or ``ptr T`` this means no locations are modified. It is a static error to -mark a proc/iterator to have no side effect if the compiler cannot verify -this. +parameters. If none of its parameters have the type `var`, `ref`, `ptr`, `cstring`, or `proc`, +then no locations are modified. + +It is a static error to mark a proc/iterator to have no side effect if the compiler cannot verify this. As a special semantic rule, the built-in `debugEcho <system.html#debugEcho,varargs[typed,]>`_ pretends to be free of side effects, @@ -6168,6 +6168,25 @@ To override the compiler's side effect analysis a ``{.noSideEffect.}`` {.cast(noSideEffect).}: echo "test" +When a `noSideEffect` proc has proc params `bar`, whether it can be used inside a `noSideEffect` context +depends on what the compiler knows about `bar`: + +.. code-block:: nim + :test: "nim c $1" + + func foo(bar: proc(): int): int = bar() + var count = 0 + proc fn1(): int = 1 + proc fn2(): int = (count.inc; count) + func fun1() = discard foo(fn1) # ok because fn1 is inferred as `func` + # func fun2() = discard foo(fn2) # would give: Error: 'fun2' can have side effects + + # with callbacks, the compiler is conservative, ie that bar will have side effects + var foo2: type(foo) = foo + func main() = + discard foo(fn1) # ok + # discard foo2(fn1) # now this errors + compileTime pragma ------------------ diff --git a/tests/effects/tnosideeffect.nim b/tests/effects/tnosideeffect.nim new file mode 100644 index 000000000..9cabb35a2 --- /dev/null +++ b/tests/effects/tnosideeffect.nim @@ -0,0 +1,24 @@ +block: # `.noSideEffect` + func foo(bar: proc(): int): int = bar() + var count = 0 + proc fn1(): int = 1 + proc fn2(): int = (count.inc; count) + + template accept(body) = + doAssert compiles(block: + body) + + template reject(body) = + doAssert not compiles(block: + body) + + accept: + func fun1() = discard foo(fn1) + reject: + func fun1() = discard foo(fn2) + + var foo2: type(foo) = foo + accept: + func main() = discard foo(fn1) + reject: + func main() = discard foo2(fn1) |