16
16
import modulegraphs, lineinfos, idents, ast, renderer, semdata,
17
17
sighashes, lowerings, options, types, msgs, magicsys, tables
18
18
19
+ from trees import isCaseObj
20
+
19
21
type
20
22
TLiftCtx = object
21
23
g: ModuleGraph
@@ -62,28 +64,45 @@ proc defaultOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
62
64
if c.kind in {attachedAsgn, attachedDeepCopy, attachedSink}:
63
65
body.add newAsgnStmt(x, y)
64
66
65
- proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode) =
67
+ proc genAddr(g: ModuleGraph; x: PNode): PNode =
68
+ if x.kind == nkHiddenDeref:
69
+ checkSonsLen(x, 1 , g.config)
70
+ result = x[0 ]
71
+ else :
72
+ result = newNodeIT(nkHiddenAddr, x.info, makeVarType(x.typ.owner, x.typ))
73
+ result .add x
74
+
75
+ proc destructorCall(g: ModuleGraph; op: PSym; x: PNode): PNode =
76
+ result = newNodeIT(nkCall, x.info, op.typ[0 ])
77
+ result .add(newSymNode(op))
78
+ result .add genAddr(g, x)
79
+
80
+ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool ) =
66
81
case n.kind
67
82
of nkSym:
68
83
let f = n.sym
69
84
let b = if c.kind == attachedTrace: y else : y.dotField(f)
70
- if sfCursor in f.flags and f.typ.skipTypes(abstractInst).kind in {tyRef, tyProc} and
71
- c.g.config.selectedGC in {gcArc, gcOrc, gcHooks}:
85
+ if (sfCursor in f.flags and f.typ.skipTypes(abstractInst).kind in {tyRef, tyProc} and
86
+ c.g.config.selectedGC in {gcArc, gcOrc, gcHooks}) or
87
+ enforceDefaultOp:
72
88
defaultOp(c, f.typ, body, x.dotField(f), b)
73
89
else :
74
90
fillBody(c, f.typ, body, x.dotField(f), b)
75
91
of nkNilLit: discard
76
92
of nkRecCase:
77
- if c.kind in {attachedSink, attachedAsgn, attachedDeepCopy}:
93
+ # XXX This is only correct for 'attachedSink'!
94
+ var localEnforceDefaultOp = enforceDefaultOp
95
+ if c.kind == attachedSink:
78
96
# # the value needs to be destroyed before we assign the selector
79
97
# # or the value is lost
80
98
let prevKind = c.kind
81
99
c.kind = attachedDestructor
82
- fillBodyObj(c, n, body, x, y)
100
+ fillBodyObj(c, n, body, x, y, enforceDefaultOp = false )
83
101
c.kind = prevKind
102
+ localEnforceDefaultOp = true
84
103
85
104
# copy the selector:
86
- fillBodyObj(c, n[0 ], body, x, y)
105
+ fillBodyObj(c, n[0 ], body, x, y, enforceDefaultOp = false )
87
106
# we need to generate a case statement:
88
107
var caseStmt = newNodeI(nkCaseStmt, c.info)
89
108
# XXX generate 'if' that checks same branches
@@ -96,28 +115,69 @@ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode) =
96
115
var branch = copyTree(n[i])
97
116
branch[^ 1 ] = newNodeI(nkStmtList, c.info)
98
117
99
- fillBodyObj(c, n[i].lastSon, branch[^ 1 ], x, y)
118
+ fillBodyObj(c, n[i].lastSon, branch[^ 1 ], x, y,
119
+ enforceDefaultOp = localEnforceDefaultOp)
100
120
if branch[^ 1 ].len == 0 : inc emptyBranches
101
121
caseStmt.add(branch)
102
122
if emptyBranches != n.len- 1 :
103
123
body.add(caseStmt)
104
124
of nkRecList:
105
- for t in items(n): fillBodyObj(c, t, body, x, y)
125
+ for t in items(n): fillBodyObj(c, t, body, x, y, enforceDefaultOp )
106
126
else :
107
127
illFormedAstLocal(n, c.g.config)
108
128
109
- proc fillBodyObjT (c: var TLiftCtx; t: PType, body, x, y: PNode) =
129
+ proc fillBodyObjTImpl (c: var TLiftCtx; t: PType, body, x, y: PNode) =
110
130
if t.len > 0 and t[0 ] != nil :
111
- fillBodyObjT (c, skipTypes(t[0 ], abstractPtrs), body, x, y)
112
- fillBodyObj(c, t.n, body, x, y)
131
+ fillBodyObjTImpl (c, skipTypes(t[0 ], abstractPtrs), body, x, y)
132
+ fillBodyObj(c, t.n, body, x, y, enforceDefaultOp = false )
113
133
114
- proc genAddr(g: ModuleGraph; x: PNode): PNode =
115
- if x.kind == nkHiddenDeref:
116
- checkSonsLen(x, 1 , g.config)
117
- result = x[0 ]
134
+ proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) =
135
+ var hasCase = isCaseObj(t.n)
136
+ var obj = t
137
+ while obj.len > 0 and obj[0 ] != nil :
138
+ obj = skipTypes(obj[0 ], abstractPtrs)
139
+ hasCase = hasCase or isCaseObj(obj.n)
140
+
141
+ if hasCase and c.kind in {attachedAsgn, attachedDeepCopy}:
142
+ # assignment for case objects is complex, we do:
143
+ # =destroy(dest)
144
+ # wasMoved(dest)
145
+ # for every field:
146
+ # `=` dest.field, src.field
147
+ # ^ this is what we used to do, but for 'result = result.sons[0]' it
148
+ # destroys 'result' too early.
149
+ # So this is what we really need to do:
150
+ # let blob {.cursor.} = dest # remembers the old dest.kind
151
+ # wasMoved(dest)
152
+ # dest.kind = src.kind
153
+ # for every field (dependent on dest.kind):
154
+ # `=` dest.field, src.field
155
+ # =destroy(blob)
156
+ var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.fn, c.info)
157
+ temp.typ = x.typ
158
+ incl(temp.flags, sfFromGeneric)
159
+ var v = newNodeI(nkVarSection, c.info)
160
+ let blob = newSymNode(temp)
161
+ v.addVar(blob, x)
162
+ body.add v
163
+ # body.add newAsgnStmt(blob, x)
164
+
165
+ var wasMovedCall = newNodeI(nkCall, c.info)
166
+ wasMovedCall.add(newSymNode(createMagic(c.g, " wasMoved" , mWasMoved)))
167
+ wasMovedCall.add x # mWasMoved does not take the address
168
+ body.add wasMovedCall
169
+
170
+ fillBodyObjTImpl(c, t, body, x, y)
171
+ when false :
172
+ # does not work yet due to phase-ordering problems:
173
+ assert t.destructor != nil
174
+ body.add destructorCall(c.g, t.destructor, blob)
175
+ let prevKind = c.kind
176
+ c.kind = attachedDestructor
177
+ fillBodyObjTImpl(c, t, body, blob, y)
178
+ c.kind = prevKind
118
179
else :
119
- result = newNodeIT(nkHiddenAddr, x.info, makeVarType(x.typ.owner, x.typ))
120
- result .add x
180
+ fillBodyObjTImpl(c, t, body, x, y)
121
181
122
182
proc newHookCall(g: ModuleGraph; op: PSym; x, y: PNode): PNode =
123
183
# if sfError in op.flags:
@@ -136,11 +196,6 @@ proc newOpCall(op: PSym; x: PNode): PNode =
136
196
result .add(newSymNode(op))
137
197
result .add x
138
198
139
- proc destructorCall(g: ModuleGraph; op: PSym; x: PNode): PNode =
140
- result = newNodeIT(nkCall, x.info, op.typ[0 ])
141
- result .add(newSymNode(op))
142
- result .add genAddr(g, x)
143
-
144
199
proc newDeepCopyCall(op: PSym; x, y: PNode): PNode =
145
200
result = newAsgnStmt(x, newOpCall(op, y))
146
201
0 commit comments