mirror of
https://github.com/nim-lang/Nim.git
synced 2026-06-14 15:43:45 +00:00
fixes #22122 The root cause is in the effect tracker: raise was recording the whole conditional expression as one exception source, so semantic checking only saw the widened common base type instead of the concrete exception classes from each branch.
This commit is contained in:
@@ -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:
|
||||
@@ -1326,7 +1346,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)
|
||||
|
||||
74
tests/effects/tcase_raises.nim
Normal file
74
tests/effects/tcase_raises.nim
Normal file
@@ -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)
|
||||
Reference in New Issue
Block a user