Skip to content

Commit

Permalink
correctly render AST in doAssert/assert condition: fixes nim-lang#8518;…
Browse files Browse the repository at this point in the history
… refs nim-lang#9301 (nim-lang#9332)

* fixes nim-lang#8518; refs nim-lang#9301; correctly render AST in doAssert condition
  • Loading branch information
Timothee Cour authored and krux02 committed Oct 15, 2018
1 parent 2f4c853 commit 0260648
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 72 deletions.
14 changes: 8 additions & 6 deletions lib/system.nim
Original file line number Diff line number Diff line change
Expand Up @@ -3880,7 +3880,7 @@ proc failedAssertImpl*(msg: string) {.raises: [], tags: [].} =

include "system/helpers" # for `lineInfoToString`

template assertImpl(cond: bool, msg = "", enabled: static[bool]) =
template assertImpl(cond: bool, msg: string, expr: string, enabled: static[bool]) =
const loc = $instantiationInfo(-1, true)
bind instantiationInfo
mixin failedAssertImpl
Expand All @@ -3889,9 +3889,9 @@ template assertImpl(cond: bool, msg = "", enabled: static[bool]) =
# here, regardless of --excessiveStackTrace
{.line: instantiationInfo(fullPaths = true).}:
if not cond:
failedAssertImpl(loc & " `" & astToStr(cond) & "` " & msg)
failedAssertImpl(loc & " `" & expr & "` " & msg)

template assert*(cond: bool, msg = "") =
template assert*(cond: untyped, msg = "") =
## Raises ``AssertionError`` with `msg` if `cond` is false. Note
## that ``AssertionError`` is hidden from the effect system, so it doesn't
## produce ``{.raises: [AssertionError].}``. This exception is only supposed
Expand All @@ -3900,11 +3900,13 @@ template assert*(cond: bool, msg = "") =
## The compiler may not generate any code at all for ``assert`` if it is
## advised to do so through the ``-d:release`` or ``--assertions:off``
## `command line switches <nimc.html#command-line-switches>`_.
assertImpl(cond, msg, compileOption("assertions"))
const expr = astToStr(cond)
assertImpl(cond, msg, expr, compileOption("assertions"))

template doAssert*(cond: bool, msg = "") =
template doAssert*(cond: untyped, msg = "") =
## same as ``assert`` but is always turned on regardless of ``--assertions``
assertImpl(cond, msg, true)
const expr = astToStr(cond)
assertImpl(cond, msg, expr, true)

