fixes #26036; compiler inference for sfNeverRaises (#26059)

fixes #26036

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
(cherry picked from commit 050b38c749)
This commit is contained in:
ringabout
2026-08-07 19:08:51 +08:00
committed by narimiran
parent 96f9020534
commit 953466839e

View File

@@ -82,6 +82,7 @@ type
guards: TModel # nested guards
locked: seq[PNode] # locked locations
gcUnsafe, isRecursive, isTopLevel, hasSideEffect, inEnforcedGcSafe: bool
canRaiseDefect: bool # defects are deliberately omitted from `exc`
isInnerProc: bool
inEnforcedNoSideEffects: bool
isArrayIndexing: bool
@@ -140,6 +141,11 @@ proc createTypeBoundOps(tracked: PEffects, typ: PType; info: TLineInfo; explicit
createTypeBoundOps(tracked.graph, tracked.c, realType.lastSon, info)
createTypeBoundOps(tracked.graph, tracked.c, typ, info, tracked.c.idgen)
for kind in TTypeAttachedOp:
let op = getAttachedOp(tracked.graph, typ, kind)
if op != nil and sfNeverRaises notin op.flags:
tracked.canRaiseDefect = true
break
if (tfHasAsgn in typ.flags) or
optSeqDestructors in tracked.config.globalOptions:
tracked.owner.flags.incl sfInjectDestructors
@@ -191,6 +197,23 @@ proc shouldWarnRangeConversion(conf: ConfigRef; info: TLineInfo; formalType, arg
else:
result = false
proc conversionCanRaiseDefect(conf: ConfigRef; destType, sourceType: PType): bool =
## Keep this in sync with the range checks introduced by `transformConv`.
let
dest = destType.skipTypes(abstractVarRange)
source = sourceType.skipTypes(abstractVarRange)
case dest.kind
of tyInt..tyInt64, tyEnum, tyChar, tyUInt8..tyUInt32:
if not source.isOrdinalType:
result = dest.kind in tyInt..tyInt64
else:
result = firstOrd(conf, destType) > firstOrd(conf, sourceType) or
lastOrd(conf, sourceType) > lastOrd(conf, destType)
of tyFloat..tyFloat128:
result = destType.skipTypes(abstractVar).kind == tyRange
else:
result = false
proc lockLocations(a: PEffects; pragma: PNode) =
if pragma.kind != nkExprColonExpr:
localError(a.config, pragma.info, "locks pragma without argument")
@@ -493,7 +516,9 @@ proc addRaiseEffect(a: PEffects, e, comesFrom: PNode) =
if sameType(a.graph.excType(aa[i]), a.graph.excType(e)): return
if e.typ != nil:
if not isDefectException(e.typ):
if isDefectException(e.typ):
a.canRaiseDefect = true
else:
throws(a.exc, e, comesFrom)
proc skipHiddenConv(n: PNode): PNode =
@@ -1109,6 +1134,32 @@ proc trackCall(tracked: PEffects; n: PNode) =
markSideEffect(tracked, a, n.info)
# p's effects are ours too:
var a = n[0]
if a.kind == nkSym:
let s = a.sym
case s.magic
of mNone:
if {sfNeverRaises, sfImportc, sfCompilerProc} * s.flags == {} and
(sfSystemModule notin getModule(s).flags or
sfSystemRaisesDefect in s.flags):
tracked.canRaiseDefect = true
of mUnaryMinusI..mAbsI, mAddI..mPred:
if optOverflowCheck in tracked.currOptions:
tracked.canRaiseDefect = true
of mInc, mDec:
let typ = n[1].typ.skipTypes({tyGenericInst, tyAlias, tySink,
tyVar, tyLent, tyRange, tyDistinct})
if optOverflowCheck in tracked.currOptions and
typ.kind notin {tyUInt..tyUInt64}:
tracked.canRaiseDefect = true
of mDivU, mModU:
tracked.canRaiseDefect = true
of mAddF64..mDivF64:
if {optNaNCheck, optInfCheck} * tracked.currOptions != {}:
tracked.canRaiseDefect = true
else:
discard
else:
tracked.canRaiseDefect = true
#if canRaise(a):
# echo "this can raise ", tracked.config $ n.info
let op = a.typ
@@ -1347,6 +1398,7 @@ proc track(tracked: PEffects, n: PNode) =
else:
track(tracked, n[0])
of nkRaiseStmt:
tracked.canRaiseDefect = true
if n[0].kind != nkEmpty:
n[0].info = n.info
#throws(tracked.exc, n[0])
@@ -1375,6 +1427,8 @@ proc track(tracked: PEffects, n: PNode) =
for i in 0..<n.len: track(tracked, n[i])
tracked.leftPartOfAsgn = oldLeftPartOfAsgn
of nkCheckedFieldExpr:
if optFieldCheck in tracked.currOptions:
tracked.canRaiseDefect = true
track(tracked, n[0])
if tracked.config.hasWarn(warnProveField) or strictCaseObjects in tracked.c.features:
checkFieldAccess(tracked.guards, n, tracked.config, strictCaseObjects in tracked.c.features)
@@ -1572,6 +1626,9 @@ proc track(tracked: PEffects, n: PNode) =
if tracked.owner.kind != skMacro:
createTypeBoundOps(tracked, n.typ, n.info)
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
if optRangeCheck in tracked.currOptions and
conversionCanRaiseDefect(tracked.config, n.typ, n[1].typ):
tracked.canRaiseDefect = true
if n.kind in {nkHiddenStdConv, nkHiddenSubConv} and
n.typ.skipTypes(abstractInst).kind == tyCstring and
not allowCStringConv(n[1]):
@@ -1609,6 +1666,11 @@ proc track(tracked: PEffects, n: PNode) =
if optStaticBoundsCheck in tracked.currOptions:
checkRange(tracked, n[1], n.typ)
of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64:
if n.kind in {nkObjUpConv, nkObjDownConv}:
if optObjCheck in tracked.currOptions:
tracked.canRaiseDefect = true
elif optRangeCheck in tracked.currOptions:
tracked.canRaiseDefect = true
if n.len == 1:
track(tracked, n[0])
if tracked.owner.kind != skMacro:
@@ -1623,6 +1685,8 @@ proc track(tracked: PEffects, n: PNode) =
if tracked.owner.kind != skMacro:
createTypeBoundOps(tracked, n.typ, n.info)
of nkBracketExpr:
if optBoundsCheck in tracked.currOptions:
tracked.canRaiseDefect = true
if optStaticBoundsCheck in tracked.currOptions and n.len == 2:
if n[0].typ != nil and skipTypes(n[0].typ, abstractVar).kind != tyTuple:
checkBounds(tracked, n[0], n[1])
@@ -1804,6 +1868,9 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) =
track(t, body)
if t.exc.len == 0 and not t.canRaiseDefect:
s.incl sfNeverRaises
if s.kind != skMacro:
let params = s.typ.n
for i in 1..<params.len: