Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support uint64 for case statement operands #820

Merged
merged 7 commits into from
Jul 31, 2023
Merged
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
16 changes: 8 additions & 8 deletions compiler/ast/nimsets.nim
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,12 @@ proc toBitSet*(conf: ConfigRef; s: PNode): TBitSet =
inclTreeSet(result, conf, s)

proc toTreeSet*(conf: ConfigRef; s: TBitSetView, settype: PType, info: TLineInfo): PNode =
let
elemType = settype[0]
first = firstOrd(conf, elemType)
var
a, b, e, first: BiggestInt # a, b are interval borders
elemType: PType
n: PNode
elemType = settype[0]
first = firstOrd(conf, elemType).toInt64
a, b, e: BiggestInt # a, b are interval borders

result = newNodeI(nkCurly, info)
result.typ = settype
result.info = info
Expand All @@ -107,12 +107,12 @@ proc toTreeSet*(conf: ConfigRef; s: TBitSetView, settype: PType, info: TLineInfo
if a == b:
result.add aa
else:
n = newNodeI(nkRange, info)
var n = newNodeI(nkRange, info, 2)
n.typ = elemType
n.add aa
n[0] = aa
let bb = newIntTypeNode(b + first, elemType)
bb.info = info
n.add bb
n[1] = bb
result.add n
e = b
inc(e)
Expand Down
33 changes: 13 additions & 20 deletions compiler/backend/ccgexprs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -39,29 +39,22 @@ proc intLiteral(i: BiggestInt): Rope =
proc intLiteral(i: Int128): Rope =
intLiteral(toInt64(i))

proc intLiteral(p: BProc, i: Int128, ty: PType): Rope =
assert ty != nil
case skipTypes(ty, abstractVarRange).kind
of tyChar: intLiteral(i)
of tyBool:
if i != Zero: "NIM_TRUE"
else: "NIM_FALSE"
of tyInt64: int64Literal(toInt64(i))
of tyUInt64: uint64Literal(toUInt64(i))
else:
"(($1) $2)" % [getTypeDesc(p.module, ty), intLiteral(i)]

proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
case n.kind
of nkCharLit..nkUInt64Lit:
var k: TTypeKind
if ty != nil:
k = skipTypes(ty, abstractVarRange).kind
else:
case n.kind
of nkCharLit: k = tyChar
of nkUInt64Lit: k = tyUInt64
of nkInt64Lit: k = tyInt64
else: k = tyNil # don't go into the case variant that uses 'ty'
case k
of tyChar, tyNil:
result = intLiteral(n.intVal)
of tyBool:
if n.intVal != 0: result = ~"NIM_TRUE"
else: result = ~"NIM_FALSE"
of tyInt64: result = int64Literal(n.intVal)
of tyUInt64: result = uint64Literal(uint64(n.intVal))
else:
result = "(($1) $2)" % [getTypeDesc(p.module,
ty), intLiteral(n.intVal)]
result = intLiteral(p, getInt(n), ty)
of nkNilLit:
let k = if ty == nil: tyPointer else: skipTypes(ty, abstractVarRange).kind
if k == tyProc and skipTypes(ty, abstractVarRange).callConv == ccClosure:
Expand Down
13 changes: 8 additions & 5 deletions compiler/backend/ccgstmts.nim
Original file line number Diff line number Diff line change
Expand Up @@ -542,7 +542,7 @@ proc branchHasTooBigRange(b: PNode): bool =
for it in b:
# last son is block
if (it.kind == nkRange) and
it[1].intVal - it[0].intVal > RangeExpandLimit:
getInt(it[1]) - getInt(it[0]) > RangeExpandLimit:
return true

proc ifSwitchSplitPoint(p: BProc, n: PNode): int =
Expand All @@ -563,10 +563,13 @@ proc genCaseRange(p: BProc, branch: PNode) =
genLiteral(p, branch[j][0]),
genLiteral(p, branch[j][1])])
else:
var v = copyNode(branch[j][0])
while v.intVal <= branch[j][1].intVal:
lineF(p, cpsStmts, "case $1:$n", [genLiteral(p, v)])
inc(v.intVal)
let
typ = branch[j][0].typ
upper = getInt(branch[j][1])
var v = getInt(branch[j][0])
while v <= upper:
lineF(p, cpsStmts, "case $1:$n", [intLiteral(p, v, typ)])
inc(v)
else:
lineF(p, cpsStmts, "case $1:$n", [genLiteral(p, branch[j])])

