fixes #11205
This commit is contained in:
parent
bcccc7dec8
commit
8bb1a6b041
4 changed files with 120 additions and 1 deletions
|
|
@ -1220,6 +1220,21 @@ proc genDiscriminantCheck(p: BProc, a, tmp: TLoc, objtype: PType,
|
||||||
[rdLoc(a), rdLoc(tmp), discriminatorTableName(p.module, t, field),
|
[rdLoc(a), rdLoc(tmp), discriminatorTableName(p.module, t, field),
|
||||||
intLiteral(L+1)])
|
intLiteral(L+1)])
|
||||||
|
|
||||||
|
proc genCaseObjDiscMapping(p: BProc, e: PNode, t: PType, field: PSym; d: var TLoc) =
|
||||||
|
const ObjDiscMappingProcSlot = -5
|
||||||
|
var theProc: PSym = nil
|
||||||
|
for idx, p in items(t.methods):
|
||||||
|
if idx == ObjDiscMappingProcSlot:
|
||||||
|
theProc = p
|
||||||
|
break
|
||||||
|
if theProc == nil:
|
||||||
|
theProc = genCaseObjDiscMapping(t, field, e.info, p.module.g.graph)
|
||||||
|
t.methods.add((ObjDiscMappingProcSlot, theProc))
|
||||||
|
var call = newNodeIT(nkCall, e.info, getSysType(p.module.g.graph, e.info, tyUInt8))
|
||||||
|
call.add newSymNode(theProc)
|
||||||
|
call.add e
|
||||||
|
expr(p, call, d)
|
||||||
|
|
||||||
proc asgnFieldDiscriminant(p: BProc, e: PNode) =
|
proc asgnFieldDiscriminant(p: BProc, e: PNode) =
|
||||||
var a, tmp: TLoc
|
var a, tmp: TLoc
|
||||||
var dotExpr = e.sons[0]
|
var dotExpr = e.sons[0]
|
||||||
|
|
@ -1227,7 +1242,17 @@ proc asgnFieldDiscriminant(p: BProc, e: PNode) =
|
||||||
initLocExpr(p, e.sons[0], a)
|
initLocExpr(p, e.sons[0], a)
|
||||||
getTemp(p, a.t, tmp)
|
getTemp(p, a.t, tmp)
|
||||||
expr(p, e.sons[1], tmp)
|
expr(p, e.sons[1], tmp)
|
||||||
genDiscriminantCheck(p, a, tmp, dotExpr.sons[0].typ, dotExpr.sons[1].sym)
|
let field = dotExpr.sons[1].sym
|
||||||
|
if optNimV2 in p.config.globalOptions:
|
||||||
|
let t = dotExpr[0].typ.skipTypes(abstractInst)
|
||||||
|
var oldVal, newVal: TLoc
|
||||||
|
genCaseObjDiscMapping(p, e[0], t, field, oldVal)
|
||||||
|
genCaseObjDiscMapping(p, e[1], t, field, newVal)
|
||||||
|
lineCg(p, cpsStmts,
|
||||||
|
"#nimFieldDiscriminantCheckV2($1, $2);$n",
|
||||||
|
[rdLoc(oldVal), rdLoc(newVal)])
|
||||||
|
else:
|
||||||
|
genDiscriminantCheck(p, a, tmp, dotExpr.sons[0].typ, field)
|
||||||
genAssignment(p, a, tmp, {})
|
genAssignment(p, a, tmp, {})
|
||||||
|
|
||||||
proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
|
proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
|
||||||
|
|
|
||||||
|
|
@ -40,3 +40,59 @@ proc genEnumToStrProc*(t: PType; info: TLineInfo; g: ModuleGraph): PSym =
|
||||||
n.sons[resultPos] = newSymNode(res)
|
n.sons[resultPos] = newSymNode(res)
|
||||||
result.ast = n
|
result.ast = n
|
||||||
incl result.flags, sfFromGeneric
|
incl result.flags, sfFromGeneric
|
||||||
|
|
||||||
|
proc searchObjCase(obj: PNode; field: PSym): PNode =
|
||||||
|
case obj.kind
|
||||||
|
of nkSym:
|
||||||
|
result = nil
|
||||||
|
of nkElse, nkOfBranch:
|
||||||
|
result = searchObjCase(obj.lastSon, field)
|
||||||
|
else:
|
||||||
|
if obj.kind == nkRecCase and obj[0].kind == nkSym and obj[0].sym == field:
|
||||||
|
result = obj
|
||||||
|
else:
|
||||||
|
for x in obj:
|
||||||
|
result = searchObjCase(x, field)
|
||||||
|
if result != nil: break
|
||||||
|
|
||||||
|
proc genCaseObjDiscMapping*(t: PType; field: PSym; info: TLineInfo; g: ModuleGraph): PSym =
|
||||||
|
result = newSym(skProc, getIdent(g.cache, "objDiscMapping"), t.owner, info)
|
||||||
|
|
||||||
|
let dest = newSym(skParam, getIdent(g.cache, "e"), result, info)
|
||||||
|
dest.typ = field.typ
|
||||||
|
|
||||||
|
let res = newSym(skResult, getIdent(g.cache, "result"), result, info)
|
||||||
|
res.typ = getSysType(g, info, tyUInt8)
|
||||||
|
|
||||||
|
result.typ = newType(tyProc, t.owner)
|
||||||
|
result.typ.n = newNodeI(nkFormalParams, info)
|
||||||
|
rawAddSon(result.typ, res.typ)
|
||||||
|
addSon(result.typ.n, newNodeI(nkEffectList, info))
|
||||||
|
|
||||||
|
result.typ.addParam dest
|
||||||
|
|
||||||
|
var body = newNodeI(nkStmtList, info)
|
||||||
|
var caseStmt = newNodeI(nkCaseStmt, info)
|
||||||
|
caseStmt.add(newSymNode dest)
|
||||||
|
|
||||||
|
let subObj = searchObjCase(t.n, field)
|
||||||
|
doAssert subObj != nil
|
||||||
|
for i in 1 ..< subObj.len:
|
||||||
|
let ofBranch = subObj[i]
|
||||||
|
var newBranch = newNodeI(ofBranch.kind, ofBranch.info)
|
||||||
|
for j in 0..ofBranch.len-2:
|
||||||
|
newBranch.add ofBranch[j]
|
||||||
|
|
||||||
|
newBranch.add newTree(nkStmtList, newTree(nkFastAsgn, newSymNode(res), newIntNode(nkInt8Lit, i)))
|
||||||
|
caseStmt.add newBranch
|
||||||
|
|
||||||
|
body.add(caseStmt)
|
||||||
|
|
||||||
|
var n = newNodeI(nkProcDef, info, bodyPos+2)
|
||||||
|
for i in 0 ..< n.len: n.sons[i] = newNodeI(nkEmpty, info)
|
||||||
|
n.sons[namePos] = newSymNode(result)
|
||||||
|
n.sons[paramsPos] = result.typ.n
|
||||||
|
n.sons[bodyPos] = body
|
||||||
|
n.sons[resultPos] = newSymNode(res)
|
||||||
|
result.ast = n
|
||||||
|
incl result.flags, sfFromGeneric
|
||||||
|
|
|
||||||
|
|
@ -114,3 +114,8 @@ when not defined(nimV2):
|
||||||
if x == nil: return false
|
if x == nil: return false
|
||||||
x = x.base
|
x = x.base
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
when defined(nimV2):
|
||||||
|
proc nimFieldDiscriminantCheckV2(oldDiscVal, newDiscVal: uint8) {.compilerProc.} =
|
||||||
|
if oldDiscVal != newDiscVal:
|
||||||
|
sysFatal(FieldError, "assignment to discriminant changes object branch")
|
||||||
|
|
|
||||||
33
tests/destructor/tcaseobj_transitions.nim
Normal file
33
tests/destructor/tcaseobj_transitions.nim
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
discard """
|
||||||
|
cmd: '''nim c --newruntime $file'''
|
||||||
|
output: '''no crash'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
# bug #11205
|
||||||
|
|
||||||
|
type
|
||||||
|
MyEnum = enum
|
||||||
|
A, B, C
|
||||||
|
MyCaseObject = object
|
||||||
|
case kind: MyEnum
|
||||||
|
of A: iseq: seq[int]
|
||||||
|
of B: fseq: seq[float]
|
||||||
|
of C: str: string
|
||||||
|
|
||||||
|
|
||||||
|
MyCaseObjectB = object # carefully constructed to use the same enum,
|
||||||
|
# but a different object type!
|
||||||
|
case kind: MyEnum
|
||||||
|
of A, C: x: int
|
||||||
|
of B: fseq: seq[float]
|
||||||
|
|
||||||
|
|
||||||
|
var x = MyCaseObject(kind: A)
|
||||||
|
x.iseq.add 1
|
||||||
|
#x.kind = B
|
||||||
|
#x.fseq.add -3.0
|
||||||
|
|
||||||
|
var y = MyCaseObjectB(kind: A)
|
||||||
|
y.x = 1
|
||||||
|
y.kind = C
|
||||||
|
echo "no crash"
|
||||||
Loading…
Add table
Add a link
Reference in a new issue