Skip to content

Commit

Permalink
fix manual to reflect reality for .nosideeffect (nim-lang#16781)
Browse files Browse the repository at this point in the history
  • Loading branch information
timotheecour authored and ardek66 committed Mar 26, 2021
1 parent ac37555 commit a4a12f2
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 6 deletions.
31 changes: 25 additions & 6 deletions doc/manual.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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
------------------
Expand Down
24 changes: 24 additions & 0 deletions tests/effects/tnosideeffect.nim
Original file line number Diff line number Diff line change
@@ -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)

0 comments on commit a4a12f2

Please sign in to comment.