iterator items*[T](a: seq[T]): T {.inline.} =
## iterates over each item of `a`.
Expand Down
89 changes: 60 additions & 29 deletions tests/assert/tfailedassert.nim
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@ test6:ok
test7:ok
-1
tfailedassert.nim
test7:ok
test8:ok
test9:ok
test10:ok
test11:ok
'''
"""

import testhelper

type
TLineInfo = tuple[filename: string, line: int, column: int]
TMyError = object of Exception
Expand All @@ -23,7 +24,6 @@ type

echo("")


# NOTE: when entering newlines, adjust `expectedEnd` ouptuts

try:
Expand Down Expand Up @@ -60,37 +60,68 @@ proc fooStatic() =
static: doAssert(true)
fooStatic()

# 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

proc foo =
assert(false, "assertion from foo")


proc bar: int =
# local overrides that are active only in this proc

block:
# scope-wide policy to change the failed assert
# exception type in order to include a lineinfo
onFailedAssert(msg):
checkMsg(msg, "tfailedassert.nim(80, 9) `false` first assertion from bar", "test6")
var e = new(TMyError)
e.msg = msg
e.lineinfo = instantiationInfo(-2)
raise e

assert(false, "first assertion from bar")
proc foo =
assert(false, "assertion from foo")

onFailedAssert(msg):
checkMsg(msg, "tfailedassert.nim(86, 9) `false` second assertion from bar", "test7")
return -1

assert(false, "second assertion from bar")
return 10
proc bar: int =
# local overrides that are active only in this proc
onFailedAssert(msg):
checkMsg(msg, "tfailedassert.nim(85, 11) `false` first assertion from bar", "test6")

echo(bar())
assert(false, "first assertion from bar")

try:
foo()
except:
let e = EMyError(getCurrentException())
echo e.lineinfo.filename
checkMsg(e.msg, "tfailedassert.nim(72, 9) `false` assertion from foo", "test7")
onFailedAssert(msg):
checkMsg(msg, "tfailedassert.nim(91, 11) `false` second assertion from bar", "test7")
return -1

assert(false, "second assertion from bar")
return 10

echo(bar())

try:
foo()
except:
let e = EMyError(getCurrentException())
echo e.lineinfo.filename
checkMsg(e.msg, "tfailedassert.nim(77, 11) `false` assertion from foo", "test8")

block: ## checks for issue https://github.com/nim-lang/Nim/issues/8518
template fun(a: string): string =
const pattern = a & a
pattern

try:
doAssert fun("foo1") == fun("foo2"), "mymsg"
except AssertionError as e:
# used to expand out the template instantiaiton, sometimes filling hundreds of lines
checkMsg(e.msg, """tfailedassert.nim(109, 14) `fun("foo1") == fun("foo2")` mymsg""", "test9")

block: ## checks for issue https://github.com/nim-lang/Nim/issues/9301
try:
doAssert 1 + 1 == 3
except AssertionError as e:
# used to const fold as false
checkMsg(e.msg, "tfailedassert.nim(116, 14) `1 + 1 == 3` ", "test10")

block: ## checks AST isnt' transformed as it used to
let a = 1
try:
doAssert a > 1
except AssertionError as e:
# used to rewrite as `1 < a`
checkMsg(e.msg, "tfailedassert.nim(124, 14) `a > 1` ", "test11")
89 changes: 52 additions & 37 deletions tests/concepts/texplain.nim
Original file line number Diff line number Diff line change
@@ -1,69 +1,84 @@
discard """
cmd: "nim c --verbosity:0 --colors:off $file"
nimout: '''
texplain.nim(103, 10) Hint: Non-matching candidates for e(y)
Hint: texplain [Processing]
texplain.nim(118, 10) Hint: Non-matching candidates for e(y)
proc e(i: int): int
texplain.nim(106, 7) Hint: Non-matching candidates for e(10)
texplain.nim(121, 7) Hint: Non-matching candidates for e(10)
proc e(o: ExplainedConcept): int
texplain.nim(69, 6) ExplainedConcept: undeclared field: 'foo'
texplain.nim(69, 6) ExplainedConcept: undeclared field: '.'
texplain.nim(69, 6) ExplainedConcept: expression '.' cannot be called
texplain.nim(69, 5) ExplainedConcept: concept predicate failed
texplain.nim(70, 6) ExplainedConcept: undeclared field: 'bar'
texplain.nim(70, 6) ExplainedConcept: undeclared field: '.'
texplain.nim(70, 6) ExplainedConcept: expression '.' cannot be called
texplain.nim(69, 5) ExplainedConcept: concept predicate failed
texplain.nim(109, 10) Hint: Non-matching candidates for e(10)
texplain.nim(84, 6) ExplainedConcept: undeclared field: 'foo'
texplain.nim(84, 6) ExplainedConcept: undeclared field: '.'
texplain.nim(84, 6) ExplainedConcept: expression '.' cannot be called
texplain.nim(84, 5) ExplainedConcept: concept predicate failed
texplain.nim(85, 6) ExplainedConcept: undeclared field: 'bar'
texplain.nim(85, 6) ExplainedConcept: undeclared field: '.'
texplain.nim(85, 6) ExplainedConcept: expression '.' cannot be called
texplain.nim(84, 5) ExplainedConcept: concept predicate failed
texplain.nim(124, 10) Hint: Non-matching candidates for e(10)
proc e(o: ExplainedConcept): int
texplain.nim(69, 6) ExplainedConcept: undeclared field: 'foo'
texplain.nim(69, 6) ExplainedConcept: undeclared field: '.'
texplain.nim(69, 6) ExplainedConcept: expression '.' cannot be called
texplain.nim(69, 5) ExplainedConcept: concept predicate failed
texplain.nim(70, 6) ExplainedConcept: undeclared field: 'bar'
texplain.nim(70, 6) ExplainedConcept: undeclared field: '.'
texplain.nim(70, 6) ExplainedConcept: expression '.' cannot be called
texplain.nim(69, 5) ExplainedConcept: concept predicate failed
texplain.nim(113, 20) Error: type mismatch: got <NonMatchingType>
texplain.nim(84, 6) ExplainedConcept: undeclared field: 'foo'
texplain.nim(84, 6) ExplainedConcept: undeclared field: '.'
texplain.nim(84, 6) ExplainedConcept: expression '.' cannot be called
texplain.nim(84, 5) ExplainedConcept: concept predicate failed
texplain.nim(85, 6) ExplainedConcept: undeclared field: 'bar'
texplain.nim(85, 6) ExplainedConcept: undeclared field: '.'
texplain.nim(85, 6) ExplainedConcept: expression '.' cannot be called
texplain.nim(84, 5) ExplainedConcept: concept predicate failed
texplain.nim(128, 20) Error: type mismatch: got <NonMatchingType>
but expected one of:
proc e(o: ExplainedConcept): int
texplain.nim(69, 5) ExplainedConcept: concept predicate failed
texplain.nim(128, 9) template/generic instantiation of `assert` from here
texplain.nim(84, 5) ExplainedConcept: concept predicate failed
proc e(i: int): int
expression: e(n)
texplain.nim(114, 20) Error: type mismatch: got <NonMatchingType>
texplain.nim(129, 20) Error: type mismatch: got <NonMatchingType>
but expected one of:
proc r(o: RegularConcept): int
texplain.nim(73, 5) RegularConcept: concept predicate failed
texplain.nim(129, 9) template/generic instantiation of `assert` from here
texplain.nim(88, 5) RegularConcept: concept predicate failed
proc r[T](a: SomeNumber; b: T; c: auto)
proc r(i: string): int
expression: r(n)
texplain.nim(115, 20) Hint: Non-matching candidates for r(y)
texplain.nim(130, 20) Hint: Non-matching candidates for r(y)
proc r[T](a: SomeNumber; b: T; c: auto)
proc r(i: string): int
texplain.nim(123, 2) Error: type mismatch: got <MatchingType>
texplain.nim(138, 2) Error: type mismatch: got <MatchingType>
but expected one of:
proc f(o: NestedConcept)
texplain.nim(73, 6) RegularConcept: undeclared field: 'foo'
texplain.nim(73, 6) RegularConcept: undeclared field: '.'
texplain.nim(73, 6) RegularConcept: expression '.' cannot be called
texplain.nim(73, 5) RegularConcept: concept predicate failed
texplain.nim(74, 6) RegularConcept: undeclared field: 'bar'
texplain.nim(74, 6) RegularConcept: undeclared field: '.'
texplain.nim(74, 6) RegularConcept: expression '.' cannot be called
texplain.nim(73, 5) RegularConcept: concept predicate failed
texplain.nim(77, 5) NestedConcept: concept predicate failed
texplain.nim(88, 6) RegularConcept: undeclared field: 'foo'
texplain.nim(88, 6) RegularConcept: undeclared field: '.'
texplain.nim(88, 6) RegularConcept: expression '.' cannot be called
texplain.nim(88, 5) RegularConcept: concept predicate failed
texplain.nim(89, 6) RegularConcept: undeclared field: 'bar'
texplain.nim(89, 6) RegularConcept: undeclared field: '.'
texplain.nim(89, 6) RegularConcept: expression '.' cannot be called
texplain.nim(88, 5) RegularConcept: concept predicate failed
texplain.nim(92, 5) NestedConcept: concept predicate failed
expression: f(y)
'''
line: 123
line: 138
errormsg: "type mismatch: got <MatchingType>"
"""











# line 80 HERE

type
ExplainedConcept {.explain.} = concept o
o.foo is int
Expand Down

0 comments on commit 0260648

Please sign in to comment.