Expand Down
1 change: 1 addition & 0 deletions compiler/backend/cgen.nim
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,7 @@ proc genStmts*(p: BProc, t: PNode)
proc expr(p: BProc, n: PNode, d: var TLoc)
proc putLocIntoDest(p: BProc, d: var TLoc, s: TLoc)
proc intLiteral(i: BiggestInt): Rope
proc intLiteral(p: BProc, i: Int128, ty: PType): Rope
proc genLiteral(p: BProc, n: PNode): Rope
proc raiseExit(p: BProc)

Expand Down
25 changes: 14 additions & 11 deletions compiler/backend/jsgen.nim
Original file line number Diff line number Diff line change
Expand Up @@ -825,10 +825,16 @@ proc genRaiseStmt(p: PProc, n: PNode) =
useMagic(p, "reraiseException")
line(p, "reraiseException();\L")

func intLiteral(v: Int128, typ: PType): string =
if typ.kind == tyBool:
if v == Zero: "false"
else: "true"
else: $v

proc genCaseJS(p: PProc, n: PNode) =
var
cond: TCompRes
totalRange = 0
totalRange = Zero
genLineDir(p, n)
gen(p, n[0], cond)
let stringSwitch = skipTypes(n[0].typ, abstractVar).kind == tyString
Expand All @@ -845,15 +851,15 @@ proc genCaseJS(p: PProc, n: PNode) =
for j in 0..<it.len - 1:
let e = it[j]
if e.kind == nkRange:
var v = copyNode(e[0])
inc(totalRange, int(e[1].intVal - v.intVal))
let upper = getInt(e[1])
var v = getInt(e[0])
totalRange += upper - v
if totalRange > 65535:
localReport(p.config, n.info, BackendReport(kind: rbackJsTooCaseTooLarge))

while v.intVal <= e[1].intVal:
gen(p, v, cond)
lineF(p, "case $1:$n", [cond.rdLoc])
inc(v.intVal)
while v <= upper:
lineF(p, "case $1:$n", [intLiteral(v, e[0].typ)])
inc v
else:
if stringSwitch:
case e.kind
Expand Down Expand Up @@ -2409,10 +2415,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
of nkSym:
genSym(p, n, r)
of nkCharLit..nkUInt64Lit:
if n.typ.kind == tyBool:
r.res = if n.intVal == 0: rope"false" else: rope"true"
else:
r.res = rope(n.intVal)
r.res = intLiteral(getInt(n), n.typ)
r.kind = resExpr
of nkNilLit:
if isEmptyType(n.typ):
Expand Down
2 changes: 1 addition & 1 deletion compiler/sem/semstmts.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1660,7 +1660,7 @@ proc semCase(c: PContext, n: PNode; flags: TExprFlags): PNode =
var typ = commonTypeBegin
var hasElse = false
let caseTyp = skipTypes(n[0].typ, abstractVar-{tyTypeDesc})
const shouldChckCovered = {tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt32, tyBool}
const shouldChckCovered = {tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt64, tyBool}
case caseTyp.kind
of shouldChckCovered:
chckCovered = true
Expand Down
40 changes: 40 additions & 0 deletions tests/lang_stmts/casestmt/tcase_with_uint_values.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
discard """
targets: "c !js vm"
description: '''
Ensures that case statements work with uint operands and of-branch values
not representable with the same-sized signed integer type
'''
"""

# knownIssue: compiles correctly for JS, but doesn't work at run-time because
# of the improper large integer support

proc test[T: uint64|uint; S]() =
const Border = T(high(S)) # the highest possible signed integer value

proc inRange(x: T): int {.noinline.} = # don't fold at compile-time
type Range = range[Border-5..Border+5]
# work-around so that the set construction expression compiles

case x
of (high(T)-3)..high(T): 0 # range that's fully beyond the border
of (Border-4)..(Border+4): 1 # range that crosses the border
of {Range(Border-5), Border+5}: 2 # set with values in and beyond the border
else: 3

doAssert inRange(0) == 3
doAssert inRange(high(T)) == 0
when defined(vm):
# knownIssue: ranges in of-branches that cross the signed/unsigned border
# don't work correctly in the VM, due to their values being
# treated as signed integers
doAssert inRange(Border) == 3
doAssert inRange(Border+1) == 3
else:
doAssert inRange(Border) == 1
doAssert inRange(Border+1) == 1
doAssert inRange(Border-5) == 2
doAssert inRange(Border+5) == 2

test[uint64, int64]()
test[uint, int]()