diff options
Diffstat (limited to 'lib/system')
-rw-r--r-- | lib/system/assertions.nim | 86 |
1 files changed, 51 insertions, 35 deletions
diff --git a/lib/system/assertions.nim b/lib/system/assertions.nim index 4c25d2a56..b30b2e26d 100644 --- a/lib/system/assertions.nim +++ b/lib/system/assertions.nim @@ -1,3 +1,37 @@ +## This module provides various assertion utilities. +## +## **Note:** This module is reexported by `system` and thus does not need to be +## imported directly (with `system/assertions`). + +runnableExamples: + # assert + assert 1 == 1 + + # onFailedAssert + block: + type MyError = object of CatchableError + lineinfo: tuple[filename: string, line: int, column: int] + + # block-wide policy to change the failed assert + # exception type in order to include a lineinfo + onFailedAssert(msg): + var e = new(MyError) + e.msg = msg + e.lineinfo = instantiationInfo(-2) + raise e + + # doAssert + doAssert 1 == 1 # generates code even when built with `-d:danger` or `--assertions:off` + + # doAssertRaises + doAssertRaises(ValueError): + raise newException(ValueError, "Hello World") + +runnableExamples("--assertions:off"): + assert 1 == 2 # no code generated + +# xxx pending bug #16993: move runnableExamples to respective templates + when not declared(sysFatal): include "system/fatal" @@ -12,7 +46,7 @@ proc `$`(info: InstantiationInfo): string = # The +1 is needed here # instead of overriding `$` (and changing its meaning), consider explicit name. result = "" - result.toLocation(info.filename, info.line, info.column+1) + result.toLocation(info.filename, info.line, info.column + 1) # --------------------------------------------------------------------------- @@ -20,13 +54,17 @@ when not defined(nimHasSinkInference): {.pragma: nosinks.} proc raiseAssert*(msg: string) {.noinline, noreturn, nosinks.} = + ## Raises an `AssertionDefect` with `msg`. sysFatal(AssertionDefect, msg) proc failedAssertImpl*(msg: string) {.raises: [], tags: [].} = - # trick the compiler to not list ``AssertionDefect`` when called - # by ``assert``. - type Hide = proc (msg: string) {.noinline, raises: [], noSideEffect, - tags: [].} + ## Raises an `AssertionDefect` with `msg`, but this is hidden + ## from the effect system. Called when an assertion failed. + # trick the compiler to not list `AssertionDefect` when called + # by `assert`. + # xxx simplify this pending bootstrap >= 1.4.0, after which cast not needed + # anymore since `Defect` can't be raised. + type Hide = proc (msg: string) {.noinline, raises: [], noSideEffect, tags: [].} cast[Hide](raiseAssert)(msg) template assertImpl(cond: bool, msg: string, expr: string, enabled: static[bool]) = @@ -41,52 +79,30 @@ template assertImpl(cond: bool, msg: string, expr: string, enabled: static[bool] failedAssertImpl(ploc & " `" & expr & "` " & msg) template assert*(cond: untyped, msg = "") = - ## Raises ``AssertionDefect`` with `msg` if `cond` is false. Note - ## that ``AssertionDefect`` is hidden from the effect system, so it doesn't - ## produce ``{.raises: [AssertionDefect].}``. This exception is only supposed + ## Raises `AssertionDefect` with `msg` if `cond` is false. Note + ## that `AssertionDefect` is hidden from the effect system, so it doesn't + ## produce `{.raises: [AssertionDefect].}`. This exception is only supposed ## to be caught by unit testing frameworks. ## - ## The compiler may not generate any code at all for ``assert`` if it is - ## advised to do so through the ``-d:danger`` or ``--assertions:off`` - ## `command line switches <nimc.html#compiler-usage-commandminusline-switches>`_. - ## - ## .. code-block:: nim - ## static: assert 1 == 9, "This assertion generates code when not built with -d:danger or --assertions:off" + ## No code will be generated for `assert` when passing `-d:danger` (implied by `--assertions:off`). + ## See `command line switches <nimc.html#compiler-usage-commandminusline-switches>`_. const expr = astToStr(cond) assertImpl(cond, msg, expr, compileOption("assertions")) template doAssert*(cond: untyped, msg = "") = - ## Similar to ``assert`` but is always turned on regardless of ``--assertions``. - ## - ## .. code-block:: nim - ## static: doAssert 1 == 9, "This assertion generates code when built with/without -d:danger or --assertions:off" + ## Similar to `assert <#assert.t,untyped,string>`_ but is always turned on regardless of `--assertions`. const expr = astToStr(cond) assertImpl(cond, msg, expr, true) template onFailedAssert*(msg, code: untyped): untyped {.dirty.} = ## Sets an assertion failure handler that will intercept any assert - ## statements following `onFailedAssert` in the current module scope. - ## - ## .. code-block:: nim - ## # module-wide policy to change the failed assert - ## # exception type in order to include a lineinfo - ## onFailedAssert(msg): - ## var e = new(TMyError) - ## e.msg = msg - ## e.lineinfo = instantiationInfo(-2) - ## raise e - ## + ## statements following `onFailedAssert` in the current scope. template failedAssertImpl(msgIMPL: string): untyped {.dirty.} = let msg = msgIMPL code template doAssertRaises*(exception: typedesc, code: untyped) = - ## Raises ``AssertionDefect`` if specified ``code`` does not raise `exception`. - ## Example: - ## - ## .. code-block:: nim - ## doAssertRaises(ValueError): - ## raise newException(ValueError, "Hello World") + ## Raises `AssertionDefect` if specified `code` does not raise `exception`. var wrong = false const begin = "expected raising '" & astToStr(exception) & "', instead" const msgEnd = " by: " & astToStr(code) |