diff options
author | Andreas Rumpf <rumpf_a@web.de> | 2019-12-05 16:59:06 +0100 |
---|---|---|
committer | Miran <narimiran@disroot.org> | 2019-12-05 16:59:06 +0100 |
commit | 3fbb3bfd3f440c059d6290c12834a38a61da98f2 (patch) | |
tree | b4561f510b23ce4fe2a19e58e15246c5ec5293a0 /compiler | |
parent | 9b0e874687177af4f758b70994b3a08f963a75cd (diff) | |
download | Nim-3fbb3bfd3f440c059d6290c12834a38a61da98f2.tar.gz |
ARC related bugfixes and refactorings (#12781)
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/ast.nim | 20 | ||||
-rw-r--r-- | compiler/ccgstmts.nim | 13 | ||||
-rw-r--r-- | compiler/cgen.nim | 2 | ||||
-rw-r--r-- | compiler/injectdestructors.nim | 427 | ||||
-rw-r--r-- | compiler/semtypinst.nim | 4 |
5 files changed, 219 insertions, 247 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 9fbcab144..208e99c4a 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1456,7 +1456,7 @@ proc isGCedMem*(t: PType): bool {.inline.} = result = t.kind in {tyString, tyRef, tySequence} or t.kind == tyProc and t.callConv == ccClosure -proc propagateToOwner*(owner, elem: PType) = +proc propagateToOwner*(owner, elem: PType; propagateHasAsgn = true) = const HaveTheirOwnEmpty = {tySequence, tyOpt, tySet, tyPtr, tyRef, tyProc} owner.flags = owner.flags + (elem.flags * {tfHasMeta, tfTriggersCompileTime}) if tfNotNil in elem.flags: @@ -1472,19 +1472,13 @@ proc propagateToOwner*(owner, elem: PType) = if elem.isMetaType: owner.flags.incl tfHasMeta - if tfHasAsgn in elem.flags: + let mask = elem.flags * {tfHasAsgn, tfHasOwned} + if mask != {} and propagateHasAsgn: let o2 = owner.skipTypes({tyGenericInst, tyAlias, tySink}) if o2.kind in {tyTuple, tyObject, tyArray, tySequence, tyOpt, tySet, tyDistinct, tyOpenArray, tyVarargs}: - o2.flags.incl tfHasAsgn - owner.flags.incl tfHasAsgn - - if tfHasOwned in elem.flags: - let o2 = owner.skipTypes({tyGenericInst, tyAlias, tySink}) - if o2.kind in {tyTuple, tyObject, tyArray, - tySequence, tyOpt, tySet, tyDistinct, tyOpenArray, tyVarargs}: - o2.flags.incl tfHasOwned - owner.flags.incl tfHasOwned + o2.flags.incl mask + owner.flags.incl mask if owner.kind notin {tyProc, tyGenericInst, tyGenericBody, tyGenericInvocation, tyPtr}: @@ -1494,11 +1488,11 @@ proc propagateToOwner*(owner, elem: PType) = # ensure this doesn't bite us in sempass2. owner.flags.incl tfHasGCedMem -proc rawAddSon*(father, son: PType) = +proc rawAddSon*(father, son: PType; propagateHasAsgn = true) = when not defined(nimNoNilSeqs): if isNil(father.sons): father.sons = @[] father.sons.add(son) - if not son.isNil: propagateToOwner(father, son) + if not son.isNil: propagateToOwner(father, son, propagateHasAsgn) proc rawAddSonNoPropagationOfTypeFlags*(father, son: PType) = when not defined(nimNoNilSeqs): diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 59db5cb72..34fb06af8 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -1041,7 +1041,7 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) = linefmt(p, cpsStmts, "#popSafePoint();$n", []) genRestoreFrameAfterException(p) elif 1 < t.len and t[1].kind == nkExceptBranch: - startBlock(p, "if (#getCurrentException()) {$n") + startBlock(p, "if (#nimBorrowCurrentException()) {$n") else: startBlock(p) p.nestedTryStmts[^1].inExcept = true @@ -1068,7 +1068,7 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) = else: genTypeInfo(p.module, t[i][j].typ, t[i][j].info) let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type" - appcg(p.module, orExpr, "#isObj(#getCurrentException()->$1, $2)", [memberName, checkFor]) + appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor]) if i > 1: line(p, cpsStmts, "else ") startBlock(p, "if ($1) {$n", [orExpr]) @@ -1082,7 +1082,14 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) = endBlock(p) # end of else block if i < t.len and t[i].kind == nkFinally: p.finallySafePoints.add(safePoint) - genSimpleBlock(p, t[i][0]) + startBlock(p) + genStmts(p, t[i][0]) + # pretend we handled the exception in a 'finally' so that we don't + # re-raise the unhandled one but instead keep the old one (it was + # not popped either): + if not quirkyExceptions and getCompilerProc(p.module.g.graph, "nimLeaveFinally") != nil: + linefmt(p, cpsStmts, "if ($1.status != 0) #nimLeaveFinally();$n", [safePoint]) + endBlock(p) discard pop(p.finallySafePoints) if not quirkyExceptions: linefmt(p, cpsStmts, "if ($1.status != 0) #reraiseException();$n", [safePoint]) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 12acd7825..a456b7d51 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1884,7 +1884,7 @@ proc shouldRecompile(m: BModule; code: Rope, cfile: Cfile): bool = if not moduleHasChanged(m.g.graph, m.module): result = false elif not equalsFile(code, cfile.cname): - if false: + when false: #m.config.symbolFiles == readOnlySf: #isDefined(m.config, "nimdiff"): if fileExists(cfile.cname): copyFile(cfile.cname.string, cfile.cname.string & ".backup") diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index de723b776..7a8c18f13 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -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) +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[1] = p(n[1], c, sinkArg) + elif n.kind in {nkObjDownConv, nkObjUpConv}: + result = copyTree(n) + result[0] = p(n[0], c, sinkArg) 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) + # copy objects that are not temporary but passed to a 'sink' parameter + result = passCopyToSink(n, c) + else: + 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[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) + 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: - 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) - 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 + 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: - 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) - 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) - else: - result = shallowCopy(n) - for i in 0..<n.len: - result[i] = p(n[i], c, consumed) + 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): + 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: + when false: + result = moveOrCopy(dest, ri[0], c) let copyRi = copyTree(ri) - copyRi[1] = result[^1] + copyRi[0] = result[^1] result[^1] = copyRi - of nkObjDownConv, nkObjUpConv: - 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: diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 786a9e4f8..6d9e9873e 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -307,6 +307,8 @@ proc instCopyType*(cl: var TReplTypeVars, t: PType): PType = if not (t.kind in tyMetaTypes or (t.kind == tyStatic and t.n == nil)): result.flags.excl tfInstClearedFlags + else: + result.flags.excl tfHasAsgn when false: if newDestructors: result.assignment = nil @@ -380,7 +382,7 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType = for i in 1..<t.len: # if one of the params is not concrete, we cannot do anything # but we already raised an error! - rawAddSon(result, header[i]) + rawAddSon(result, header[i], propagateHasAsgn = false) if body.kind == tyError: return |