destructors: lift type bound operations for case and distinct objects (#10238)

This commit is contained in:
cooldome 2019-01-10 08:25:35 +00:00 • committed by Andreas Rumpf
commit 44b4e289d6
2 changed files with 92 additions and 27 deletions

View file

@ -49,6 +49,14 @@ proc liftBodyObj(c: var TLiftCtx; n, body, x, y: PNode) =
liftBodyAux(c, f.typ, body, x.dotField(f), y.dotField(f)) liftBodyAux(c, f.typ, body, x.dotField(f), y.dotField(f))
of nkNilLit: discard of nkNilLit: discard
of nkRecCase: of nkRecCase:
if c.kind in {attachedSink, attachedAsgn, attachedDeepCopy}:
## the value needs to be destroyed before we assign the selector
## or the value is lost
let prevKind = c.kind
c.kind = attachedDestructor
liftBodyObj(c, n, body, x, y)
c.kind = prevKind
# copy the selector: # copy the selector:
liftBodyObj(c, n[0], body, x, y) liftBodyObj(c, n[0], body, x, y)
# we need to generate a case statement: # we need to generate a case statement:
@ -66,7 +74,6 @@ proc liftBodyObj(c: var TLiftCtx; n, body, x, y: PNode) =
liftBodyObj(c, n[i].lastSon, branch.sons[L-1], x, y) liftBodyObj(c, n[i].lastSon, branch.sons[L-1], x, y)
caseStmt.add(branch) caseStmt.add(branch)
body.add(caseStmt) body.add(caseStmt)
localError(c.c.config, c.info, "cannot lift assignment operator to 'case' object")
of nkRecList: of nkRecList:
for t in items(n): liftBodyObj(c, t, body, x, y) for t in items(n): liftBodyObj(c, t, body, x, y)
else: else:
@ -235,11 +242,12 @@ proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) =
discard considerOverloadedOp(c, t, body, x, y) discard considerOverloadedOp(c, t, body, x, y)
else: else:
defaultOp(c, t, body, x, y) defaultOp(c, t, body, x, y)
of tyObject, tyDistinct: of tyObject:
if not considerOverloadedOp(c, t, body, x, y):
liftBodyObj(c, t.n, body, x, y)
of tyDistinct:
if not considerOverloadedOp(c, t, body, x, y): if not considerOverloadedOp(c, t, body, x, y):
if t.sons[0] != nil:
liftBodyAux(c, t.sons[0].skipTypes(skipPtrs), body, x, y) liftBodyAux(c, t.sons[0].skipTypes(skipPtrs), body, x, y)
if t.kind == tyObject: liftBodyObj(c, t.n, body, x, y)
of tyTuple: of tyTuple:
liftBodyTup(c, t, body, x, y) liftBodyTup(c, t, body, x, y)
of tyProc: of tyProc:
@ -279,8 +287,36 @@ proc addParam(procType: PType; param: PSym) =
addSon(procType.n, newSymNode(param)) addSon(procType.n, newSymNode(param))
rawAddSon(procType, param.typ) rawAddSon(procType, param.typ)
proc liftBodyDistinctType(c: PContext; typ: PType; kind: TTypeAttachedOp; info: TLineInfo): PSym =
assert typ.kind == tyDistinct
let baseType = typ[0]
case kind
of attachedAsgn:
if baseType.assignment == nil:
discard liftBody(c, baseType, kind, info)
typ.assignment = baseType.assignment
result = typ.assignment
of attachedSink:
if baseType.sink == nil:
discard liftBody(c, baseType, kind, info)
typ.sink = baseType.sink
result = typ.sink
of attachedDeepCopy:
if baseType.deepCopy == nil:
discard liftBody(c, baseType, kind, info)
typ.deepCopy = baseType.deepCopy
result = typ.deepCopy
of attachedDestructor:
if baseType.destructor == nil:
discard liftBody(c, baseType, kind, info)
typ.destructor = baseType.destructor
result = typ.destructor
proc liftBody(c: PContext; typ: PType; kind: TTypeAttachedOp; proc liftBody(c: PContext; typ: PType; kind: TTypeAttachedOp;
info: TLineInfo): PSym = info: TLineInfo): PSym =
if typ.kind == tyDistinct:
return liftBodyDistinctType(c, typ, kind, info)
var a: TLiftCtx var a: TLiftCtx
a.info = info a.info = info
a.c = c a.c = c

View file

