Files
Nim/tests/effects/tcase_raises.nim
ringabout 587f90a816 fixes #22122; Unclear error message for raise of a complex expression (#25899)
fixes  #22122

The commit fixes a bug in Nim's effects checker where raise statements
with case/if expressions (commonly from template expansion) failed to
track exception types from individual branches.
Problem: addRaiseEffect only saw the outermost expression. When a
template like getTransportError(err) expanded to a case expression
raising 3 different exception types, the compiler only registered the
top-level call — missing the branch-level exceptions.
Fix (2 files):
- compiler/sempass2.nim: Added skipHiddenConv to strip implicit type
coercion nodes (nkHiddenStdConv/nkHiddenSubConv) that hide the control
flow structure. Added addRaiseEffectsFromExpr that recursively walks
into case/if/block/stmtlist expressions to find raise effects in each
branch body. Changed the nkRaiseStmt handler to use this new function.
- tests/effects/tcase_raises.nim: Test with templates that expand to
case expressions raising different exception types, verified via
{.raises: [].} pragma.
2026-06-13 10:17:59 +02:00

74 lines
2.3 KiB
Nim

from std/os import osLastError, osErrorMsg, OSErrorCode, raiseOSError,
newOSError, `==`
{.push raises: [].}
const
EPERM* = OSErrorCode(1)
ECONNABORTED* = OSErrorCode(53)
ETIMEDOUT* = OSErrorCode(60)
ENOTCONN* = OSErrorCode(107)
EMFILE* = OSErrorCode(24)
ENFILE* = OSErrorCode(23)
ENOBUFS* = OSErrorCode(55)
ENOMEM* = OSErrorCode(12)
type
AsyncError* = object of CatchableError
TransportErrorBase* = object of AsyncError
TransportOsError* = object of TransportErrorBase
code*: OSErrorCode
TransportTooManyError* = object of TransportErrorBase
TransportAbortedError* = object of TransportErrorBase
template getConnectionAbortedError*(
code: OSErrorCode
): ref TransportAbortedError =
let msg =
case code
of OSErrorCode(0), ECONNABORTED:
"[ECONNABORTED] Connection has been aborted before being accepted"
of EPERM:
"[EPERM] Firewall rules forbid connection"
of ETIMEDOUT:
"[ETIMEDOUT] Operation has been timed out"
of ENOTCONN:
"[ENOTCONN] Transport endpoint is not connected"
else:
"[" & $int(code) & "] Connection has been aborted"
newException(TransportAbortedError, msg)
template getTransportTooManyError*(
code = OSErrorCode(0)
): ref TransportTooManyError =
let msg =
case code
of OSErrorCode(0):
"Too many open transports"
of EMFILE:
"[EMFILE] Too many open files in the process"
of ENFILE:
"[ENFILE] Too many open files in system"
of ENOBUFS:
"[ENOBUFS] No buffer space available"
of ENOMEM:
"[ENOMEM] Not enough memory availble"
else:
"[" & $int(code) & "] Too many open transports"
newException(TransportTooManyError, msg)
template getTransportError*(ecode: OSErrorCode): untyped =
case ecode
of ECONNABORTED, EPERM, ETIMEDOUT, ENOTCONN:
getConnectionAbortedError(ecode)
of EMFILE, ENFILE, ENOBUFS, ENOMEM:
getTransportTooManyError(ecode)
else:
(ref TransportOsError)(code: ecode,
msg: "(" & $int(ecode) & ") " & osErrorMsg(ecode))
proc raiseTransportError*(err: OSErrorCode) {.
raises: [TransportAbortedError, TransportTooManyError, TransportOsError],
noreturn.} =
## Raises transport specific OS error.
raise getTransportError(err)