Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
22 changes: 21 additions & 1 deletion compiler/sempass2.nim
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,26 @@ proc addRaiseEffect(a: PEffects, e, comesFrom: PNode) =
if not isDefectException(e.typ):
throws(a.exc, e, comesFrom)

proc addRaiseEffectsFromExpr(a: PEffects, e, comesFrom: PNode) =
if e.isNil:
return
let x = skipConvCastAndClosure(e)
case x.kind
of nkStmtList, nkStmtListExpr, nkBlockStmt, nkBlockExpr:
if x.len > 0:
addRaiseEffectsFromExpr(a, x.lastSon, comesFrom)
of nkIfExpr, nkIfStmt:
for branch in items(x):
if branch.len > 0:
addRaiseEffectsFromExpr(a, branch.lastSon, comesFrom)
of nkCaseStmt:
for i in 1..<x.len:
let branch = x[i]
if branch.len > 0:
addRaiseEffectsFromExpr(a, branch.lastSon, comesFrom)
else:
addRaiseEffect(a, x, x)

proc addTag(a: PEffects, e, comesFrom: PNode) =
var aa = a.tags
for i in 0..<aa.len:
Expand Down Expand Up @@ -1324,7 +1344,7 @@ proc track(tracked: PEffects, n: PNode) =
if n[0].kind != nkEmpty:
n[0].info = n.info
#throws(tracked.exc, n[0])
addRaiseEffect(tracked, n[0], n)
addRaiseEffectsFromExpr(tracked, n[0], n)
for i in 0..<n.safeLen:
track(tracked, n[i])
createTypeBoundOps(tracked, n[0].typ, n.info)
Expand Down
74 changes: 74 additions & 0 deletions tests/effects/tcase_raises.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
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)
Loading