diff --git a/compiler/destroyer.nim b/compiler/destroyer.nim index 51ad26f2c..407204e51 100644 --- a/compiler/destroyer.nim +++ b/compiler/destroyer.nim @@ -116,7 +116,7 @@ Remarks: Rule 1.2 is not yet implemented because ``sink`` is currently import intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees, - strutils, options, dfa, lowerings, tables, modulegraphs, + strutils, options, dfa, lowerings, tables, modulegraphs, msgs, lineinfos, parampatterns const @@ -127,20 +127,11 @@ type owner: PSym g: ControlFlowGraph jumpTargets: IntSet - tmpObj: PType - tmp: PSym destroys, topLevelVars: PNode - toDropBit: Table[int, PSym] graph: ModuleGraph emptyNode: PNode otherRead: PNode -proc getTemp(c: var Con; typ: PType; info: TLineInfo): PNode = - # XXX why are temps fields in an object here? - let f = newSym(skField, getIdent(c.graph.cache, ":d" & $c.tmpObj.n.len), c.owner, info) - f.typ = typ - rawAddField c.tmpObj, f - result = rawDirectAccess(c.tmp, f) proc isHarmlessVar*(s: PSym; c: Con): bool = # 's' is harmless if it used only once and its @@ -329,22 +320,11 @@ proc genDestroy(c: Con; t: PType; dest: PNode): PNode = proc addTopVar(c: var Con; v: PNode) = c.topLevelVars.add newTree(nkIdentDefs, v, c.emptyNode, c.emptyNode) -proc dropBit(c: var Con; s: PSym): PSym = - result = c.toDropBit.getOrDefault(s.id) - assert result != nil - -proc registerDropBit(c: var Con; s: PSym) = - let result = newSym(skTemp, getIdent(c.graph.cache, s.name.s & "_AliveBit"), c.owner, s.info) - result.typ = getSysType(c.graph, s.info, tyBool) - let trueVal = newIntTypeNode(nkIntLit, 1, result.typ) - c.topLevelVars.add newTree(nkIdentDefs, newSymNode result, c.emptyNode, trueVal) - c.toDropBit[s.id] = result - # generate: - # if not sinkParam_AliveBit: `=destroy`(sinkParam) - let t = s.typ.skipTypes({tyGenericInst, tyAlias, tySink}) - if t.destructor != nil: - c.destroys.add newTree(nkIfStmt, - newTree(nkElifBranch, newSymNode result, genDestroy(c, t, newSymNode s))) +proc getTemp(c: var Con; typ: PType; info: TLineInfo): PNode = + let sym = newSym(skTemp, getIdent(c.graph.cache, ":tmpD"), c.owner, info) + sym.typ = typ + result = newSymNode(sym) + c.addTopVar(result) proc p(n: PNode; c: var Con): PNode @@ -355,16 +335,6 @@ template recurse(n, dest) = proc isSinkParam(s: PSym): bool {.inline.} = result = s.kind == skParam and s.typ.kind == tySink -proc destructiveMoveSink(n: PNode; c: var Con): PNode = - # generate: (chckMove(sinkParam_AliveBit); sinkParam_AliveBit = false; sinkParam) - result = newNodeIT(nkStmtListExpr, n.info, n.typ) - let bit = newSymNode dropBit(c, n.sym) - if optMoveCheck in c.owner.options: - result.add callCodegenProc(c.graph, "chckMove", bit.info, bit) - result.add newTree(nkAsgn, bit, - newIntTypeNode(nkIntLit, 0, getSysType(c.graph, n.info, tyBool))) - result.add n - proc genMagicCall(n: PNode; c: var Con; magicname: string; m: TMagic): PNode = result = newNodeI(nkCall, n.info) result.add(newSymNode(createMagic(c.graph, magicname, m))) @@ -395,6 +365,12 @@ proc destructiveMoveVar(n: PNode; c: var Con): PNode = result.add genWasMoved(n, c) result.add tempAsNode +proc sinkParamIsLastReadCheck(c: var Con, s: PNode) = + assert s.kind == nkSym and s.sym.kind == skParam + if not isLastRead(s, c): + localError(c.graph.config, c.otherRead.info, "sink parameter `" & $s.sym.name.s & + "` is already consumed at " & toFileLineCol(c. graph.config, s.info)) + proc passCopyToSink(n: PNode; c: var Con): PNode = result = newNodeIT(nkStmtListExpr, n.info, n.typ) let tmp = getTemp(c, n.typ, n.info) @@ -411,6 +387,11 @@ proc passCopyToSink(n: PNode; c: var Con): PNode = result.add tmp proc pArg(arg: PNode; c: var Con; isSink: bool): PNode = + template pArgIfTyped(arg_part: PNode): PNode = + # typ is nil if we are in if/case expr branch with noreturn + if arg_part.typ == nil: p(arg_part, c) + else: pArg(arg_part, c, isSink) + if isSink: if arg.kind in nkCallKinds: # recurse but skip the call expression in order to prevent @@ -421,17 +402,53 @@ proc pArg(arg: PNode; c: var Con; isSink: bool): PNode = result.add arg[0] for i in 1.. 0: - c.addTopVar(newSymNode c.tmp) result = newNodeI(nkStmtList, n.info) if c.topLevelVars.len > 0: result.add c.topLevelVars diff --git a/compiler/dfa.nim b/compiler/dfa.nim index 415cc4ab3..cd32d95d5 100644 --- a/compiler/dfa.nim +++ b/compiler/dfa.nim @@ -272,7 +272,7 @@ proc genReturn(c: var Con; n: PNode) = c.code.add Instr(n: n, kind: goto, dest: high(int) - c.code.len) const - InterestingSyms = {skVar, skResult, skLet} + InterestingSyms = {skVar, skResult, skLet, skParam} proc genUse(c: var Con; n: PNode) = var n = n diff --git a/tests/destructor/tmatrix.nim b/tests/destructor/tmatrix.nim index a16bfa37b..b89b41a4c 100644 --- a/tests/destructor/tmatrix.nim +++ b/tests/destructor/tmatrix.nim @@ -52,6 +52,8 @@ proc matrix*(m, n: int, s: float): Matrix = for i in 0 ..< m * n: result.data[i] = s +proc len(m: Matrix): int = m.n * m.m + proc `[]`*(m: Matrix, i, j: int): float {.inline.} = ## Get a single element. m.data[i * m.n + j] @@ -67,24 +69,26 @@ proc `[]=`*(m: var Matrix, i, j: int, s: float) = proc `-`*(m: sink Matrix): Matrix = ## Unary minus result = m - for i in 0 ..< m.m: - for j in 0 ..< m.n: - result[i, j] = -m[i, j] + for i in 0 ..< result.m: + for j in 0 ..< result.n: + result[i, j] = -result[i, j] proc `+`*(a: sink Matrix; b: Matrix): Matrix = ## ``C = A + B`` - assert(b.m == a.m and b.n == a.n, "Matrix dimensions must agree.") + doAssert(b.m == a.m and b.n == a.n, "Matrix dimensions must agree.") + doAssert(a.len == b.len) # non destructive use before sink is ok result = a - for i in 0 ..< a.m: - for j in 0 ..< a.n: - result[i, j] = a[i, j] + b[i, j] + for i in 0 ..< result.m: + for j in 0 ..< result.n: + result[i, j] = result[i, j] + b[i, j] proc `-`*(a: sink Matrix; b: Matrix): Matrix = ## ``C = A - B`` assert(b.m == a.m and b.n == a.n, "Matrix dimensions must agree.") + doAssert(a.len == b.len) # non destructive use before sink is ok result = a - for i in 0 ..< a.m: - for j in 0 ..< a.n: + for i in 0 ..< result.m: + for j in 0 ..< result.n: result[i, j] = a[i, j] - b[i, j] proc info = diff --git a/tests/destructor/tmove_objconstr.nim b/tests/destructor/tmove_objconstr.nim index 26cc682b5..51aba1592 100644 --- a/tests/destructor/tmove_objconstr.nim +++ b/tests/destructor/tmove_objconstr.nim @@ -109,7 +109,19 @@ proc myfunc(x, y: int): (MySeqNonCopyable, MySeqNonCopyable) = proc myfunc2(x, y: int): tuple[a: MySeqNonCopyable, b:int, c:MySeqNonCopyable] = var cc = newMySeq(y, 5.0) - (a: newMySeq(x, 1.0), b:0, c: cc) + (a: case x: + of 1: + let (z1, z2) = myfunc(x,y) + z2 + elif x > 5: raise newException(ValueError, "new error") + else: newMySeq(x, 1.0), + b: 0, + c: block: + var tmp = if y > 0: move(cc) else: newMySeq(1, 3.0) + tmp[0] = 5 + tmp + ) + let (seq1, seq2) = myfunc(2, 3) doAssert seq1.len == 2 @@ -122,4 +134,35 @@ doAssert seq3.len == 2 doAssert seq3[0] == 1.0 var seq4, seq5: MySeqNonCopyable -(seq4, i, seq5) = myfunc2(2, 3) \ No newline at end of file +(seq4, i, seq5) = myfunc2(2, 3) + +seq4 = block: + var tmp = newMySeq(4, 1.0) + tmp[0] = 3.0 + tmp + +doAssert seq4[0] == 3.0 + +import macros + +seq4 = + if i > 0: newMySeq(2, 5.0) + elif i < -100: raise newException(ValueError, "Parse Error") + else: newMySeq(2, 3.0) + +seq4 = + case (char) i: + of 'A', {'W'..'Z'}: newMySeq(2, 5.0) + of 'B': quit(-1) + else: + let (x1, x2, x3) = myfunc2(2, 3) + x3 + + +#------------------------------------------------------------ +#-- Move into array constructor +#------------------------------------------------------------ + +var ii = 1 +let arr2 = [newMySeq(2, 5.0), if i > 1: newMySeq(3, 1.0) else: newMySeq(0, 0.0)] +var seqOfSeq2 = @[newMySeq(2, 5.0), newMySeq(3, 1.0)]