* fixes #21023; Segfault when mixing seqs, orc, variants and futures * fixes none of the branches were explicitly selected * add one more test * one more test
This commit is contained in:
parent
72e262666b
commit
0319824322
3 changed files with 136 additions and 18 deletions
|
|
@ -142,15 +142,45 @@ proc fieldsPresentInInitExpr(c: PContext, fieldsRecList, initExpr: PNode): strin
|
||||||
if result.len != 0: result.add ", "
|
if result.len != 0: result.add ", "
|
||||||
result.add field.sym.name.s.quoteStr
|
result.add field.sym.name.s.quoteStr
|
||||||
|
|
||||||
|
proc locateFieldInDefaults(sym: PSym, defaults: seq[PNode]): bool =
|
||||||
|
result = false
|
||||||
|
for d in defaults:
|
||||||
|
if sym.id == d[0].sym.id:
|
||||||
|
return true
|
||||||
|
|
||||||
proc collectMissingFields(c: PContext, fieldsRecList: PNode,
|
proc collectMissingFields(c: PContext, fieldsRecList: PNode,
|
||||||
constrCtx: var ObjConstrContext) =
|
constrCtx: var ObjConstrContext, defaults: seq[PNode]
|
||||||
for r in directFieldsInRecList(fieldsRecList):
|
): seq[PSym] =
|
||||||
if constrCtx.needsFullInit or
|
for r in directFieldsInRecList(fieldsRecList):
|
||||||
sfRequiresInit in r.sym.flags or
|
|
||||||
r.sym.typ.requiresInit:
|
|
||||||
let assignment = locateFieldInInitExpr(c, r.sym, constrCtx.initExpr)
|
let assignment = locateFieldInInitExpr(c, r.sym, constrCtx.initExpr)
|
||||||
if assignment == nil:
|
if assignment == nil and not locateFieldInDefaults(r.sym, defaults):
|
||||||
constrCtx.missingFields.add r.sym
|
if constrCtx.needsFullInit or
|
||||||
|
sfRequiresInit in r.sym.flags or
|
||||||
|
r.sym.typ.requiresInit:
|
||||||
|
constrCtx.missingFields.add r.sym
|
||||||
|
else:
|
||||||
|
result.add r.sym
|
||||||
|
|
||||||
|
proc collectMissingCaseFields(c: PContext, branchNode: PNode,
|
||||||
|
constrCtx: var ObjConstrContext, defaults: seq[PNode]): seq[PSym] =
|
||||||
|
if branchNode != nil:
|
||||||
|
let fieldsRecList = branchNode[^1]
|
||||||
|
result = collectMissingFields(c, fieldsRecList, constrCtx, defaults)
|
||||||
|
|
||||||
|
proc collectOrAddMissingCaseFields(c: PContext, branchNode: PNode,
|
||||||
|
constrCtx: var ObjConstrContext, defaults: var seq[PNode]) =
|
||||||
|
let res = collectMissingCaseFields(c, branchNode, constrCtx, defaults)
|
||||||
|
for sym in res:
|
||||||
|
let asgnType = newType(tyTypeDesc, nextTypeId(c.idgen), sym.typ.owner)
|
||||||
|
let recTyp = sym.typ.skipTypes(defaultFieldsSkipTypes)
|
||||||
|
rawAddSon(asgnType, recTyp)
|
||||||
|
let asgnExpr = newTree(nkCall,
|
||||||
|
newSymNode(getSysMagic(c.graph, constrCtx.initExpr.info, "zeroDefault", mZeroDefault)),
|
||||||
|
newNodeIT(nkType, constrCtx.initExpr.info, asgnType)
|
||||||
|
)
|
||||||
|
asgnExpr.flags.incl nfUseDefaultField
|
||||||
|
asgnExpr.typ = recTyp
|
||||||
|
defaults.add newTree(nkExprColonExpr, newSymNode(sym), asgnExpr)
|
||||||
|
|
||||||
proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext,
|
proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext,
|
||||||
flags: TExprFlags): tuple[status: InitStatus, defaults: seq[PNode]] =
|
flags: TExprFlags): tuple[status: InitStatus, defaults: seq[PNode]] =
|
||||||
|
|
@ -166,11 +196,6 @@ proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext,
|
||||||
let fields = branch[^1]
|
let fields = branch[^1]
|
||||||
fieldsPresentInInitExpr(c, fields, constrCtx.initExpr)
|
fieldsPresentInInitExpr(c, fields, constrCtx.initExpr)
|
||||||
|
|
||||||
template collectMissingFields(branchNode: PNode) =
|
|
||||||
if branchNode != nil:
|
|
||||||
let fields = branchNode[^1]
|
|
||||||
collectMissingFields(c, fields, constrCtx)
|
|
||||||
|
|
||||||
let discriminator = n[0]
|
let discriminator = n[0]
|
||||||
internalAssert c.config, discriminator.kind == nkSym
|
internalAssert c.config, discriminator.kind == nkSym
|
||||||
var selectedBranch = -1
|
var selectedBranch = -1
|
||||||
|
|
@ -288,8 +313,7 @@ proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext,
|
||||||
# When a branch is selected with a partial match, some of the fields
|
# When a branch is selected with a partial match, some of the fields
|
||||||
# that were not initialized may be mandatory. We must check for this:
|
# that were not initialized may be mandatory. We must check for this:
|
||||||
if result.status == initPartial:
|
if result.status == initPartial:
|
||||||
collectMissingFields branchNode
|
collectOrAddMissingCaseFields(c, branchNode, constrCtx, result.defaults)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
result.status = initNone
|
result.status = initNone
|
||||||
let discriminatorVal = semConstrField(c, flags + {efPreferStatic},
|
let discriminatorVal = semConstrField(c, flags + {efPreferStatic},
|
||||||
|
|
@ -302,7 +326,7 @@ proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext,
|
||||||
# a result:
|
# a result:
|
||||||
let defaultValue = newIntLit(c.graph, constrCtx.initExpr.info, 0)
|
let defaultValue = newIntLit(c.graph, constrCtx.initExpr.info, 0)
|
||||||
let matchedBranch = n.pickCaseBranch defaultValue
|
let matchedBranch = n.pickCaseBranch defaultValue
|
||||||
collectMissingFields matchedBranch
|
discard collectMissingCaseFields(c, matchedBranch, constrCtx, @[])
|
||||||
else:
|
else:
|
||||||
result.status = initPartial
|
result.status = initPartial
|
||||||
if discriminatorVal.kind == nkIntLit:
|
if discriminatorVal.kind == nkIntLit:
|
||||||
|
|
@ -312,11 +336,12 @@ proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext,
|
||||||
if matchedBranch != nil:
|
if matchedBranch != nil:
|
||||||
let (_, defaults) = semConstructFields(c, matchedBranch[^1], constrCtx, flags)
|
let (_, defaults) = semConstructFields(c, matchedBranch[^1], constrCtx, flags)
|
||||||
result.defaults.add defaults
|
result.defaults.add defaults
|
||||||
collectMissingFields matchedBranch
|
collectOrAddMissingCaseFields(c, matchedBranch, constrCtx, result.defaults)
|
||||||
else:
|
else:
|
||||||
# All bets are off. If any of the branches has a mandatory
|
# All bets are off. If any of the branches has a mandatory
|
||||||
# fields we must produce an error:
|
# fields we must produce an error:
|
||||||
for i in 1..<n.len: collectMissingFields n[i]
|
for i in 1..<n.len:
|
||||||
|
discard collectMissingCaseFields(c, n[i], constrCtx, @[])
|
||||||
of nkSym:
|
of nkSym:
|
||||||
let field = n.sym
|
let field = n.sym
|
||||||
let e = semConstrField(c, flags, field, constrCtx.initExpr)
|
let e = semConstrField(c, flags, field, constrCtx.initExpr)
|
||||||
|
|
@ -348,7 +373,7 @@ proc semConstructTypeAux(c: PContext,
|
||||||
result.status.mergeInitStatus status
|
result.status.mergeInitStatus status
|
||||||
result.defaults.add defaults
|
result.defaults.add defaults
|
||||||
if status in {initPartial, initNone, initUnknown}:
|
if status in {initPartial, initNone, initUnknown}:
|
||||||
collectMissingFields c, t.n, constrCtx
|
discard collectMissingFields(c, t.n, constrCtx, result.defaults)
|
||||||
let base = t[0]
|
let base = t[0]
|
||||||
if base == nil: break
|
if base == nil: break
|
||||||
t = skipTypes(base, skipPtrs)
|
t = skipTypes(base, skipPtrs)
|
||||||
|
|
|
||||||
|
|
@ -269,3 +269,64 @@ proc bug20305 =
|
||||||
echo x.pChildren
|
echo x.pChildren
|
||||||
|
|
||||||
bug20305()
|
bug20305()
|
||||||
|
|
||||||
|
# bug #21023
|
||||||
|
block:
|
||||||
|
block:
|
||||||
|
type
|
||||||
|
MGErrorKind = enum
|
||||||
|
mgeUnexpected, mgeNotFound
|
||||||
|
|
||||||
|
type Foo = object
|
||||||
|
kind: MGErrorKind
|
||||||
|
ex: Exception
|
||||||
|
|
||||||
|
type Boo = object
|
||||||
|
a: seq[int]
|
||||||
|
|
||||||
|
type
|
||||||
|
Result2 = object
|
||||||
|
case o: bool
|
||||||
|
of false:
|
||||||
|
e: Foo
|
||||||
|
of true:
|
||||||
|
v: Boo
|
||||||
|
|
||||||
|
proc startSessionSync(): Result2 =
|
||||||
|
return Result2(o: true)
|
||||||
|
|
||||||
|
proc mainSync =
|
||||||
|
let ff = startSessionSync()
|
||||||
|
doAssert ff.o == true
|
||||||
|
|
||||||
|
mainSync()
|
||||||
|
|
||||||
|
block:
|
||||||
|
type
|
||||||
|
MGErrorKind = enum
|
||||||
|
mgeUnexpected, mgeNotFound
|
||||||
|
|
||||||
|
type Foo = object
|
||||||
|
kind: MGErrorKind
|
||||||
|
ex: Exception
|
||||||
|
|
||||||
|
type Boo = object
|
||||||
|
a: seq[int]
|
||||||
|
|
||||||
|
type
|
||||||
|
Result2 = object
|
||||||
|
case o: bool
|
||||||
|
of false:
|
||||||
|
e: Foo
|
||||||
|
of true:
|
||||||
|
v: Boo
|
||||||
|
s: int
|
||||||
|
|
||||||
|
proc startSessionSync(): Result2 =
|
||||||
|
return Result2(o: true, s: 12)
|
||||||
|
|
||||||
|
proc mainSync =
|
||||||
|
let ff = startSessionSync()
|
||||||
|
doAssert ff.s == 12
|
||||||
|
|
||||||
|
mainSync()
|
||||||
|
|
|
||||||
|
|
@ -559,6 +559,38 @@ template main {.dirty.} =
|
||||||
let x = default(Default)
|
let x = default(Default)
|
||||||
doAssert x.data is DjangoDateTime
|
doAssert x.data is DjangoDateTime
|
||||||
|
|
||||||
|
block:
|
||||||
|
type
|
||||||
|
Result2 = object
|
||||||
|
case o: bool
|
||||||
|
of false:
|
||||||
|
e: float
|
||||||
|
of true:
|
||||||
|
v {.requiresInit.} : int = 1
|
||||||
|
|
||||||
|
proc startSessionSync(): Result2 =
|
||||||
|
return Result2(o: true)
|
||||||
|
|
||||||
|
proc mainSync =
|
||||||
|
let ff = startSessionSync()
|
||||||
|
doAssert ff.v == 1
|
||||||
|
|
||||||
|
mainSync()
|
||||||
|
|
||||||
|
block:
|
||||||
|
type
|
||||||
|
Result2 = object
|
||||||
|
v {.requiresInit.} : int = 1
|
||||||
|
|
||||||
|
proc startSessionSync(): Result2 =
|
||||||
|
return Result2()
|
||||||
|
|
||||||
|
proc mainSync =
|
||||||
|
let ff = startSessionSync()
|
||||||
|
doAssert ff.v == 1
|
||||||
|
|
||||||
|
mainSync()
|
||||||
|
|
||||||
|
|
||||||
static: main()
|
static: main()
|
||||||
main()
|
main()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue