From a1ee35e29b04e6d7d38eaf091848bfca54b096d5 Mon Sep 17 00:00:00 2001 From: Saem Ghani Date: Thu, 12 Sep 2024 18:32:07 -0700 Subject: [PATCH] fix(sem): noreturn analysis for `void` exprs (#1454) ## Summary `void` branches preceeding with no-return terminal branches are checked with no-return analysis to avoid false positives. ## Details The analysis is updated to recursively check `if/elif/of/except` non-terminal branches as well as the terminal branch. Fixes https://github.com/nim-works/nimskull/issues/1453 --- compiler/ast/ast_query.nim | 53 +++++++++++-------- tests/lang_exprs/tnoreturn_nested.nim | 11 ++++ ...eturn_nested_reject_nonexhaustive_case.nim | 16 ++++++ ...oreturn_nested_reject_nonexhaustive_if.nim | 14 +++++ .../tnoreturn_nested_reject_void.nim | 16 ++++++ 5 files changed, 89 insertions(+), 21 deletions(-) create mode 100644 tests/lang_exprs/tnoreturn_nested_reject_nonexhaustive_case.nim create mode 100644 tests/lang_exprs/tnoreturn_nested_reject_nonexhaustive_if.nim create mode 100644 tests/lang_exprs/tnoreturn_nested_reject_void.nim diff --git a/compiler/ast/ast_query.nim b/compiler/ast/ast_query.nim index ab8cadf396..58fceac534 100644 --- a/compiler/ast/ast_query.nim +++ b/compiler/ast/ast_query.nim @@ -694,27 +694,38 @@ 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 + result = result and n[^1].kind == nkElse + of nkCaseStmt: + # skip the selector expression + for i in 1..