@ -7,21 +7,28 @@ mygeneric1 constructed
mygeneric1 destroyed mygeneric1 destroyed
---- ----
mygeneric2 constructed mygeneric2 constructed
mygeneric2 destroyed
myobj destroyed myobj destroyed
mygeneric2 destroyed
---- ----
mygeneric3 constructed mygeneric3 constructed
mygeneric1 destroyed mygeneric1 destroyed
---- ----
mygeneric1 destroyed mydistinctObj constructed
myobj destroyed
mygeneric2 destroyed
------------------
----
---- ----
myobj destroyed myobj destroyed
---- mygeneric1 destroyed
---- myobj destroyed
myobj destroyed
myobj destroyed
---
myobj destroyed
myobj destroyed
myobj destroyed myobj destroyed
''' '''
cmd: '''nim c --newruntime $file'''
disabled: "true"
""" """
type type
@ -29,6 +36,11 @@ type
x, y: int x, y: int
p: pointer p: pointer
proc `=destroy`(o: var TMyObj) =
if o.p != nil: dealloc o.p
echo "myobj destroyed"
type
TMyGeneric1[T] = object TMyGeneric1[T] = object
x: T x: T
@ -36,37 +48,40 @@ type
x: A x: A
y: B y: B
proc `=destroy`(o: var TMyGeneric1[int]) =
echo "mygeneric1 destroyed"
proc `=destroy`[A, B](o: var TMyGeneric2[A, B]) =
echo "mygeneric2 destroyed"
type
TMyGeneric3[A, B, C] = object TMyGeneric3[A, B, C] = object
x: A x: A
y: B y: B
z: C z: C
TObjKind = enum A, B, C, D TDistinctObjX = distinct TMyGeneric3[TMyObj, TMyGeneric2[int, int], int]
TDistinctObj = TDistinctObjX
TObjKind = enum Z, A, B, C, D
TCaseObj = object TCaseObj = object
z: TMyGeneric3[TMyObj, float, int]
case kind: TObjKind case kind: TObjKind
of Z: discard
of A: of A:
x: TMyGeneric1[int] x: TMyGeneric1[int]
of B, C: of B, C:
y: TMyObj y: TMyObj
else: else:
case innerKind: TObjKind case innerKind: TObjKind
of Z: discard
of A, B, C: of A, B, C:
p: TMyGeneric3[int, float, string] p: TMyGeneric3[int, float, string]
of D: of D:
q: TMyGeneric3[TMyObj, int, int] q: TMyGeneric3[TMyObj, int, int]
r: string r: string
proc `=destroy`(o: var TMyObj) =
if o.p != nil: dealloc o.p
echo "myobj destroyed"
proc `=destroy`(o: var TMyGeneric1[int]) =
echo "mygeneric1 destroyed"
proc `=destroy`[A, B](o: var TMyGeneric2[A, B]) =
echo "mygeneric2 destroyed"
proc open: TMyObj = proc open: TMyObj =
# allow for superfluous () # allow for superfluous ()
result = (TMyObj(x: 1, y: 2, p: alloc(3))) result = (TMyObj(x: 1, y: 2, p: alloc(3)))
@ -95,6 +110,12 @@ proc mygeneric3 =
echo "mygeneric3 constructed" echo "mygeneric3 constructed"
proc mydistinctObj =
var x = TMyGeneric3[TMyObj, TMyGeneric2[int, int], int](
x: open(), y: TMyGeneric2[int, int](x: 5, y: 15), z: 20)
echo "mydistinctObj constructed"
echo "----" echo "----"
myobj() myobj()
@ -107,9 +128,11 @@ mygeneric2[int](10)
echo "----" echo "----"
mygeneric3() mygeneric3()
echo "----"
mydistinctObj()
proc caseobj = proc caseobj =
block: block:
echo "----"
var o1 = TCaseObj(kind: A, x: TMyGeneric1[int](x: 10)) var o1 = TCaseObj(kind: A, x: TMyGeneric1[int](x: 10))
block: block:
@ -121,10 +144,16 @@ proc caseobj =
var o3 = TCaseObj(kind: D, innerKind: B, r: "test", var o3 = TCaseObj(kind: D, innerKind: B, r: "test",
p: TMyGeneric3[int, float, string](x: 10, y: 1.0, z: "test")) p: TMyGeneric3[int, float, string](x: 10, y: 1.0, z: "test"))
block:
echo "----"
var o4 = TCaseObj(kind: D, innerKind: D, r: "test",
q: TMyGeneric3[TMyObj, int, int](x: open(), y: 1, z: 0))
echo "------------------"
caseobj() caseobj()
proc caseobj_test_sink: TCaseObj =
# check that lifted sink can destroy case val correctly
result = TCaseObj(kind: D, innerKind: D, r: "test",
q: TMyGeneric3[TMyObj, int, int](x: open(), y: 1, z: 0))
result = TCaseObj(kind: B, y: open())
echo "---"
discard caseobj_test_sink()