mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-08 14:03:23 +00:00
Destructors: move into nkTupleConstr and move on tuple unpacking (#9776)
This commit is contained in:
@@ -261,6 +261,11 @@ proc isLastRead(n: PNode; c: var Con): bool =
|
||||
template interestingSym(s: PSym): bool =
|
||||
s.owner == c.owner and s.kind in InterestingSyms and hasDestructor(s.typ)
|
||||
|
||||
template isUnpackedTuple(s: PSym): bool =
|
||||
## we move out all elements of unpacked tuples,
|
||||
## hence unpacked tuples themselves don't need to be destroyed
|
||||
s.kind == skTemp and s.typ.kind == tyTuple
|
||||
|
||||
proc patchHead(n: PNode) =
|
||||
if n.kind in nkCallKinds and n[0].kind == nkSym and n.len > 1:
|
||||
let s = n[0].sym
|
||||
@@ -446,6 +451,13 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
|
||||
ri2.add pArg(ri[i], c, i < L and parameters[i].kind == tySink)
|
||||
#recurse(ri, ri2)
|
||||
result.add ri2
|
||||
of nkBracketExpr:
|
||||
if ri[0].kind == nkSym and isUnpackedTuple(ri[0].sym):
|
||||
# unpacking of tuple: move out the elements
|
||||
result = genSink(c, dest.typ, dest, ri)
|
||||
else:
|
||||
result = genCopy(c, dest.typ, dest, ri)
|
||||
result.add p(ri, c)
|
||||
of nkObjConstr:
|
||||
result = genSink(c, dest.typ, dest, ri)
|
||||
let ri2 = copyTree(ri)
|
||||
@@ -454,6 +466,17 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
|
||||
# so these all act like 'sink' parameters:
|
||||
ri2[i].sons[1] = pArg(ri[i][1], c, isSink = true)
|
||||
result.add ri2
|
||||
of nkTupleConstr:
|
||||
result = genSink(c, dest.typ, dest, ri)
|
||||
let ri2 = copyTree(ri)
|
||||
for i in 0..<ri.len:
|
||||
# everything that is passed to an tuple constructor is consumed,
|
||||
# so these all act like 'sink' parameters:
|
||||
if ri[i].kind == nkExprColonExpr:
|
||||
ri2[i].sons[1] = pArg(ri[i][1], c, isSink = true)
|
||||
else:
|
||||
ri2[i] = pArg(ri[i], c, isSink = true)
|
||||
result.add ri2
|
||||
of nkSym:
|
||||
if ri.sym.kind != skParam and isLastRead(ri, c):
|
||||
# Rule 3: `=sink`(x, z); wasMoved(z)
|
||||
@@ -483,7 +506,7 @@ proc p(n: PNode; c: var Con): PNode =
|
||||
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):
|
||||
elif it.kind == nkIdentDefs and hasDestructor(it[0].typ) and not isUnpackedTuple(it[0].sym):
|
||||
for j in 0..L-2:
|
||||
let v = it[j]
|
||||
doAssert v.kind == nkSym
|
||||
|
||||
@@ -1,21 +1,26 @@
|
||||
discard """
|
||||
exitcode: 0
|
||||
output: '''assingment
|
||||
assingment
|
||||
assingment
|
||||
assingment
|
||||
'''
|
||||
output: ""
|
||||
"""
|
||||
|
||||
type
|
||||
Foo* = object
|
||||
boo: int
|
||||
|
||||
var sink_counter = 0
|
||||
var assign_counter = 0
|
||||
|
||||
proc `=sink`(dest: var Foo, src: Foo) =
|
||||
sink_counter.inc
|
||||
|
||||
proc `=`(dest: var Foo, src: Foo) =
|
||||
debugEcho "assingment"
|
||||
assign_counter.inc
|
||||
|
||||
proc test(): auto =
|
||||
var a,b : Foo
|
||||
return (a, b)
|
||||
return (a, b, Foo(boo: 5))
|
||||
|
||||
var (a, b) = test()
|
||||
var (a, b, _) = test()
|
||||
|
||||
doAssert: assign_counter == 0
|
||||
doAssert: sink_counter == 9
|
||||
@@ -60,3 +60,62 @@ for x in getPony():
|
||||
# XXX this needs to be enabled once top level statements
|
||||
# produce destructor calls again.
|
||||
#echo "Pony is dying!"
|
||||
|
||||
|
||||
#------------------------------------------------------------
|
||||
#-- Move into tuple constructor and move on tuple unpacking
|
||||
#------------------------------------------------------------
|
||||
|
||||
type
|
||||
MySeqNonCopyable* = object
|
||||
len: int
|
||||
data: ptr UncheckedArray[float]
|
||||
|
||||
proc `=destroy`*(m: var MySeqNonCopyable) {.inline.} =
|
||||
if m.data != nil:
|
||||
deallocShared(m.data)
|
||||
m.data = nil
|
||||
|
||||
proc `=`*(m: var MySeqNonCopyable, m2: MySeqNonCopyable) {.error.}
|
||||
|
||||
proc `=sink`*(m: var MySeqNonCopyable, m2: MySeqNonCopyable) {.inline.} =
|
||||
if m.data != m2.data:
|
||||
if m.data != nil:
|
||||
`=destroy`(m)
|
||||
m.len = m2.len
|
||||
m.data = m2.data
|
||||
|
||||
proc len*(m: MySeqNonCopyable): int {.inline.} = m.len
|
||||
|
||||
proc `[]`*(m: MySeqNonCopyable; i: int): float {.inline.} =
|
||||
m.data[i.int]
|
||||
|
||||
proc `[]=`*(m: var MySeqNonCopyable; i, val: float) {.inline.} =
|
||||
m.data[i.int] = val
|
||||
|
||||
proc setTo(s: var MySeqNonCopyable, val: float) =
|
||||
for i in 0..<s.len.int:
|
||||
s.data[i] = val
|
||||
|
||||
proc newMySeq*(size: int, initial_value = 0.0): MySeqNonCopyable =#
|
||||
result.len = size
|
||||
if size > 0:
|
||||
result.data = cast[ptr UncheckedArray[float]](createShared(float, size))
|
||||
|
||||
result.setTo(initial_value)
|
||||
|
||||
proc myfunc(x, y: int): (MySeqNonCopyable, MySeqNonCopyable) =
|
||||
result = (newMySeq(x, 1.0), newMySeq(y, 5.0))
|
||||
|
||||
proc myfunc2(x, y: int): tuple[a: MySeqNonCopyable, b:int, c:MySeqNonCopyable] =
|
||||
(a: newMySeq(x, 1.0), b:0, c:newMySeq(y, 5.0))
|
||||
|
||||
let (seq1, seq2) = myfunc(2, 3)
|
||||
doAssert seq1.len == 2
|
||||
doAssert seq1[0] == 1.0
|
||||
doAssert seq2.len == 3
|
||||
doAssert seq2[0] == 5.0
|
||||
|
||||
var (seq3, i, _) = myfunc2(2, 3)
|
||||
doAssert seq3.len == 2
|
||||
doAssert seq3[0] == 1.0
|
||||
Reference in New Issue
Block a user