Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(sem): noreturn analysis for void exprs #1454

Merged
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 38 additions & 21 deletions compiler/ast/ast_query.nim
Original file line number Diff line number Diff line change
Expand Up @@ -694,27 +694,44 @@ proc endsInNoReturn*(n: PNode): bool =
## Checks if expression `n` ends in an unstructured exit (raise, return,
## etc.) or a call of a noreturn proc. This is meant to be called on a
## semmed `n`.
var it = n
while it.kind in {nkStmtList, nkStmtListExpr} and it.len > 0 or
it.kind in {nkIfStmt, nkCaseStmt, nkBlockStmt, nkTryStmt} and it.typ.isEmptyType:
case it.kind
of nkStmtList, nkStmtListExpr, nkBlockStmt:
it = it.lastSon
of nkIfStmt, nkCaseStmt:
it = it.lastSon.lastSon
of nkTryStmt:
it =
case it[^1].kind
of nkFinally:
it[^2]
of nkExceptBranch:
it[^1]
of nkAllNodeKinds - {nkFinally, nkExceptBranch}:
unreachable()
else:
unreachable()
result = it.kind in nkLastBlockStmts or
it.kind in nkCallKinds and it[0].kind == nkSym and sfNoReturn in it[0].sym.flags
case n.kind
of nkStmtList, nkStmtListExpr:
result = n.len > 0 and endsInNoReturn(n[^1])
of nkBlockStmt, nkExceptBranch, nkElifBranch, nkElse, nkOfBranch:
result = endsInNoReturn(n[^1])
of nkIfStmt:
for it in n.items:
result = endsInNoReturn(it[^1])
if not result:
break
zerbina marked this conversation as resolved.
Show resolved Hide resolved
result = result and n[^1].kind == nkElse
of nkCaseStmt:
# skip the selector expression
for i in 1..<n.len:
result = endsInNoReturn(n[i])
if not result:
break
zerbina marked this conversation as resolved.
Show resolved Hide resolved
let
caseType = n[0].typ.skipTypes(abstractRange)
requiresElse =
case caseType.kind
of tyFloat..tyFloat64, tyString:
true
else:
false
saem marked this conversation as resolved.
Show resolved Hide resolved
result = result and (n[^1].kind == nkElse or not requiresElse)
of nkTryStmt:
# ignore the 'finally' -- it doesn't contribute to the type
for i in 0..<(n.len - ord(n[^1].kind == nkFinally)):
result = endsInNoReturn(n[i])
if not result:
break
of nkLastBlockStmts:
result = true
of nkCallKinds:
result = n[0].kind == nkSym and sfNoReturn in n[0].sym.flags
else:
result = false

type
NodePosName* = enum
Expand Down
11 changes: 11 additions & 0 deletions tests/lang_exprs/tnoreturn_nested.nim
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,17 @@ block nested_in_case:

doAssert x is int

block nested_in_case_range:
type Foo = range[1..1]
let x =
if true:
0
else:
let y: Foo = 1
case y
of 1:
raise newException(CatchableError, "error")

block nested_in_block:
let x =
if true:
Expand Down
16 changes: 16 additions & 0 deletions tests/lang_exprs/tnoreturn_nested_reject_nonexhaustive_case.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
discard """
description: '''
Ensure nested non-noreturn statements aren't treated as such
'''
errormsg: "expression '1' is of type 'int literal(1)' and has to be used (or discarded)"
line: 11
"""

let x =
if true:
1
else:
let y = "hi"
case y:
of "hi":
raise newException(Defect, "gone") # no return
14 changes: 14 additions & 0 deletions tests/lang_exprs/tnoreturn_nested_reject_nonexhaustive_if.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
discard """
description: '''
Ensure nested non-noreturn statements aren't treated as such
'''
errormsg: "expression '1' is of type 'int literal(1)' and has to be used (or discarded)"
line: 11
"""

let x =
if true:
1
else:
if true:
raise newException(Defect, "gone") # no return
16 changes: 16 additions & 0 deletions tests/lang_exprs/tnoreturn_nested_reject_void.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
discard """
description: '''
Ensure nested non-noreturn statements aren't treated as such
'''
errormsg: "expression '1' is of type 'int literal(1)' and has to be used (or discarded)"
line: 11
"""

let x =
if true:
1
else:
if true:
echo "fun" # void
else:
raise newException(Defect, "gone") # no return
Loading