lift the =dup hook (#21903)

* fixes tests again
* remove helper functions
* fixes closures, owned refs
* final cleanup
This commit is contained in:
ringabout
2023-06-02 22:03:32 +08:00
committed by GitHub
parent ead7e20926
commit 1133f20fe2
15 changed files with 151 additions and 93 deletions

View File

@@ -944,10 +944,10 @@ type
attachedWasMoved,
attachedDestructor,
attachedAsgn,
attachedDup,
attachedSink,
attachedTrace,
attachedDeepCopy,
attachedDup
attachedDeepCopy
TType* {.acyclic.} = object of TIdObj # \
# types are identical iff they have the
@@ -1518,7 +1518,7 @@ proc newProcNode*(kind: TNodeKind, info: TLineInfo, body: PNode,
const
AttachedOpToStr*: array[TTypeAttachedOp, string] = [
"=wasMoved", "=destroy", "=copy", "=sink", "=trace", "=deepcopy", "=dup"]
"=wasMoved", "=destroy", "=copy", "=dup", "=sink", "=trace", "=deepcopy"]
proc `$`*(s: PSym): string =
if s != nil:

View File

@@ -2359,11 +2359,6 @@ proc genMove(p: BProc; n: PNode; d: var TLoc) =
genAssignment(p, d, a, {})
resetLoc(p, a)
proc genDup(p: BProc; src: TLoc; d: var TLoc; n: PNode) =
if d.k == locNone: getTemp(p, n.typ, d)
linefmt(p, cpsStmts, "#nimDupRef((void**)$1, (void*)$2);$n",
[addrLoc(p.config, d), rdLoc(src)])
proc genDestroy(p: BProc; n: PNode) =
if optSeqDestructors in p.config.globalOptions:
let arg = n[1].skipAddr
@@ -2615,11 +2610,6 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
of mAccessTypeField: genAccessTypeField(p, e, d)
of mSlice: genSlice(p, e, d)
of mTrace: discard "no code to generate"
of mDup:
var a: TLoc
let x = if e[1].kind in {nkAddr, nkHiddenAddr}: e[1][0] else: e[1]
initLocExpr(p, x, a)
genDup(p, a, d, e)
else:
when defined(debugMagics):
echo p.prc.name.s, " ", p.prc.id, " ", p.prc.flags, " ", p.prc.ast[genericParamsPos].kind

View File

@@ -188,7 +188,7 @@ template isUnpackedTuple(n: PNode): bool =
proc checkForErrorPragma(c: Con; t: PType; ri: PNode; opname: string) =
var m = "'" & opname & "' is not available for type <" & typeToString(t) & ">"
if (opname == "=" or opname == "=copy") and ri != nil:
if (opname == "=" or opname == "=copy" or opname == "=dup") and ri != nil:
m.add "; requires a copy because it's not the last read of '"
m.add renderTree(ri)
m.add '\''
@@ -427,21 +427,17 @@ proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode =
if hasDestructor(c, n.typ):
let typ = n.typ.skipTypes({tyGenericInst, tyAlias, tySink})
let op = getAttachedOp(c.graph, typ, attachedDup)
if op != nil:
if op != nil and tfHasOwned notin typ.flags:
if sfError in op.flags:
c.checkForErrorPragma(n.typ, n, "=dup")
let src = p(n, c, s, normal)
result.add newTreeI(nkFastAsgn,
src.info, tmp,
newTreeIT(nkCall, src.info, src.typ,
var newCall = newTreeIT(nkCall, src.info, src.typ,
newSymNode(op),
src)
)
elif typ.kind == tyRef:
let src = p(n, c, s, normal)
c.finishCopy(newCall, n, isFromSink = true)
result.add newTreeI(nkFastAsgn,
src.info, tmp,
newTreeIT(nkCall, src.info, src.typ,
newSymNode(createMagic(c.graph, c.idgen, "`=dup`", mDup)),
src)
newCall
)
else:
result.add c.genWasMoved(tmp)

View File

@@ -34,6 +34,7 @@ type
template destructor*(t: PType): PSym = getAttachedOp(c.g, t, attachedDestructor)
template assignment*(t: PType): PSym = getAttachedOp(c.g, t, attachedAsgn)
template dup*(t: PType): PSym = getAttachedOp(c.g, t, attachedDup)
template asink*(t: PType): PSym = getAttachedOp(c.g, t, attachedSink)
proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode)
@@ -82,7 +83,7 @@ proc genBuiltin(c: var TLiftCtx; magic: TMagic; name: string; i: PNode): PNode =
result = genBuiltin(c.g, c.idgen, magic, name, i)
proc defaultOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
if c.kind in {attachedAsgn, attachedDeepCopy, attachedSink}:
if c.kind in {attachedAsgn, attachedDeepCopy, attachedSink, attachedDup}:
body.add newAsgnStmt(x, y)
elif c.kind == attachedDestructor and c.addMemReset:
let call = genBuiltin(c, mDefault, "default", x)
@@ -283,7 +284,7 @@ proc boolLit*(g: ModuleGraph; info: TLineInfo; value: bool): PNode =
result.typ = getSysType(g, info, tyBool)
proc getCycleParam(c: TLiftCtx): PNode =
assert c.kind == attachedAsgn
assert c.kind in {attachedAsgn, attachedDup}
if c.fn.typ.len == 4:
result = c.fn.typ.n.lastSon
assert result.kind == nkSym
@@ -322,6 +323,9 @@ proc newOpCall(c: var TLiftCtx; op: PSym; x: PNode): PNode =
proc newDeepCopyCall(c: var TLiftCtx; op: PSym; x, y: PNode): PNode =
result = newAsgnStmt(x, newOpCall(c, op, y))
proc newDupCall(c: var TLiftCtx; op: PSym; x, y: PNode): PNode =
result = newAsgnStmt(x, newOpCall(c, op, y))
proc usesBuiltinArc(t: PType): bool =
proc wrap(t: PType): bool {.nimcall.} = ast.isGCedMem(t)
result = types.searchTypeFor(t, wrap)
@@ -464,7 +468,18 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
result = true
of attachedDup:
assert false, "cannot happen"
var op = getAttachedOp(c.g, t, attachedDup)
if op != nil and sfOverriden in op.flags:
if op.ast.isGenericRoutine:
# patch generic destructor:
op = instantiateGeneric(c, op, t, t.typeInst)
setAttachedOp(c.g, c.idgen.module, t, attachedDup, op)
#markUsed(c.g.config, c.info, op, c.g.usageSym)
onUse(c.info, op)
body.add newDupCall(c, op, x, y)
result = true
proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode =
var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.idgen, c.fn, c.info)
@@ -526,6 +541,9 @@ proc forallElements(c: var TLiftCtx; t: PType; body, x, y: PNode) =
proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
case c.kind
of attachedDup:
body.add setLenSeqCall(c, t, x, y)
forallElements(c, t, body, x, y)
of attachedAsgn, attachedDeepCopy:
# we generate:
# setLen(dest, y.len)
@@ -549,15 +567,13 @@ proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
# follow all elements:
forallElements(c, t, body, x, y)
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
of attachedDup:
assert false, "cannot happen"
proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
createTypeBoundOps(c.g, c.c, t, body.info, c.idgen)
# recursions are tricky, so we might need to forward the generated
# operation here:
var t = t
if t.assignment == nil or t.destructor == nil:
if t.assignment == nil or t.destructor == nil or t.dup == nil:
let h = sighashes.hashType(t,c.g.config, {CoType, CoConsiderOwned, CoDistinct})
let canon = c.g.canonTypes.getOrDefault(h)
if canon != nil: t = canon
@@ -590,11 +606,15 @@ proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
body.add newHookCall(c, op, x, y)
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
of attachedDup:
assert false, "cannot happen"
# XXX: replace these with assertions.
let op = getAttachedOp(c.g, t, c.kind)
if op == nil:
return # protect from recursion
body.add newDupCall(c, op, x, y)
proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
case c.kind
of attachedAsgn, attachedDeepCopy:
of attachedAsgn, attachedDeepCopy, attachedDup:
body.add callCodegenProc(c.g, "nimAsgnStrV2", c.info, genAddr(c, x), y)
of attachedSink:
let moveCall = genBuiltin(c, mMove, "move", x)
@@ -607,8 +627,6 @@ proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
of attachedTrace:
discard "strings are atomic and have no inner elements that are to trace"
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
of attachedDup:
assert false, "cannot happen"
proc cyclicType*(g: ModuleGraph, t: PType): bool =
case t.kind
@@ -648,7 +666,7 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
# dynamic Acyclic refs need to use dyn decRef
let tmp =
if isCyclic and c.kind in {attachedAsgn, attachedSink}:
if isCyclic and c.kind in {attachedAsgn, attachedSink, attachedDup}:
declareTempOf(c, body, x)
else:
x
@@ -709,7 +727,14 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
#echo "can follow ", elemType, " static ", isFinal(elemType)
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
of attachedDup:
assert false, "cannot happen"
if isCyclic:
body.add newAsgnStmt(x, y)
body.add genIf(c, y, callCodegenProc(c.g,
"nimIncRefCyclic", c.info, y, getCycleParam(c)))
else:
body.add newAsgnStmt(x, y)
body.add genIf(c, y, callCodegenProc(c.g,
"nimIncRef", c.info, y))
proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
## Closures are really like refs except they always use a virtual destructor
@@ -719,7 +744,7 @@ proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
let isCyclic = c.g.config.selectedGC == gcOrc
let tmp =
if isCyclic and c.kind in {attachedAsgn, attachedSink}:
if isCyclic and c.kind in {attachedAsgn, attachedSink, attachedDup}:
declareTempOf(c, body, xenv)
else:
xenv
@@ -753,14 +778,21 @@ proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
body.add genIf(c, cond, actions)
body.add newAsgnStmt(x, y)
of attachedDup:
let yenv = genBuiltin(c, mAccessEnv, "accessEnv", y)
yenv.typ = getSysType(c.g, c.info, tyPointer)
if isCyclic:
body.add newAsgnStmt(x, y)
body.add genIf(c, yenv, callCodegenProc(c.g, "nimIncRefCyclic", c.info, yenv, getCycleParam(c)))
else:
body.add newAsgnStmt(x, y)
body.add genIf(c, yenv, callCodegenProc(c.g, "nimIncRef", c.info, yenv))
of attachedDestructor:
body.add genIf(c, cond, actions)
of attachedDeepCopy: assert(false, "cannot happen")
of attachedTrace:
body.add callCodegenProc(c.g, "nimTraceRefDyn", c.info, genAddrOf(xenv, c.idgen), y)
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
of attachedDup:
assert false, "cannot happen"
proc weakrefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
case c.kind
@@ -773,6 +805,9 @@ proc weakrefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
body.add genIf(c, y, callCodegenProc(c.g, "nimIncRef", c.info, y))
body.add genIf(c, x, callCodegenProc(c.g, "nimDecWeakRef", c.info, x))
body.add newAsgnStmt(x, y)
of attachedDup:
body.add newAsgnStmt(x, y)
body.add genIf(c, y, callCodegenProc(c.g, "nimIncRef", c.info, y))
of attachedDestructor:
# it's better to prepend the destruction of weak refs in order to
# prevent wrong "dangling refs exist" problems:
@@ -786,8 +821,6 @@ proc weakrefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
of attachedDeepCopy: assert(false, "cannot happen")
of attachedTrace: discard
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
of attachedDup:
assert false, "cannot happen"
proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
var actions = newNodeI(nkStmtList, c.info)
@@ -809,13 +842,13 @@ proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
of attachedSink, attachedAsgn:
body.add genIf(c, x, actions)
body.add newAsgnStmt(x, y)
of attachedDup:
body.add newAsgnStmt(x, y)
of attachedDestructor:
body.add genIf(c, x, actions)
of attachedDeepCopy: assert(false, "cannot happen")
of attachedTrace: discard
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
of attachedDup:
assert false, "cannot happen"
proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
if c.kind == attachedDeepCopy:
@@ -842,6 +875,11 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
body.add genIf(c, yy, callCodegenProc(c.g, "nimIncRef", c.info, yy))
body.add genIf(c, xx, callCodegenProc(c.g, "nimDecWeakRef", c.info, xx))
body.add newAsgnStmt(x, y)
of attachedDup:
let yy = genBuiltin(c, mAccessEnv, "accessEnv", y)
yy.typ = getSysType(c.g, c.info, tyPointer)
body.add newAsgnStmt(x, y)
body.add genIf(c, yy, callCodegenProc(c.g, "nimIncRef", c.info, yy))
of attachedDestructor:
let des = genIf(c, xx, callCodegenProc(c.g, "nimDecWeakRef", c.info, xx))
if body.len == 0:
@@ -851,8 +889,6 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
of attachedDeepCopy: assert(false, "cannot happen")
of attachedTrace: discard
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
of attachedDup:
assert false, "cannot happen"
proc ownedClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
let xx = genBuiltin(c, mAccessEnv, "accessEnv", x)
@@ -864,13 +900,13 @@ proc ownedClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
of attachedSink, attachedAsgn:
body.add genIf(c, xx, actions)
body.add newAsgnStmt(x, y)
of attachedDup:
body.add newAsgnStmt(x, y)
of attachedDestructor:
body.add genIf(c, xx, actions)
of attachedDeepCopy: assert(false, "cannot happen")
of attachedTrace: discard
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
of attachedDup:
assert false, "cannot happen"
proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
case t.kind
@@ -936,7 +972,7 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
if not considerUserDefinedOp(c, t, body, x, y):
if t.sym != nil and sfImportc in t.sym.flags:
case c.kind
of {attachedAsgn, attachedSink}:
of {attachedAsgn, attachedSink, attachedDup}:
body.add newAsgnStmt(x, y)
of attachedWasMoved:
body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
@@ -976,8 +1012,44 @@ proc produceSymDistinctType(g: ModuleGraph; c: PContext; typ: PType;
result = getAttachedOp(g, baseType, kind)
setAttachedOp(g, idgen.module, typ, kind, result)
proc symDupPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp;
info: TLineInfo; idgen: IdGenerator): PSym =
let procname = getIdent(g.cache, AttachedOpToStr[kind])
result = newSym(skProc, procname, idgen, owner, info)
let res = newSym(skResult, getIdent(g.cache, "result"), idgen, result, info)
let src = newSym(skParam, getIdent(g.cache, "src"),
idgen, result, info)
res.typ = typ
src.typ = typ
result.typ = newType(tyProc, nextTypeId idgen, owner)
result.typ.n = newNodeI(nkFormalParams, info)
rawAddSon(result.typ, res.typ)
result.typ.n.add newNodeI(nkEffectList, info)
result.typ.addParam src
if g.config.selectedGC == gcOrc and
cyclicType(g, typ.skipTypes(abstractInst)):
let cycleParam = newSym(skParam, getIdent(g.cache, "cyclic"),
idgen, result, info)
cycleParam.typ = getSysType(g, info, tyBool)
result.typ.addParam cycleParam
var n = newNodeI(nkProcDef, info, bodyPos+2)
for i in 0..<n.len: n[i] = newNodeI(nkEmpty, info)
n[namePos] = newSymNode(result)
n[paramsPos] = result.typ.n
n[bodyPos] = newNodeI(nkStmtList, info)
n[resultPos] = newSymNode(res)
result.ast = n
incl result.flags, sfFromGeneric
incl result.flags, sfGeneratedOp
proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp;
info: TLineInfo; idgen: IdGenerator): PSym =
if kind == attachedDup:
return symDupPrototype(g, typ, owner, kind, info, idgen)
let procname = getIdent(g.cache, AttachedOpToStr[kind])
result = newSym(skProc, procname, idgen, owner, info)
@@ -992,7 +1064,7 @@ proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp
result.typ = newProcType(info, nextTypeId(idgen), owner)
result.typ.addParam dest
if kind notin {attachedDestructor, attachedWasMoved, attachedDup}:
if kind notin {attachedDestructor, attachedWasMoved}:
result.typ.addParam src
if kind == attachedAsgn and g.config.selectedGC == gcOrc and
@@ -1033,9 +1105,11 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
var a = TLiftCtx(info: info, g: g, kind: kind, c: c, asgnForType: typ, idgen: idgen,
fn: result)
let dest = result.typ.n[1].sym
let d = newDeref(newSymNode(dest))
let src = if kind in {attachedDestructor, attachedWasMoved, attachedDup}: newNodeIT(nkSym, info, getSysType(g, info, tyPointer))
let dest = if kind == attachedDup: result.ast[resultPos].sym else: result.typ.n[1].sym
let d = if kind == attachedDup: newSymNode(dest) else: newDeref(newSymNode(dest))
let src = case kind
of {attachedDestructor, attachedWasMoved}: newNodeIT(nkSym, info, getSysType(g, info, tyPointer))
of attachedDup: newSymNode(result.typ.n[1].sym)
else: newSymNode(result.typ.n[2].sym)
# register this operation already:
@@ -1059,7 +1133,7 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
fillStrOp(a, typ, result.ast[bodyPos], d, src)
else:
fillBody(a, typ, result.ast[bodyPos], d, src)
if tk == tyObject and a.kind in {attachedAsgn, attachedSink, attachedDeepCopy} and not lacksMTypeField(typ):
if tk == tyObject and a.kind in {attachedAsgn, attachedSink, attachedDeepCopy, attachedDup} and not lacksMTypeField(typ):
# bug #19205: Do not forget to also copy the hidden type field:
genTypeFieldCopy(a, typ, result.ast[bodyPos], d, src)

