mirror of
https://github.com/nim-lang/Nim.git
synced 2026-07-19 07:21:19 +00:00
fixes #11205
This commit is contained in:
@@ -1220,6 +1220,21 @@ proc genDiscriminantCheck(p: BProc, a, tmp: TLoc, objtype: PType,
|
||||
[rdLoc(a), rdLoc(tmp), discriminatorTableName(p.module, t, field),
|
||||
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) =
|
||||
var a, tmp: TLoc
|
||||
var dotExpr = e.sons[0]
|
||||
@@ -1227,7 +1242,17 @@ proc asgnFieldDiscriminant(p: BProc, e: PNode) =
|
||||
initLocExpr(p, e.sons[0], a)
|
||||
getTemp(p, a.t, 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, {})
|
||||
|
||||
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)
|
||||
result.ast = n
|
||||
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
|
||||
x = x.base
|
||||
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"
|
||||
Reference in New Issue
Block a user