summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorTimothee Cour <timothee.cour2@gmail.com>2021-01-22 11:04:48 -0800
committerGitHub <noreply@github.com>2021-01-22 20:04:48 +0100
commit8f62cd512c0c5ae9a27087ccf8b4f666611709e6 (patch)
tree0e2eb7135212d1ff130a00d29016381ec0057d60
parentaca97250eae891c87e0c98f02bd7db9687bab5b0 (diff)
downloadNim-8f62cd512c0c5ae9a27087ccf8b4f666611709e6.tar.gz
fix manual to reflect reality for .nosideeffect (#16781)
-rw-r--r--doc/manual.rst31
-rw-r--r--tests/effects/tnosideeffect.nim24
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)