View File

@@ -137,7 +137,7 @@ proc new*[T](a: var ref T, finalizer: proc (x: ref T) {.nimcall.}) {.
## **Note**: The `finalizer` refers to the type `T`, not to the object!
## This means that for each object of type `T` the finalizer will be called!
proc `=wasMoved`[T](obj: var T) {.magic: "WasMoved", noSideEffect.} =
proc `=wasMoved`*[T](obj: var T) {.magic: "WasMoved", noSideEffect.} =
## Generic `wasMoved`:idx: implementation that can be overridden.
proc wasMoved*[T](obj: var T) {.inline, noSideEffect.} =
@@ -354,7 +354,7 @@ proc `=destroy`*[T](x: var T) {.inline, magic: "Destroy".} =
discard
when defined(nimHasDup):
proc `=dup`*[T](x: ref T): ref T {.inline, magic: "Dup".} =
proc `=dup`*[T](x: T): T {.inline, magic: "Dup".} =
## Generic `dup`:idx: implementation that can be overridden.
discard

View File

@@ -200,10 +200,6 @@ proc nimDecRefIsLast(p: pointer): bool {.compilerRtl, inl.} =
when traceCollector:
cprintf("[DECREF] %p\n", cell)
proc nimDupRef(dest: ptr pointer, src: pointer) {.compilerRtl, inl.} =
dest[] = src
if src != nil: nimIncRef src
proc GC_unref*[T](x: ref T) =
## New runtime only supports this operation for 'ref T'.
var y {.cursor.} = x

View File

@@ -87,7 +87,7 @@ pkg "kdtree", "nimble test -d:nimLegacyRandomInitRand", "https://github.com/jbli
pkg "loopfusion"
pkg "lockfreequeues"
pkg "macroutils"
pkg "manu"
pkg "manu", url = "https://github.com/nim-lang/manu"
pkg "markdown"
pkg "measuremancer", "nimble testDeps; nimble -y test"
pkg "memo"

View File

@@ -18,7 +18,7 @@ inc:
var id_1 = 777
s = RefCustom(id_2: addr(id_1))
inc_1 :
:tmpD_1 = `=dup`(s)
:tmpD_1 = `=dup_1`(s)
:tmpD_1
inc_1 :
let blitTmp_1 = s
@@ -34,14 +34,15 @@ type
RefCustom = object
id: ptr int
proc `=dup`(x: RefCustom): RefCustom =
result.id = x.id
proc inc(x: sink Ref) =
inc x.id
proc inc(x: sink RefCustom) =
inc x.id[]
proc `=dup`(x: RefCustom): RefCustom =
result.id = x.id
proc foo =
var x = Ref(id: 8)

View File

@@ -61,11 +61,9 @@ var
try:
it_cursor = x
a = (
`=wasMoved`(:tmpD)
`=copy`(:tmpD, it_cursor.key)
:tmpD = `=dup`(it_cursor.key)
:tmpD,
`=wasMoved`(:tmpD_1)
`=copy`(:tmpD_1, it_cursor.val)
:tmpD_1 = `=dup`(it_cursor.val)
:tmpD_1)
echo [
:tmpD_2 = `$$`(a)
@@ -125,19 +123,16 @@ this.isValid = fileExists(this.value)
if dirExists(this.value):
var :tmpD
par = (dir:
`=wasMoved`(:tmpD)
`=copy`(:tmpD, this.value)
:tmpD = `=dup`(this.value)
:tmpD, front: "") else:
var
:tmpD_1
:tmpD_2
:tmpD_3
par = (dir_1: parentDir(this.value), front_1:
`=wasMoved`(:tmpD_1)
`=copy`(:tmpD_1,
:tmpD_1 = `=dup`(
:tmpD_3 = splitDrive do:
`=wasMoved`(:tmpD_2)
`=copy`(:tmpD_2, this.value)
:tmpD_2 = `=dup`(this.value)
:tmpD_2
:tmpD_3.path)
:tmpD_1)

View File

@@ -39,8 +39,7 @@ try:
if i_cursor == 2:
return
add(a):
`=wasMoved`(:tmpD)
`=copy`(:tmpD, x)
:tmpD = `=dup`(x)
:tmpD
inc i_1, 1
if cond:

View File

@@ -39,7 +39,7 @@ proc `=destroy`*[T](dest: var SharedPtr[T]) =
echo "deallocating"
dest.x = nil
proc `=`*[T](dest: var SharedPtr[T]; src: SharedPtr[T]) =
proc `=copy`*[T](dest: var SharedPtr[T]; src: SharedPtr[T]) =
var s = src.x
if s != nil: incRef(s)
#atomicSwap(dest, s)
@@ -50,6 +50,9 @@ proc `=`*[T](dest: var SharedPtr[T]; src: SharedPtr[T]) =
deallocShared(s)
echo "deallocating"
proc `=dup`*[T](src: SharedPtr[T]): SharedPtr[T] =
`=copy`(result, src)
proc `=sink`*[T](dest: var SharedPtr[T]; src: SharedPtr[T]) =
## XXX make this an atomic store:
if dest.x != src.x:
@@ -120,7 +123,7 @@ proc `=destroy`*[T](m: var MySeq[T]) {.inline.} =
deallocShared(m.data)
m.data = nil
proc `=`*[T](m: var MySeq[T], m2: MySeq[T]) =
proc `=copy`*[T](m: var MySeq[T], m2: MySeq[T]) =
if m.data == m2.data: return
if m.data != nil:
`=destroy`(m)
@@ -131,6 +134,9 @@ proc `=`*[T](m: var MySeq[T], m2: MySeq[T]) =
m.data = cast[ptr UncheckedArray[T]](allocShared(bytes))
copyMem(m.data, m2.data, bytes)
proc `=dup`*[T](m: MySeq[T]): MySeq[T] =
`=copy`[T](result, m)
proc `=sink`*[T](m: var MySeq[T], m2: MySeq[T]) {.inline.} =
if m.data != m2.data:
if m.data != nil:

View File

@@ -31,7 +31,7 @@ proc `=sink`*(a: var Matrix; b: Matrix) =
a.m = b.m
a.n = b.n
proc `=`*(a: var Matrix; b: Matrix) =
proc `=copy`*(a: var Matrix; b: Matrix) =
if a.data != nil and a.data != b.data:
dealloc(a.data)
deallocCount.inc
@@ -43,6 +43,9 @@ proc `=`*(a: var Matrix; b: Matrix) =
allocCount.inc
copyMem(a.data, b.data, b.m * b.n * sizeof(float))
proc `=dup`*(a: Matrix): Matrix =
`=copy`(result, a)
proc matrix*(m, n: int, s: float): Matrix =
## Construct an m-by-n constant matrix.
result.m = m

View File

@@ -1,7 +1,7 @@
discard """
errormsg: "'=copy' is not available for type <Foo>; requires a copy because it's not the last read of 'otherTree'"
errormsg: "'=dup' is not available for type <Foo>; requires a copy because it's not the last read of 'otherTree'"
file: "tprevent_assign2.nim"
line: 48
line: 49
"""
type
@@ -9,7 +9,8 @@ type
x: int
proc `=destroy`(f: var Foo) = f.x = 0
proc `=`(a: var Foo; b: Foo) {.error.} # = a.x = b.x
proc `=copy`(a: var Foo; b: Foo) {.error.} # = a.x = b.x
proc `=dup`(a: Foo): Foo {.error.}
proc `=sink`(a: var Foo; b: Foo) = a.x = b.x
proc createTree(x: int): Foo =

View File

@@ -1,7 +1,7 @@
discard """
errormsg: "'=copy' is not available for type <Foo>; requires a copy because it's not the last read of 'otherTree'"
errormsg: "'=dup' is not available for type <Foo>; requires a copy because it's not the last read of 'otherTree'"
file: "tprevent_assign3.nim"
line: 46
line: 47
"""
type
@@ -9,7 +9,8 @@ type
x: int
proc `=destroy`(f: var Foo) = f.x = 0
proc `=`(a: var Foo; b: Foo) {.error.} # = a.x = b.x
proc `=copy`(a: var Foo; b: Foo) {.error.} # = a.x = b.x
proc `=dup`(a: Foo): Foo {.error.}
proc `=sink`(a: var Foo; b: Foo) = a.x = b.x
proc createTree(x: int): Foo =

View File

@@ -3,7 +3,7 @@ discard """
@[116, 101, 115, 116]
@[1953719668, 875770417]
destroying O1'''
cmd: '''nim c --gc:arc --expandArc:main --expandArc:main1 --expandArc:main2 --expandArc:main3 --hints:off --assertions:off $file'''
cmd: '''nim c --mm:arc --expandArc:main --expandArc:main1 --expandArc:main2 --expandArc:main3 --hints:off --assertions:off $file'''
nimout: '''
--expandArc: main
@@ -13,8 +13,7 @@ var
:tmpD_1
:tmpD_2
data =
`=wasMoved`(:tmpD)
`=copy`(:tmpD, cast[string](
:tmpD = `=dup`(cast[string](
:tmpD_2 = encode(cast[seq[byte]](
:tmpD_1 = newString(100)
:tmpD_1))
@@ -33,8 +32,7 @@ var
:tmpD_1
s = newString(100)
data =
`=wasMoved`(:tmpD)
`=copy`(:tmpD, cast[string](
:tmpD = `=dup`(cast[string](
:tmpD_1 = encode(toOpenArrayByte(s, 0, len(s) - 1))
:tmpD_1))
:tmpD
@@ -51,8 +49,7 @@ var
:tmpD_1
s = newSeq(100)
data =
`=wasMoved`(:tmpD)
`=copy`(:tmpD, cast[string](
:tmpD = `=dup`(cast[string](
:tmpD_1 = encode(s)
:tmpD_1))
:tmpD
@@ -68,8 +65,7 @@ var
:tmpD_1
:tmpD_2
data =
`=wasMoved`(:tmpD)
`=copy`(:tmpD, cast[string](
:tmpD = `=dup`(cast[string](
:tmpD_2 = encode do:
:tmpD_1 = newSeq(100)
:tmpD_1