mirror of
https://github.com/nim-lang/Nim.git
synced 2026-07-12 04:09:34 +00:00
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.
74 lines
2.3 KiB
Nim
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) |