mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-03 11:42:33 +00:00
check constant conditions in generic when in objects (#24042)
fixes #24041 `when` statements in generic object types normally just leave their conditions as expressions and still typecheck their branch bodies. Instead of this, when the condition can be evaluated as a constant as well as the ones before it and it resolves to `true`, it now uses the body of that branch without typechecking the remaining ones.
This commit is contained in:
@@ -789,6 +789,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
||||
of nkRecWhen:
|
||||
var a = copyTree(n)
|
||||
var branch: PNode = nil # the branch to take
|
||||
var cannotResolve = false # no branch should be taken
|
||||
for i in 0..<a.len:
|
||||
var it = a[i]
|
||||
if it == nil: illFormedAst(n, c.config)
|
||||
@@ -806,24 +807,30 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
||||
let e = semExprWithType(c, it[0], {efDetermineType})
|
||||
if e.typ.kind == tyFromExpr:
|
||||
it[0] = makeStaticExpr(c, e)
|
||||
cannotResolve = true
|
||||
else:
|
||||
it[0] = forceBool(c, e)
|
||||
let val = getConstExpr(c.module, it[0], c.idgen, c.graph)
|
||||
if val == nil or val.kind != nkIntLit:
|
||||
cannotResolve = true
|
||||
elif not cannotResolve and val.intVal != 0 and branch == nil:
|
||||
branch = it[1]
|
||||
of nkElse:
|
||||
checkSonsLen(it, 1, c.config)
|
||||
if branch == nil: branch = it[0]
|
||||
if branch == nil and not cannotResolve: branch = it[0]
|
||||
idx = 0
|
||||
else: illFormedAst(n, c.config)
|
||||
if c.inGenericContext > 0:
|
||||
if c.inGenericContext > 0 and cannotResolve:
|
||||
# use a new check intset here for each branch:
|
||||
var newCheck: IntSet = check
|
||||
var newPos = pos
|
||||
var newf = newNodeI(nkRecList, n.info)
|
||||
semRecordNodeAux(c, it[idx], newCheck, newPos, newf, rectype, hasCaseFields)
|
||||
it[idx] = if newf.len == 1: newf[0] else: newf
|
||||
if c.inGenericContext > 0:
|
||||
father.add a
|
||||
elif branch != nil:
|
||||
if branch != nil:
|
||||
semRecordNodeAux(c, branch, check, pos, father, rectype, hasCaseFields)
|
||||
elif c.inGenericContext > 0:
|
||||
father.add a
|
||||
elif father.kind in {nkElse, nkOfBranch}:
|
||||
father.add newNodeI(nkRecList, n.info)
|
||||
of nkRecCase:
|
||||
|
||||
46
tests/generics/tgenericwhen.nim
Normal file
46
tests/generics/tgenericwhen.nim
Normal file
@@ -0,0 +1,46 @@
|
||||
discard """
|
||||
targets: "c js"
|
||||
"""
|
||||
|
||||
block: # issue #24041
|
||||
type ArrayBuf[N: static int, T = byte] = object
|
||||
when sizeof(int) > sizeof(uint8):
|
||||
when N <= int(uint8.high):
|
||||
n: uint8
|
||||
else:
|
||||
when sizeof(int) > sizeof(uint16):
|
||||
when N <= int(uint16.high):
|
||||
n: uint16
|
||||
else:
|
||||
when sizeof(int) > sizeof(uint32):
|
||||
when N <= int(uint32.high):
|
||||
n: uint32
|
||||
else:
|
||||
n: int
|
||||
else:
|
||||
n: int
|
||||
else:
|
||||
n: int
|
||||
else:
|
||||
n: int
|
||||
|
||||
var x: ArrayBuf[8]
|
||||
doAssert x.n is uint8
|
||||
when sizeof(int) > sizeof(uint32):
|
||||
var y: ArrayBuf[int(uint32.high) * 8]
|
||||
doAssert y.n is int
|
||||
|
||||
block: # constant condition after dynamic one
|
||||
type Foo[T] = object
|
||||
when T is int:
|
||||
a: int
|
||||
elif true:
|
||||
a: string
|
||||
else:
|
||||
a: bool
|
||||
var x: Foo[string]
|
||||
doAssert x.a is string
|
||||
var y: Foo[int]
|
||||
doAssert y.a is int
|
||||
var z: Foo[float]
|
||||
doAssert z.a is string
|
||||
Reference in New Issue
Block a user