ARC related bugfixes and refactorings (#12781)
This commit is contained in:
parent
9b0e874687
commit
3fbb3bfd3f
11 changed files with 381 additions and 367 deletions
|
|
@ -170,6 +170,7 @@ proc genOp(c: Con; t: PType; kind: TTypeAttachedOp; dest, ri: PNode): PNode =
|
|||
op = canon.attachedOps[kind]
|
||||
|
||||
if op == nil:
|
||||
#echo dest.typ.id
|
||||
globalError(c.graph.config, dest.info, "internal error: '" & AttachedOpToStr[kind] &
|
||||
"' operator not found for type " & typeToString(t))
|
||||
elif op.ast[genericParamsPos].kind != nkEmpty:
|
||||
|
|
@ -250,22 +251,25 @@ proc destructiveMoveVar(n: PNode; c: var Con): PNode =
|
|||
# generate: (let tmp = v; reset(v); tmp)
|
||||
# XXX: Strictly speaking we can only move if there is a ``=sink`` defined
|
||||
# or if no ``=sink`` is defined and also no assignment.
|
||||
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
|
||||
if not hasDestructor(n.typ):
|
||||
result = copyTree(n)
|
||||
else:
|
||||
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
|
||||
|
||||
var temp = newSym(skLet, getIdent(c.graph.cache, "blitTmp"), c.owner, n.info)
|
||||
temp.typ = n.typ
|
||||
var v = newNodeI(nkLetSection, n.info)
|
||||
let tempAsNode = newSymNode(temp)
|
||||
var temp = newSym(skLet, getIdent(c.graph.cache, "blitTmp"), c.owner, n.info)
|
||||
temp.typ = n.typ
|
||||
var v = newNodeI(nkLetSection, n.info)
|
||||
let tempAsNode = newSymNode(temp)
|
||||
|
||||
var vpart = newNodeI(nkIdentDefs, tempAsNode.info, 3)
|
||||
vpart[0] = tempAsNode
|
||||
vpart[1] = c.emptyNode
|
||||
vpart[2] = n
|
||||
v.add(vpart)
|
||||
var vpart = newNodeI(nkIdentDefs, tempAsNode.info, 3)
|
||||
vpart[0] = tempAsNode
|
||||
vpart[1] = c.emptyNode
|
||||
vpart[2] = n
|
||||
v.add(vpart)
|
||||
|
||||
result.add v
|
||||
result.add genWasMoved(skipConv(n), c)
|
||||
result.add tempAsNode
|
||||
result.add v
|
||||
result.add genWasMoved(skipConv(n), c)
|
||||
result.add tempAsNode
|
||||
|
||||
proc sinkParamIsLastReadCheck(c: var Con, s: PNode) =
|
||||
assert s.kind == nkSym and s.sym.kind == skParam
|
||||
|
|
@ -273,8 +277,12 @@ proc sinkParamIsLastReadCheck(c: var Con, s: PNode) =
|
|||
localError(c.graph.config, c.otherRead.info, "sink parameter `" & $s.sym.name.s &
|
||||
"` is already consumed at " & toFileLineCol(c. graph.config, s.info))
|
||||
|
||||
proc p(n: PNode; c: var Con; consumed = false): PNode
|
||||
proc pArg(arg: PNode; c: var Con; isSink: bool): PNode
|
||||
type ProcessMode = enum
|
||||
normal
|
||||
consumed
|
||||
sinkArg
|
||||
|
||||
proc p(n: PNode; c: var Con; mode: ProcessMode = normal): PNode
|
||||
proc moveOrCopy(dest, ri: PNode; c: var Con): PNode
|
||||
|
||||
proc isClosureEnv(n: PNode): bool = n.kind == nkSym and n.sym.name.s[0] == ':'
|
||||
|
|
@ -366,6 +374,10 @@ template handleNested(n: untyped, processCall: untyped) =
|
|||
branch.add if node.typ == nil: p(node, c) #noreturn
|
||||
else: processCall
|
||||
result.add branch
|
||||
of nkWhen: # This should be a "when nimvm" node.
|
||||
result = copyTree(n)
|
||||
template node: untyped = n[1][0]
|
||||
result[1][0] = processCall
|
||||
else: assert(false)
|
||||
|
||||
proc ensureDestruction(arg: PNode; c: var Con): PNode =
|
||||
|
|
@ -384,75 +396,6 @@ proc ensureDestruction(arg: PNode; c: var Con): PNode =
|
|||
else:
|
||||
result = arg
|
||||
|
||||
proc pArg(arg: PNode; c: var Con; isSink: bool): PNode =
|
||||
if isSink:
|
||||
if arg.kind in nkCallKinds:
|
||||
# recurse but skip the call expression in order to prevent
|
||||
# destructor injections: Rule 5.1 is different from rule 5.4!
|
||||
result = copyNode(arg)
|
||||
let parameters = arg[0].typ
|
||||
let L = if parameters != nil: parameters.len else: 0
|
||||
result.add pArg(arg[0], c, isSink = false)
|
||||
for i in 1..<arg.len:
|
||||
result.add pArg(arg[i], c, i < L and isSinkTypeForParam(parameters[i]))
|
||||
elif arg.containsConstSeq:
|
||||
# const sequences are not mutable and so we need to pass a copy to the
|
||||
# sink parameter (bug #11524). Note that the string implementation is
|
||||
# different and can deal with 'const string sunk into var'.
|
||||
result = passCopyToSink(arg, c)
|
||||
elif arg.kind in nkLiterals:
|
||||
# literals are save to share accross ASTs (for now!)
|
||||
result = arg # literal to sink parameter: nothing to do
|
||||
elif arg.kind in {nkBracket, nkObjConstr, nkTupleConstr, nkClosure}:
|
||||
# object construction to sink parameter: nothing to do
|
||||
result = copyTree(arg)
|
||||
for i in ord(arg.kind in {nkObjConstr, nkClosure})..<arg.len:
|
||||
if arg[i].kind == nkExprColonExpr:
|
||||
result[i][1] = pArg(arg[i][1], c, isSink = true)
|
||||
else:
|
||||
result[i] = pArg(arg[i], c, isSink = true)
|
||||
#if arg.kind == nkClosure:
|
||||
# result = handleClosureCall(result, c)
|
||||
# Not required here because the nkClosure will be consumed!
|
||||
elif arg.kind == nkSym and isSinkParam(arg.sym):
|
||||
# Sinked params can be consumed only once. We need to reset the memory
|
||||
# to disable the destructor which we have not elided
|
||||
sinkParamIsLastReadCheck(c, arg)
|
||||
result = destructiveMoveVar(arg, c)
|
||||
elif isAnalysableFieldAccess(arg, c.owner) and isLastRead(arg, c):
|
||||
# it is the last read, can be sinked. We need to reset the memory
|
||||
# to disable the destructor which we have not elided
|
||||
result = destructiveMoveVar(arg, c)
|
||||
elif arg.kind in {nkStmtListExpr, nkBlockExpr, nkBlockStmt, nkIfExpr, nkIfStmt, nkCaseStmt}:
|
||||
handleNested(arg): pArg(node, c, isSink)
|
||||
elif arg.kind in {nkHiddenSubConv, nkHiddenStdConv, nkConv}:
|
||||
result = copyTree(arg)
|
||||
result[1] = pArg(arg[1], c, isSink = true)
|
||||
elif arg.kind in {nkObjDownConv, nkObjUpConv}:
|
||||
result = copyTree(arg)
|
||||
result[0] = pArg(arg[0], c, isSink = true)
|
||||
else:
|
||||
# an object that is not temporary but passed to a 'sink' parameter
|
||||
# results in a copy.
|
||||
result = passCopyToSink(arg, c)
|
||||
elif arg.kind == nkBracket:
|
||||
# Treat `f([...])` like `f(...)`
|
||||
result = copyNode(arg)
|
||||
for son in arg:
|
||||
result.add pArg(son, c, isSinkTypeForParam(son.typ))
|
||||
elif arg.kind in nkCallKinds and arg.typ != nil and hasDestructor(arg.typ):
|
||||
# produce temp creation
|
||||
result = newNodeIT(nkStmtListExpr, arg.info, arg.typ)
|
||||
let tmp = getTemp(c, arg.typ, arg.info)
|
||||
let res = p(arg, c)
|
||||
var sinkExpr = genSink(c, tmp, res)
|
||||
sinkExpr.add res
|
||||
result.add sinkExpr
|
||||
result.add tmp
|
||||
c.destroys.add genDestroy(c, tmp)
|
||||
else:
|
||||
result = p(arg, c)
|
||||
|
||||
proc isCursor(n: PNode): bool =
|
||||
case n.kind
|
||||
of nkSym:
|
||||
|
|
@ -493,154 +436,172 @@ proc cycleCheck(n: PNode; c: var Con) =
|
|||
message(c.graph.config, n.info, warnCycleCreated, msg)
|
||||
break
|
||||
|
||||
proc p(n: PNode; c: var Con; consumed = false): PNode =
|
||||
case n.kind
|
||||
of nkCallKinds:
|
||||
let parameters = n[0].typ
|
||||
let L = if parameters != nil: parameters.len else: 0
|
||||
result = shallowCopy(n)
|
||||
for i in 1..<n.len:
|
||||
result[i] = pArg(n[i], c, i < L and isSinkTypeForParam(parameters[i]))
|
||||
if n[0].kind == nkSym and n[0].sym.magic in {mNew, mNewFinalize}:
|
||||
result[0] = copyTree(n[0])
|
||||
if c.graph.config.selectedGC in {gcHooks, gcDestructors}:
|
||||
let destroyOld = genDestroy(c, result[1])
|
||||
result = newTree(nkStmtList, destroyOld, result)
|
||||
else:
|
||||
result[0] = pArg(n[0], c, isSink = false)
|
||||
of nkDiscardStmt: # Small optimization
|
||||
result = shallowCopy(n)
|
||||
if n[0].kind != nkEmpty:
|
||||
result[0] = pArg(n[0], c, false)
|
||||
else:
|
||||
result[0] = copyNode(n[0])
|
||||
of nkBracket:
|
||||
result = copyTree(n)
|
||||
for i in 0..<n.len:
|
||||
# everything that is passed to an array constructor is consumed,
|
||||
# so these all act like 'sink' parameters:
|
||||
result[i] = pArg(n[i], c, isSink = true)
|
||||
if not consumed:
|
||||
result = ensureDestruction(result, c)
|
||||
of nkObjConstr:
|
||||
result = copyTree(n)
|
||||
for i in 1..<n.len:
|
||||
# everything that is passed to an object constructor is consumed,
|
||||
# so these all act like 'sink' parameters:
|
||||
result[i][1] = pArg(n[i][1], c, isSink = true)
|
||||
if not consumed:
|
||||
result = ensureDestruction(result, c)
|
||||
of nkTupleConstr, nkClosure:
|
||||
result = copyTree(n)
|
||||
for i in ord(n.kind == nkClosure)..<n.len:
|
||||
# everything that is passed to an tuple constructor is consumed,
|
||||
# so these all act like 'sink' parameters:
|
||||
if n[i].kind == nkExprColonExpr:
|
||||
result[i][1] = pArg(n[i][1], c, isSink = true)
|
||||
proc p(n: PNode; c: var Con; mode: ProcessMode = normal): PNode =
|
||||
if n.kind in {nkStmtList, nkStmtListExpr, nkBlockStmt, nkBlockExpr, nkIfStmt, nkIfExpr, nkCaseStmt, nkWhen}:
|
||||
handleNested(n): p(node, c, mode)
|
||||
elif mode == sinkArg:
|
||||
if n.containsConstSeq:
|
||||
# const sequences are not mutable and so we need to pass a copy to the
|
||||
# sink parameter (bug #11524). Note that the string implementation is
|
||||
# different and can deal with 'const string sunk into var'.
|
||||
result = passCopyToSink(n, c)
|
||||
elif n.kind in {nkBracket, nkObjConstr, nkTupleConstr, nkClosure} + nkCallKinds + nkLiterals:
|
||||
result = p(n, c, consumed)
|
||||
elif n.kind == nkSym and isSinkParam(n.sym):
|
||||
# Sinked params can be consumed only once. We need to reset the memory
|
||||
# to disable the destructor which we have not elided
|
||||
sinkParamIsLastReadCheck(c, n)
|
||||
result = destructiveMoveVar(n, c)
|
||||
elif isAnalysableFieldAccess(n, c.owner) and isLastRead(n, c):
|
||||
# it is the last read, can be sinkArg. We need to reset the memory
|
||||
# to disable the destructor which we have not elided
|
||||
result = destructiveMoveVar(n, c)
|
||||
elif n.kind in {nkHiddenSubConv, nkHiddenStdConv, nkConv}:
|
||||
result = copyTree(n)
|
||||
if n.typ.skipTypes(abstractInst-{tyOwned}).kind != tyOwned and
|
||||
n[1].typ.skipTypes(abstractInst-{tyOwned}).kind == tyOwned:
|
||||
# allow conversions from owned to unowned via this little hack:
|
||||
let nTyp = n[1].typ
|
||||
n[1].typ = n.typ
|
||||
result[1] = p(n[1], c, sinkArg)
|
||||
result[1].typ = nTyp
|
||||
else:
|
||||
result[i] = pArg(n[i], c, isSink = true)
|
||||
if not consumed:
|
||||
result = ensureDestruction(result, c)
|
||||
of nkVarSection, nkLetSection:
|
||||
# transform; var x = y to var x; x op y where op is a move or copy
|
||||
result = newNodeI(nkStmtList, n.info)
|
||||
for it in n:
|
||||
var ri = it[^1]
|
||||
if it.kind == nkVarTuple and hasDestructor(ri.typ):
|
||||
let x = lowerTupleUnpacking(c.graph, it, c.owner)
|
||||
result.add p(x, c)
|
||||
elif it.kind == nkIdentDefs and hasDestructor(it[0].typ) and not isCursor(it[0]):
|
||||
for j in 0..<it.len-2:
|
||||
let v = it[j]
|
||||
if v.kind == nkSym:
|
||||
if sfCompileTime in v.sym.flags: continue
|
||||
# move the variable declaration to the top of the frame:
|
||||
c.addTopVar v
|
||||
# make sure it's destroyed at the end of the proc:
|
||||
if not isUnpackedTuple(it[0].sym):
|
||||
c.destroys.add genDestroy(c, v)
|
||||
if ri.kind == nkEmpty and c.inLoop > 0:
|
||||
ri = genDefaultCall(v.typ, c, v.info)
|
||||
if ri.kind != nkEmpty:
|
||||
let r = moveOrCopy(v, ri, c)
|
||||
result.add r
|
||||
else: # keep the var but transform 'ri':
|
||||
var v = copyNode(n)
|
||||
var itCopy = copyNode(it)
|
||||
for j in 0..<it.len-1:
|
||||
itCopy.add it[j]
|
||||
itCopy.add p(it[^1], c)
|
||||
v.add itCopy
|
||||
result.add v
|
||||
of nkAsgn, nkFastAsgn:
|
||||
if hasDestructor(n[0].typ) and n[1].kind notin {nkProcDef, nkDo, nkLambda} and
|
||||
not isCursor(n[0]):
|
||||
# rule (self-assignment-removal):
|
||||
if n[1].kind == nkSym and n[0].kind == nkSym and n[0].sym == n[1].sym:
|
||||
result = newNodeI(nkEmpty, n.info)
|
||||
else:
|
||||
if n[0].kind in {nkDotExpr, nkCheckedFieldExpr}:
|
||||
cycleCheck(n, c)
|
||||
result = moveOrCopy(n[0], n[1], c)
|
||||
result[1] = p(n[1], c, sinkArg)
|
||||
elif n.kind in {nkObjDownConv, nkObjUpConv}:
|
||||
result = copyTree(n)
|
||||
result[0] = p(n[0], c, sinkArg)
|
||||
else:
|
||||
result = copyNode(n)
|
||||
result.add copyTree(n[0])
|
||||
result.add p(n[1], c)
|
||||
of nkRaiseStmt:
|
||||
if optOwnedRefs in c.graph.config.globalOptions and n[0].kind != nkEmpty:
|
||||
if n[0].kind in nkCallKinds:
|
||||
let call = p(n[0], c)
|
||||
result = copyNode(n)
|
||||
result.add call
|
||||
else:
|
||||
let tmp = getTemp(c, n[0].typ, n.info)
|
||||
var m = genCopyNoCheck(c, tmp, n[0])
|
||||
m.add p(n[0], c)
|
||||
result = newTree(nkStmtList, genWasMoved(tmp, c), m)
|
||||
var toDisarm = n[0]
|
||||
if toDisarm.kind == nkStmtListExpr: toDisarm = toDisarm.lastSon
|
||||
if toDisarm.kind == nkSym and toDisarm.sym.owner == c.owner:
|
||||
result.add genWasMoved(toDisarm, c)
|
||||
result.add newTree(nkRaiseStmt, tmp)
|
||||
else:
|
||||
result = copyNode(n)
|
||||
result.add p(n[0], c)
|
||||
of nkNone..nkNilLit, nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef,
|
||||
nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo, nkFuncDef,
|
||||
nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt, nkExportStmt,
|
||||
nkPragma, nkCommentStmt, nkBreakStmt, nkBreakState:
|
||||
result = n
|
||||
of nkWhileStmt:
|
||||
result = copyNode(n)
|
||||
inc c.inLoop
|
||||
result.add p(n[0], c)
|
||||
result.add p(n[1], c)
|
||||
dec c.inLoop
|
||||
of nkWhen: # This should be a "when nimvm" node.
|
||||
result = copyTree(n)
|
||||
result[1][0] = p(result[1][0], c)
|
||||
of nkStmtList, nkStmtListExpr, nkBlockStmt, nkBlockExpr, nkIfStmt, nkIfExpr, nkCaseStmt:
|
||||
handleNested(n): p(node, c, consumed)
|
||||
# copy objects that are not temporary but passed to a 'sink' parameter
|
||||
result = passCopyToSink(n, c)
|
||||
else:
|
||||
result = shallowCopy(n)
|
||||
for i in 0..<n.len:
|
||||
result[i] = p(n[i], c, consumed)
|
||||
case n.kind
|
||||
of nkBracket, nkObjConstr, nkTupleConstr, nkClosure:
|
||||
result = copyTree(n)
|
||||
for i in ord(n.kind in {nkObjConstr, nkClosure})..<n.len:
|
||||
let m = if mode == normal: normal
|
||||
else: sinkArg
|
||||
if n[i].kind == nkExprColonExpr:
|
||||
result[i][1] = p(n[i][1], c, m)
|
||||
else:
|
||||
result[i] = p(n[i], c, m)
|
||||
of nkCallKinds:
|
||||
let parameters = n[0].typ
|
||||
let L = if parameters != nil: parameters.len else: 0
|
||||
result = shallowCopy(n)
|
||||
for i in 1..<n.len:
|
||||
if i < L and isSinkTypeForParam(parameters[i]):
|
||||
result[i] = p(n[i], c, sinkArg)
|
||||
else:
|
||||
result[i] = p(n[i], c, normal)
|
||||
if n[0].kind == nkSym and n[0].sym.magic in {mNew, mNewFinalize}:
|
||||
result[0] = copyTree(n[0])
|
||||
if c.graph.config.selectedGC in {gcHooks, gcDestructors}:
|
||||
let destroyOld = genDestroy(c, result[1])
|
||||
result = newTree(nkStmtList, destroyOld, result)
|
||||
else:
|
||||
result[0] = p(n[0], c, normal)
|
||||
|
||||
if mode == normal:
|
||||
result = ensureDestruction(result, c)
|
||||
of nkDiscardStmt: # Small optimization
|
||||
result = shallowCopy(n)
|
||||
if n[0].kind != nkEmpty:
|
||||
result[0] = p(n[0], c, normal)
|
||||
else:
|
||||
result[0] = copyNode(n[0])
|
||||
of nkVarSection, nkLetSection:
|
||||
# transform; var x = y to var x; x op y where op is a move or copy
|
||||
result = newNodeI(nkStmtList, n.info)
|
||||
for it in n:
|
||||
var ri = it[^1]
|
||||
if it.kind == nkVarTuple and hasDestructor(ri.typ):
|
||||
let x = lowerTupleUnpacking(c.graph, it, c.owner)
|
||||
result.add p(x, c, consumed)
|
||||
elif it.kind == nkIdentDefs and hasDestructor(it[0].typ) and not isCursor(it[0]):
|
||||
for j in 0..<it.len-2:
|
||||
let v = it[j]
|
||||
if v.kind == nkSym:
|
||||
if sfCompileTime in v.sym.flags: continue
|
||||
# move the variable declaration to the top of the frame:
|
||||
c.addTopVar v
|
||||
# make sure it's destroyed at the end of the proc:
|
||||
if not isUnpackedTuple(it[0].sym):
|
||||
c.destroys.add genDestroy(c, v)
|
||||
if ri.kind == nkEmpty and c.inLoop > 0:
|
||||
ri = genDefaultCall(v.typ, c, v.info)
|
||||
if ri.kind != nkEmpty:
|
||||
let r = moveOrCopy(v, ri, c)
|
||||
result.add r
|
||||
else: # keep the var but transform 'ri':
|
||||
var v = copyNode(n)
|
||||
var itCopy = copyNode(it)
|
||||
for j in 0..<it.len-1:
|
||||
itCopy.add it[j]
|
||||
itCopy.add p(it[^1], c)
|
||||
v.add itCopy
|
||||
result.add v
|
||||
of nkAsgn, nkFastAsgn:
|
||||
if hasDestructor(n[0].typ) and n[1].kind notin {nkProcDef, nkDo, nkLambda} and
|
||||
not isCursor(n[0]):
|
||||
# rule (self-assignment-removal):
|
||||
if n[1].kind == nkSym and n[0].kind == nkSym and n[0].sym == n[1].sym:
|
||||
result = newNodeI(nkEmpty, n.info)
|
||||
else:
|
||||
if n[0].kind in {nkDotExpr, nkCheckedFieldExpr}:
|
||||
cycleCheck(n, c)
|
||||
result = moveOrCopy(n[0], n[1], c)
|
||||
else:
|
||||
result = copyNode(n)
|
||||
result.add copyTree(n[0])
|
||||
result.add p(n[1], c, consumed)
|
||||
of nkRaiseStmt:
|
||||
if optOwnedRefs in c.graph.config.globalOptions and n[0].kind != nkEmpty:
|
||||
if n[0].kind in nkCallKinds:
|
||||
let call = p(n[0], c)
|
||||
result = copyNode(n)
|
||||
result.add call
|
||||
else:
|
||||
let tmp = getTemp(c, n[0].typ, n.info)
|
||||
var m = genCopyNoCheck(c, tmp, n[0])
|
||||
m.add p(n[0], c)
|
||||
result = newTree(nkStmtList, genWasMoved(tmp, c), m)
|
||||
var toDisarm = n[0]
|
||||
if toDisarm.kind == nkStmtListExpr: toDisarm = toDisarm.lastSon
|
||||
if toDisarm.kind == nkSym and toDisarm.sym.owner == c.owner:
|
||||
result.add genWasMoved(toDisarm, c)
|
||||
result.add newTree(nkRaiseStmt, tmp)
|
||||
else:
|
||||
result = copyNode(n)
|
||||
if n[0].kind != nkEmpty:
|
||||
result.add p(n[0], c, sinkArg)
|
||||
else:
|
||||
result.add copyNode(n[0])
|
||||
of nkWhileStmt:
|
||||
result = copyNode(n)
|
||||
inc c.inLoop
|
||||
result.add p(n[0], c)
|
||||
result.add p(n[1], c)
|
||||
dec c.inLoop
|
||||
of nkNone..nkNilLit, nkTypeSection, nkProcDef, nkConverterDef,
|
||||
nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo,
|
||||
nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt,
|
||||
nkExportStmt, nkPragma, nkCommentStmt, nkBreakStmt, nkBreakState:
|
||||
result = n
|
||||
else:
|
||||
result = shallowCopy(n)
|
||||
for i in 0..<n.len:
|
||||
result[i] = p(n[i], c, mode)
|
||||
|
||||
proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
|
||||
# unfortunately, this needs to be kept consistent with the cases
|
||||
# we handle in the 'case of' statement below:
|
||||
const movableNodeKinds = (nkCallKinds + {nkSym, nkTupleConstr, nkClosure, nkObjConstr,
|
||||
nkBracket, nkBracketExpr, nkNilLit})
|
||||
|
||||
case ri.kind
|
||||
of nkCallKinds:
|
||||
result = genSink(c, dest, ri)
|
||||
result.add p(ri, c, consumed = true)
|
||||
result.add p(ri, c, consumed)
|
||||
of nkBracketExpr:
|
||||
if ri[0].kind == nkSym and isUnpackedTuple(ri[0].sym):
|
||||
# unpacking of tuple: move out the elements
|
||||
result = genSink(c, dest, ri)
|
||||
result.add p(ri, c, consumed = true)
|
||||
result.add p(ri, c, consumed)
|
||||
elif isAnalysableFieldAccess(ri, c.owner) and isLastRead(ri, c):
|
||||
# Rule 3: `=sink`(x, z); wasMoved(z)
|
||||
var snk = genSink(c, dest, ri)
|
||||
|
|
@ -648,17 +609,17 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
|
|||
result = newTree(nkStmtList, snk, genWasMoved(ri, c))
|
||||
else:
|
||||
result = genCopy(c, dest, ri)
|
||||
result.add p(ri, c, consumed = true)
|
||||
result.add p(ri, c, consumed)
|
||||
of nkBracket:
|
||||
# array constructor
|
||||
if ri.len > 0 and isDangerousSeq(ri.typ):
|
||||
result = genCopy(c, dest, ri)
|
||||
else:
|
||||
result = genSink(c, dest, ri)
|
||||
result.add p(ri, c, consumed = true)
|
||||
result.add p(ri, c, consumed)
|
||||
of nkObjConstr, nkTupleConstr, nkClosure, nkCharLit..nkNilLit:
|
||||
result = genSink(c, dest, ri)
|
||||
result.add p(ri, c, consumed = true)
|
||||
result.add p(ri, c, consumed)
|
||||
of nkSym:
|
||||
if isSinkParam(ri.sym):
|
||||
# Rule 3: `=sink`(x, z); wasMoved(z)
|
||||
|
|
@ -674,18 +635,26 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
|
|||
result = newTree(nkStmtList, snk, genWasMoved(ri, c))
|
||||
else:
|
||||
result = genCopy(c, dest, ri)
|
||||
result.add p(ri, c, consumed = true)
|
||||
result.add p(ri, c, consumed)
|
||||
of nkHiddenSubConv, nkHiddenStdConv, nkConv:
|
||||
result = moveOrCopy(dest, ri[1], c)
|
||||
if not sameType(ri.typ, ri[1].typ):
|
||||
let copyRi = copyTree(ri)
|
||||
copyRi[1] = result[^1]
|
||||
result[^1] = copyRi
|
||||
when false:
|
||||
result = moveOrCopy(dest, ri[1], c)
|
||||
if not sameType(ri.typ, ri[1].typ):
|
||||
let copyRi = copyTree(ri)
|
||||
copyRi[1] = result[^1]
|
||||
result[^1] = copyRi
|
||||
else:
|
||||
result = genSink(c, dest, ri)
|
||||
result.add p(ri, c, sinkArg)
|
||||
of nkObjDownConv, nkObjUpConv:
|
||||
result = moveOrCopy(dest, ri[0], c)
|
||||
let copyRi = copyTree(ri)
|
||||
copyRi[0] = result[^1]
|
||||
result[^1] = copyRi
|
||||
when false:
|
||||
result = moveOrCopy(dest, ri[0], c)
|
||||
let copyRi = copyTree(ri)
|
||||
copyRi[0] = result[^1]
|
||||
result[^1] = copyRi
|
||||
else:
|
||||
result = genSink(c, dest, ri)
|
||||
result.add p(ri, c, sinkArg)
|
||||
of nkStmtListExpr, nkBlockExpr, nkIfExpr, nkCaseStmt:
|
||||
handleNested(ri): moveOrCopy(dest, node, c)
|
||||
else:
|
||||
|
|
@ -697,7 +666,7 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
|
|||
result = newTree(nkStmtList, snk, genWasMoved(ri, c))
|
||||
else:
|
||||
result = genCopy(c, dest, ri)
|
||||
result.add p(ri, c, consumed = true)
|
||||
result.add p(ri, c, consumed)
|
||||
|
||||
proc computeUninit(c: var Con) =
|
||||
if not c.uninitComputed:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue