Skip to content

Commit

Permalink
fixes #22613; Default value does not work with object's discriminator (
Browse files Browse the repository at this point in the history
…#22614)

* fixes #22613; Default value does not work with object's discriminator

fixes #22613

* merge branches

* add a test case

* fixes status

* remove outdated comments

* move collectBranchFields into the global scope
  • Loading branch information
ringabout committed Sep 1, 2023
1 parent 3b206ed commit affd3f7
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 24 deletions.
66 changes: 43 additions & 23 deletions compiler/semobjconstr.nim
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ proc locateFieldInInitExpr(c: PContext, field: PSym, initExpr: PNode): PNode =

proc semConstrField(c: PContext, flags: TExprFlags,
field: PSym, initExpr: PNode): PNode =
result = nil
let assignment = locateFieldInInitExpr(c, field, initExpr)
if assignment != nil:
if nfSem in assignment.flags: return assignment[1]
Expand All @@ -93,7 +92,9 @@ proc semConstrField(c: PContext, flags: TExprFlags,
assignment[0] = newSymNode(field)
assignment[1] = initValue
assignment.flags.incl nfSem
return initValue
result = initValue
else:
result = nil

proc branchVals(c: PContext, caseNode: PNode, caseIdx: int,
isStmtBranch: bool): IntSet =
Expand Down Expand Up @@ -192,6 +193,23 @@ proc collectOrAddMissingCaseFields(c: PContext, branchNode: PNode,
asgnExpr.typ = recTyp
defaults.add newTree(nkExprColonExpr, newSymNode(sym), asgnExpr)

proc collectBranchFields(c: PContext, n: PNode, discriminatorVal: PNode,
constrCtx: var ObjConstrContext, flags: TExprFlags) =
# All bets are off. If any of the branches has a mandatory
# fields we must produce an error:
for i in 1..<n.len:
let branchNode = n[i]
if branchNode != nil:
let oldCheckDefault = constrCtx.checkDefault
constrCtx.checkDefault = true
let (_, defaults) = semConstructFields(c, branchNode[^1], constrCtx, flags)
constrCtx.checkDefault = oldCheckDefault
if len(defaults) > 0:
localError(c.config, discriminatorVal.info, "branch initialization " &
"with a runtime discriminator is not supported " &
"for a branch whose fields have default values.")
discard collectMissingCaseFields(c, n[i], constrCtx, @[])

proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext,
flags: TExprFlags): tuple[status: InitStatus, defaults: seq[PNode]] =
result = (initUnknown, @[])
Expand Down Expand Up @@ -331,13 +349,27 @@ proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext,
discriminator.sym,
constrCtx.initExpr)
if discriminatorVal == nil:
# None of the branches were explicitly selected by the user and no
# value was given to the discrimator. We can assume that it will be
# initialized to zero and this will select a particular branch as
# a result:
let defaultValue = newIntLit(c.graph, constrCtx.initExpr.info, 0)
let matchedBranch = n.pickCaseBranch defaultValue
discard collectMissingCaseFields(c, matchedBranch, constrCtx, @[])
if discriminator.sym.ast != nil:
# branch is selected by the default field value of discriminator
let discriminatorDefaultVal = discriminator.sym.ast
result.status = initUnknown
result.defaults.add newTree(nkExprColonExpr, n[0], discriminatorDefaultVal)
if discriminatorDefaultVal.kind == nkIntLit:
let matchedBranch = n.pickCaseBranch discriminatorDefaultVal
if matchedBranch != nil:
let (_, defaults) = semConstructFields(c, matchedBranch[^1], constrCtx, flags)
result.defaults.add defaults
collectOrAddMissingCaseFields(c, matchedBranch, constrCtx, result.defaults)
else:
collectBranchFields(c, n, discriminatorDefaultVal, constrCtx, flags)
else:
# None of the branches were explicitly selected by the user and no
# value was given to the discrimator. We can assume that it will be
# initialized to zero and this will select a particular branch as
# a result:
let defaultValue = newIntLit(c.graph, constrCtx.initExpr.info, 0)
let matchedBranch = n.pickCaseBranch defaultValue
discard collectMissingCaseFields(c, matchedBranch, constrCtx, @[])
else:
result.status = initPartial
if discriminatorVal.kind == nkIntLit:
Expand All @@ -349,20 +381,8 @@ proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext,
result.defaults.add defaults
collectOrAddMissingCaseFields(c, matchedBranch, constrCtx, result.defaults)
else:
# All bets are off. If any of the branches has a mandatory
# fields we must produce an error:
for i in 1..<n.len:
let branchNode = n[i]
if branchNode != nil:
let oldCheckDefault = constrCtx.checkDefault
constrCtx.checkDefault = true
let (_, defaults) = semConstructFields(c, branchNode[^1], constrCtx, flags)
constrCtx.checkDefault = oldCheckDefault
if len(defaults) > 0:
localError(c.config, discriminatorVal.info, "branch initialization " &
"with a runtime discriminator is not supported " &
"for a branch whose fields have default values.")
discard collectMissingCaseFields(c, n[i], constrCtx, @[])
collectBranchFields(c, n, discriminatorVal, constrCtx, flags)

of nkSym:
let field = n.sym
let e = semConstrField(c, flags, field, constrCtx.initExpr)
Expand Down
17 changes: 16 additions & 1 deletion tests/objects/tobject_default_value.nim
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ template main {.dirty.} =
Red, Blue, Yellow

type
ObjectVarint3 = object # fixme it doesn't work with static
ObjectVarint3 = object
case kind: Color = Blue
of Red:
data1: int = 10
Expand Down Expand Up @@ -703,5 +703,20 @@ template main {.dirty.} =
var foo = new Container
doAssert int(foo.thing[0].x) == 1

block: # bug #22613
type
K = enum
A = "a"
B = "b"
T = object
case kind: K = B
of A:
a: int
of B:
b: float

doAssert T().kind == B


static: main()
main()

0 comments on commit affd3f7

Please sign in to comment.