fix noreturn/implicit discard check logic (#23681)

fixes #10440, fixes #13871, fixes #14665, fixes #19672, fixes #23677

The false positive in #23677 was caused by behavior in
`implicitlyDiscardable` where only the last node of `if`/`case`/`try`
etc expressions were considered, as in the final node of the final
branch (in this case `else`). To fix this we use the same iteration in
`implicitlyDiscardable` that we use in `endsInNoReturn`, with the
difference that for an `if`/`case`/`try` statement to be implicitly
discardable, all of its branches must be implicitly discardable.
`noreturn` calls are also considered implicitly discardable for this
reason, otherwise stuff like `if true: discardableCall() else: error()`
doesn't compile.

However `endsInNoReturn` also had bugs, one where `finally` was
considered in noreturn checking when it shouldn't, another where only
`nkIfStmt` was checked and not `nkIfExpr`, and the node given for the
error message was bad. So `endsInNoReturn` now skips over
`skipForDiscardable` which no longer contains
`nkIfStmt`/`nkCaseStmt`/`nkTryStmt`, stores the first encountered
returning node in a var parameter for the error message, and handles
`finally` and `nkIfExpr`.

Fixing #23677 already broke a line in `syncio` so some package code
might be affected.
This commit is contained in:
metagn
2024-06-05 21:53:05 +03:00
committed by GitHub
parent 77c04092e0
commit 42e8472ca6
6 changed files with 195 additions and 74 deletions

12
tests/discard/t23677.nim Normal file
View File

@@ -0,0 +1,12 @@
discard """
errormsg: "expression '0' is of type 'int literal(0)' and has to be used (or discarded); start of expression here: t23677.nim(1, 1)"
line: 10
column: 3
"""
# issue #23677
if true:
0
else:
raise newException(ValueError, "err")

View File

@@ -5,6 +5,7 @@ tdiscardable
1
something defered
something defered
hi
'''
"""
@@ -110,3 +111,32 @@ block:
doAssertRaises(ValueError):
doAssert foo() == 12
block: # issue #10440
proc x(): int {.discardable.} = discard
try:
x()
finally:
echo "hi"
import macros
block: # issue #14665
macro test(): untyped =
let b = @[1, 2, 3, 4]
result = nnkStmtList.newTree()
var i = 0
while i < b.len:
if false:
# this quote do is mandatory, removing it fixes the problem
result.add quote do:
let testtest = 5
else:
result.add quote do:
let test = 6
inc i
# removing this continue fixes the problem too
continue
inc i
test()

View File

@@ -0,0 +1,19 @@
discard """
cmd: "nim check $file"
"""
block: # issue #19672
try:
10 #[tt.Error
^ expression '10' is of type 'int literal(10)' and has to be used (or discarded); start of expression here: tfinallyerrmsg.nim(5, 1)]#
finally:
echo "Finally block"
block: # issue #13871
template t(body: int) =
try:
body
finally:
echo "expression"
t: 2 #[tt.Error
^ expression '2' is of type 'int literal(2)' and has to be used (or discarded)]#