diff options
-rw-r--r-- | compiler/ast.nim | 3 | ||||
-rw-r--r-- | compiler/ccgcalls.nim | 2 | ||||
-rw-r--r-- | compiler/ccgexprs.nim | 2 | ||||
-rw-r--r-- | compiler/cgen.nim | 4 | ||||
-rw-r--r-- | compiler/closureiters.nim | 4 | ||||
-rw-r--r-- | compiler/dfa.nim | 2 | ||||
-rw-r--r-- | compiler/docgen.nim | 4 | ||||
-rw-r--r-- | compiler/hlo.nim | 2 | ||||
-rw-r--r-- | compiler/injectdestructors.nim | 84 | ||||
-rw-r--r-- | compiler/jsgen.nim | 2 | ||||
-rw-r--r-- | compiler/lambdalifting.nim | 2 | ||||
-rw-r--r-- | compiler/nilcheck.nim | 2 | ||||
-rw-r--r-- | compiler/optimizer.nim | 2 | ||||
-rw-r--r-- | compiler/patterns.nim | 2 | ||||
-rw-r--r-- | compiler/renderer.nim | 7 | ||||
-rw-r--r-- | compiler/semgnrc.nim | 2 | ||||
-rw-r--r-- | compiler/semmagic.nim | 8 | ||||
-rw-r--r-- | compiler/semparallel.nim | 4 | ||||
-rw-r--r-- | compiler/sempass2.nim | 2 | ||||
-rw-r--r-- | compiler/semtempl.nim | 2 | ||||
-rw-r--r-- | compiler/suggest.nim | 2 | ||||
-rw-r--r-- | compiler/varpartitions.nim | 8 | ||||
-rw-r--r-- | compiler/vmgen.nim | 2 | ||||
-rw-r--r-- | lib/core/macros.nim | 3 | ||||
-rw-r--r-- | tests/arc/texplicit_sink.nim | 29 |
25 files changed, 116 insertions, 70 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index c4c183932..228f7381c 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -211,8 +211,7 @@ type nkDistinctTy, # distinct type nkProcTy, # proc type nkIteratorTy, # iterator type - nkSharedTy, # 'shared T' - # we use 'nkPostFix' for the 'not nil' addition + nkSinkAsgn, # '=sink(x, y)' nkEnumTy, # enum body nkEnumFieldDef, # `ident = expr` in an enumeration nkArgList, # argument list diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 81e74d089..c9ab1ddcb 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -335,7 +335,7 @@ proc getPotentialWrites(n: PNode; mutate: bool; result: var seq[PNode]) = of nkLiterals, nkIdent, nkFormalParams: discard of nkSym: if mutate: result.add n - of nkAsgn, nkFastAsgn: + of nkAsgn, nkFastAsgn, nkSinkAsgn: getPotentialWrites(n[0], true, result) getPotentialWrites(n[1], mutate, result) of nkAddr, nkHiddenAddr: diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index f71a4ddbd..a34e0535c 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -3086,7 +3086,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = cow(p, n[1]) if nfPreventCg notin n.flags: genAsgn(p, n, fastAsgn=false) - of nkFastAsgn: + of nkFastAsgn, nkSinkAsgn: cow(p, n[1]) if nfPreventCg notin n.flags: # transf is overly aggressive with 'nkFastAsgn', so we work around here. diff --git a/compiler/cgen.nim b/compiler/cgen.nim index e2b7c67ad..5fc42bfec 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -926,7 +926,7 @@ proc easyResultAsgn(n: PNode): PNode = var i = 0 while i < n.len and n[i].kind in harmless: inc i if i < n.len: result = easyResultAsgn(n[i]) - of nkAsgn, nkFastAsgn: + of nkAsgn, nkFastAsgn, nkSinkAsgn: if n[0].kind == nkSym and n[0].sym.kind == skResult and not containsResult(n[1]): incl n.flags, nfPreventCg return n[1] @@ -968,7 +968,7 @@ proc allPathsAsgnResult(n: PNode): InitResultEnum = for it in n: result = allPathsAsgnResult(it) if result != Unknown: return result - of nkAsgn, nkFastAsgn: + of nkAsgn, nkFastAsgn, nkSinkAsgn: if n[0].kind == nkSym and n[0].sym.kind == skResult: if not containsResult(n[1]): result = InitSkippable else: result = InitRequired diff --git a/compiler/closureiters.nim b/compiler/closureiters.nim index 613fbe582..79038a4f5 100644 --- a/compiler/closureiters.nim +++ b/compiler/closureiters.nim @@ -718,7 +718,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode = n[^1] = ex result.add(n) - of nkAsgn, nkFastAsgn: + of nkAsgn, nkFastAsgn, nkSinkAsgn: var ns = false for i in 0..<n.len: n[i] = ctx.lowerStmtListExprs(n[i], ns) @@ -868,7 +868,7 @@ proc transformReturnsInTry(ctx: var Ctx, n: PNode): PNode = if n[0].kind != nkEmpty: let asgnTmpResult = newNodeI(nkAsgn, n.info) asgnTmpResult.add(ctx.newTmpResultAccess()) - let x = if n[0].kind in {nkAsgn, nkFastAsgn}: n[0][1] else: n[0] + let x = if n[0].kind in {nkAsgn, nkFastAsgn, nkSinkAsgn}: n[0][1] else: n[0] asgnTmpResult.add(x) result.add(asgnTmpResult) diff --git a/compiler/dfa.nim b/compiler/dfa.nim index 001fcdbe7..61a921ba0 100644 --- a/compiler/dfa.nim +++ b/compiler/dfa.nim @@ -433,7 +433,7 @@ proc gen(c: var Con; n: PNode) = else: genCall(c, n) of nkCharLit..nkNilLit: discard - of nkAsgn, nkFastAsgn: + of nkAsgn, nkFastAsgn, nkSinkAsgn: gen(c, n[1]) if n[0].kind in PathKinds0: diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 9271d4975..e2c04430c 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -400,7 +400,7 @@ proc genRecCommentAux(d: PDoc, n: PNode): PRstNode = result = genComment(d, n) if result == nil: if n.kind in {nkStmtList, nkStmtListExpr, nkTypeDef, nkConstDef, - nkObjectTy, nkRefTy, nkPtrTy, nkAsgn, nkFastAsgn, nkHiddenStdConv}: + nkObjectTy, nkRefTy, nkPtrTy, nkAsgn, nkFastAsgn, nkSinkAsgn, nkHiddenStdConv}: # notin {nkEmpty..nkNilLit, nkEnumTy, nkTupleTy}: for i in 0..<n.len: result = genRecCommentAux(d, n[i]) @@ -1551,7 +1551,7 @@ proc genSection(d: PDoc, kind: TSymKind, groupedToc = false) = else: # Just have the link d.toc[kind] = getConfigVar(d.conf, "doc.section.toc_item") % sectionValues - + proc relLink(outDir: AbsoluteDir, destFile: AbsoluteFile, linkto: RelativeFile): string = $relativeTo(outDir / linkto, destFile.splitFile().dir, '/') diff --git a/compiler/hlo.nim b/compiler/hlo.nim index e3670312e..1aab9d5fe 100644 --- a/compiler/hlo.nim +++ b/compiler/hlo.nim @@ -71,7 +71,7 @@ proc hlo(c: PContext, n: PNode): PNode = # already processed (special cases in semstmts.nim) result = n else: - if n.kind in {nkFastAsgn, nkAsgn, nkIdentDefs, nkVarTuple} and + if n.kind in {nkFastAsgn, nkAsgn, nkSinkAsgn, nkIdentDefs, nkVarTuple} and n[0].kind == nkSym and {sfGlobal, sfPure} * n[0].sym.flags == {sfGlobal, sfPure}: # do not optimize 'var g {.global} = re(...)' again! diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index b41fc4ab5..ad43e23fc 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -78,7 +78,12 @@ proc nestedScope(parent: var Scope; body: PNode): Scope = Scope(vars: @[], locals: @[], wasMoved: @[], final: @[], body: body, needsTry: false, parent: addr(parent)) proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSingleUsedTemp}): PNode -proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope; isDecl = false): PNode + +type + MoveOrCopyFlag = enum + IsDecl, IsExplicitSink + +proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope; flags: set[MoveOrCopyFlag] = {}): PNode when false: var @@ -243,8 +248,8 @@ proc canBeMoved(c: Con; t: PType): bool {.inline.} = proc isNoInit(dest: PNode): bool {.inline.} = result = dest.kind == nkSym and sfNoInit in dest.sym.flags -proc genSink(c: var Con; dest, ri: PNode, isDecl = false): PNode = - if (c.inLoopCond == 0 and (isUnpackedTuple(dest) or isDecl or +proc genSink(c: var Con; dest, ri: PNode; flags: set[MoveOrCopyFlag] = {}): PNode = + if (c.inLoopCond == 0 and (isUnpackedTuple(dest) or IsDecl in flags or (isAnalysableFieldAccess(dest, c.owner) and isFirstWrite(dest, c)))) or isNoInit(dest): # optimize sink call into a bitwise memcopy @@ -296,17 +301,21 @@ proc genMarkCyclic(c: var Con; result, dest: PNode) = xenv.typ = getSysType(c.graph, dest.info, tyPointer) result.add callCodegenProc(c.graph, "nimMarkCyclic", dest.info, xenv) -proc genCopyNoCheck(c: var Con; dest, ri: PNode): PNode = +proc genCopyNoCheck(c: var Con; dest, ri: PNode; a: TTypeAttachedOp): PNode = let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink}) - result = c.genOp(t, attachedAsgn, dest, ri) + result = c.genOp(t, a, dest, ri) assert ri.typ != nil -proc genCopy(c: var Con; dest, ri: PNode): PNode = +proc genCopy(c: var Con; dest, ri: PNode; flags: set[MoveOrCopyFlag]): PNode = let t = dest.typ if tfHasOwned in t.flags and ri.kind != nkNilLit: # try to improve the error message here: - c.checkForErrorPragma(t, ri, "=copy") - result = c.genCopyNoCheck(dest, ri) + if IsExplicitSink in flags: + c.checkForErrorPragma(t, ri, "=sink") + else: + c.checkForErrorPragma(t, ri, "=copy") + let a = if IsExplicitSink in flags: attachedSink else: attachedAsgn + result = c.genCopyNoCheck(dest, ri, a) assert ri.typ != nil proc genDiscriminantAsgn(c: var Con; s: var Scope; n: PNode): PNode = @@ -391,7 +400,7 @@ proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode = let tmp = c.getTemp(s, n.typ, n.info) if hasDestructor(c, n.typ): result.add c.genWasMoved(tmp) - var m = c.genCopy(tmp, n) + var m = c.genCopy(tmp, n, {}) m.add p(n, c, s, normal) c.finishCopy(m, n, isFromSink = true) result.add m @@ -436,7 +445,7 @@ proc ensureDestruction(arg, orig: PNode; c: var Con; s: var Scope): PNode = # This was already done in the sink parameter handling logic. result = newNodeIT(nkStmtListExpr, arg.info, arg.typ) let tmp = c.getTemp(s, arg.typ, arg.info) - result.add c.genSink(tmp, arg, isDecl = true) + result.add c.genSink(tmp, arg, {IsDecl}) result.add tmp s.final.add c.genDestroy(tmp) else: @@ -518,7 +527,7 @@ template processScopeExpr(c: var Con; s: var Scope; ret: PNode, processCall: unt tmp.sym.flags = tmpFlags let cpy = if hasDestructor(c, ret.typ): s.parent[].final.add c.genDestroy(tmp) - moveOrCopy(tmp, ret, c, s, isDecl = true) + moveOrCopy(tmp, ret, c, s, {IsDecl}) else: newTree(nkFastAsgn, tmp, p(ret, c, s, normal)) @@ -654,7 +663,7 @@ proc pRaiseStmt(n: PNode, c: var Con; s: var Scope): PNode = result.add call else: let tmp = c.getTemp(s, n[0].typ, n.info) - var m = c.genCopyNoCheck(tmp, n[0]) + var m = c.genCopyNoCheck(tmp, n[0], attachedAsgn) m.add p(n[0], c, s, normal) c.finishCopy(m, n[0], isFromSink = false) result = newTree(nkStmtList, c.genWasMoved(tmp), m) @@ -818,9 +827,9 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing s.locals.add v.sym pVarTopLevel(v, c, s, result) if ri.kind != nkEmpty: - result.add moveOrCopy(v, ri, c, s, isDecl = v.kind == nkSym) + result.add moveOrCopy(v, ri, c, s, if v.kind == nkSym: {IsDecl} else: {}) elif ri.kind == nkEmpty and c.inLoop > 0: - result.add moveOrCopy(v, genDefaultCall(v.typ, c, v.info), c, s, isDecl = v.kind == nkSym) + result.add moveOrCopy(v, genDefaultCall(v.typ, c, v.info), c, s, if v.kind == nkSym: {IsDecl} else: {}) else: # keep the var but transform 'ri': var v = copyNode(n) var itCopy = copyNode(it) @@ -833,12 +842,13 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing itCopy.add p(it[^1], c, s, normal, tmpFlags = flags) v.add itCopy result.add v - of nkAsgn, nkFastAsgn: + of nkAsgn, nkFastAsgn, nkSinkAsgn: if hasDestructor(c, n[0].typ) and n[1].kind notin {nkProcDef, nkDo, nkLambda}: if n[0].kind in {nkDotExpr, nkCheckedFieldExpr}: cycleCheck(n, c) - assert n[1].kind notin {nkAsgn, nkFastAsgn} - result = moveOrCopy(p(n[0], c, s, mode), n[1], c, s) + assert n[1].kind notin {nkAsgn, nkFastAsgn, nkSinkAsgn} + let flags = if n.kind == nkSinkAsgn: {IsExplicitSink} else: {} + result = moveOrCopy(p(n[0], c, s, mode), n[1], c, s, flags) elif isDiscriminantField(n[0]): result = c.genDiscriminantAsgn(s, n) else: @@ -963,7 +973,7 @@ proc sameLocation*(a, b: PNode): bool = of nkHiddenStdConv, nkHiddenSubConv: sameLocation(a[1], b) else: false -proc genFieldAccessSideEffects(c: var Con; dest, ri: PNode, isDecl: bool): PNode = +proc genFieldAccessSideEffects(c: var Con; dest, ri: PNode; flags: set[MoveOrCopyFlag] = {}): PNode = # with side effects var temp = newSym(skLet, getIdent(c.graph.cache, "bracketTmp"), nextSymId c.idgen, c.owner, ri[1].info) temp.typ = ri[1].typ @@ -980,17 +990,17 @@ proc genFieldAccessSideEffects(c: var Con; dest, ri: PNode, isDecl: bool): PNode newAccess.add ri[0] newAccess.add tempAsNode - var snk = c.genSink(dest, newAccess, isDecl) + var snk = c.genSink(dest, newAccess, flags) result = newTree(nkStmtList, v, snk, c.genWasMoved(newAccess)) -proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, isDecl = false): PNode = +proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopyFlag] = {}): PNode = if sameLocation(dest, ri): # rule (self-assignment-removal): result = newNodeI(nkEmpty, dest.info) elif isCursor(dest): case ri.kind: of nkStmtListExpr, nkBlockExpr, nkIfExpr, nkCaseStmt, nkTryStmt: - template process(child, s): untyped = moveOrCopy(dest, child, c, s, isDecl) + template process(child, s): untyped = moveOrCopy(dest, child, c, s, flags) # We know the result will be a stmt so we use that fact to optimize handleNestedTempl(ri, process, willProduceStmt = true) else: @@ -998,53 +1008,53 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, isDecl = false): PNod else: case ri.kind of nkCallKinds: - result = c.genSink(dest, p(ri, c, s, consumed), isDecl) + result = c.genSink(dest, p(ri, c, s, consumed), flags) of nkBracketExpr: if isUnpackedTuple(ri[0]): # unpacking of tuple: take over the elements - result = c.genSink(dest, p(ri, c, s, consumed), isDecl) + result = c.genSink(dest, p(ri, c, s, consumed), flags) elif isAnalysableFieldAccess(ri, c.owner) and isLastRead(ri, c, s): if aliases(dest, ri) == no: # Rule 3: `=sink`(x, z); wasMoved(z) if isAtom(ri[1]): - var snk = c.genSink(dest, ri, isDecl) + var snk = c.genSink(dest, ri, flags) result = newTree(nkStmtList, snk, c.genWasMoved(ri)) else: - result = genFieldAccessSideEffects(c, dest, ri, isDecl) + result = genFieldAccessSideEffects(c, dest, ri, flags) else: - result = c.genSink(dest, destructiveMoveVar(ri, c, s), isDecl) + result = c.genSink(dest, destructiveMoveVar(ri, c, s), flags) else: - result = c.genCopy(dest, ri) + result = c.genCopy(dest, ri, flags) result.add p(ri, c, s, consumed) c.finishCopy(result, dest, isFromSink = false) of nkBracket: # array constructor if ri.len > 0 and isDangerousSeq(ri.typ): - result = c.genCopy(dest, ri) + result = c.genCopy(dest, ri, flags) result.add p(ri, c, s, consumed) c.finishCopy(result, dest, isFromSink = false) else: - result = c.genSink(dest, p(ri, c, s, consumed), isDecl) + result = c.genSink(dest, p(ri, c, s, consumed), flags) of nkObjConstr, nkTupleConstr, nkClosure, nkCharLit..nkNilLit: - result = c.genSink(dest, p(ri, c, s, consumed), isDecl) + result = c.genSink(dest, p(ri, c, s, consumed), flags) of nkSym: if isSinkParam(ri.sym) and isLastRead(ri, c, s): # Rule 3: `=sink`(x, z); wasMoved(z) - let snk = c.genSink(dest, ri, isDecl) + let snk = c.genSink(dest, ri, flags) result = newTree(nkStmtList, snk, c.genWasMoved(ri)) elif ri.sym.kind != skParam and ri.sym.owner == c.owner and isLastRead(ri, c, s) and canBeMoved(c, dest.typ) and not isCursor(ri): # Rule 3: `=sink`(x, z); wasMoved(z) - let snk = c.genSink(dest, ri, isDecl) + let snk = c.genSink(dest, ri, flags) result = newTree(nkStmtList, snk, c.genWasMoved(ri)) else: - result = c.genCopy(dest, ri) + result = c.genCopy(dest, ri, flags) result.add p(ri, c, s, consumed) c.finishCopy(result, dest, isFromSink = false) of nkHiddenSubConv, nkHiddenStdConv, nkConv, nkObjDownConv, nkObjUpConv, nkCast: - result = c.genSink(dest, p(ri, c, s, sinkArg), isDecl) + result = c.genSink(dest, p(ri, c, s, sinkArg), flags) of nkStmtListExpr, nkBlockExpr, nkIfExpr, nkCaseStmt, nkTryStmt: - template process(child, s): untyped = moveOrCopy(dest, child, c, s, isDecl) + template process(child, s): untyped = moveOrCopy(dest, child, c, s, flags) # We know the result will be a stmt so we use that fact to optimize handleNestedTempl(ri, process, willProduceStmt = true) of nkRaiseStmt: @@ -1053,10 +1063,10 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, isDecl = false): PNod if isAnalysableFieldAccess(ri, c.owner) and isLastRead(ri, c, s) and canBeMoved(c, dest.typ): # Rule 3: `=sink`(x, z); wasMoved(z) - let snk = c.genSink(dest, ri, isDecl) + let snk = c.genSink(dest, ri, flags) result = newTree(nkStmtList, snk, c.genWasMoved(ri)) else: - result = c.genCopy(dest, ri) + result = c.genCopy(dest, ri, flags) result.add p(ri, c, s, consumed) c.finishCopy(result, dest, isFromSink = false) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 267b9ba34..29bfb7df5 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -2711,7 +2711,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) = of nkReturnStmt: genReturnStmt(p, n) of nkBreakStmt: genBreakStmt(p, n) of nkAsgn: genAsgn(p, n) - of nkFastAsgn: genFastAsgn(p, n) + of nkFastAsgn, nkSinkAsgn: genFastAsgn(p, n) of nkDiscardStmt: if n[0].kind != nkEmpty: genLineDir(p, n) diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index ca9b29a77..a34f4ba94 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -782,7 +782,7 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: var DetectionPass; n[1] = liftCapturedVars(n[1], owner, d, c) if n[1].kind == nkClosure: result = n[1] of nkReturnStmt: - if n[0].kind in {nkAsgn, nkFastAsgn}: + if n[0].kind in {nkAsgn, nkFastAsgn, nkSinkAsgn}: # we have a `result = result` expression produced by the closure # transform, let's not touch the LHS in order to make the lifting pass # correct when `result` is lifted diff --git a/compiler/nilcheck.nim b/compiler/nilcheck.nim index 49ceb8942..91d76b2b8 100644 --- a/compiler/nilcheck.nim +++ b/compiler/nilcheck.nim @@ -1242,7 +1242,7 @@ proc check(n: PNode, ctx: NilCheckerContext, map: NilMap): Check = result = check(n.sons[0], ctx, map) of nkIfStmt, nkIfExpr: result = checkIf(n, ctx, map) - of nkAsgn: + of nkAsgn, nkFastAsgn, nkSinkAsgn: result = checkAsgn(n[0], n[1], ctx, map) of nkVarSection: result.map = map diff --git a/compiler/optimizer.nim b/compiler/optimizer.nim index 10b092e11..98939f80d 100644 --- a/compiler/optimizer.nim +++ b/compiler/optimizer.nim @@ -154,7 +154,7 @@ proc analyse(c: var Con; b: var BasicBlock; n: PNode) = nkTypeOfExpr, nkMixinStmt, nkBindStmt: discard "do not follow the construct" - of nkAsgn, nkFastAsgn: + of nkAsgn, nkFastAsgn, nkSinkAsgn: # reverse order, see remark for `=sink`: analyse(c, b, n[1]) analyse(c, b, n[0]) diff --git a/compiler/patterns.nim b/compiler/patterns.nim index d4577981f..ff9a9efa3 100644 --- a/compiler/patterns.nim +++ b/compiler/patterns.nim @@ -44,7 +44,7 @@ proc canonKind(n: PNode): TNodeKind = case result of nkCallKinds: result = nkCall of nkStrLit..nkTripleStrLit: result = nkStrLit - of nkFastAsgn: result = nkAsgn + of nkFastAsgn, nkSinkAsgn: result = nkAsgn else: discard proc sameKinds(a, b: PNode): bool {.inline.} = diff --git a/compiler/renderer.nim b/compiler/renderer.nim index eb410bc5d..f975dc896 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -518,7 +518,7 @@ proc lsub(g: TSrcGen; n: PNode): int = of nkOfInherit: result = lsub(g, n[0]) + len("of_") of nkProcTy: result = lsons(g, n) + len("proc_") of nkIteratorTy: result = lsons(g, n) + len("iterator_") - of nkSharedTy: result = lsons(g, n) + len("shared_") + of nkSinkAsgn: result = lsons(g, n) + len("`=sink`(, )") of nkEnumTy: if n.len > 0: result = lsub(g, n[0]) + lcomma(g, n, 1) + len("enum_") @@ -1170,6 +1170,11 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) = put(g, tkSpaces, Space) putWithSpace(g, tkEquals, "=") gsub(g, n, 1) + of nkSinkAsgn: + put(g, tkSymbol, "`=sink`") + put(g, tkParLe, "(") + gcomma(g, n) + put(g, tkParRi, ")") of nkChckRangeF: put(g, tkSymbol, "chckRangeF") put(g, tkParLe, "(") diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index d1c4acef6..0827e6845 100644 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -306,7 +306,7 @@ proc semGenericStmt(c: PContext, n: PNode, result.add newIdentNode(getIdent(c.cache, "[]"), n.info) for i in 0..<n.len: result.add(n[i]) result = semGenericStmt(c, result, flags, ctx) - of nkAsgn, nkFastAsgn: + of nkAsgn, nkFastAsgn, nkSinkAsgn: checkSonsLen(n, 2, c.config) let a = n[0] let b = n[1] diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index f815c7059..9e484e214 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -78,8 +78,8 @@ proc semArrPut(c: PContext; n: PNode; flags: TExprFlags): PNode = result[1] = n.lastSon result = semAsgn(c, result, noOverloadedSubscript) -proc semAsgnOpr(c: PContext; n: PNode): PNode = - result = newNodeI(nkAsgn, n.info, 2) +proc semAsgnOpr(c: PContext; n: PNode; k: TNodeKind): PNode = + result = newNodeI(k, n.info, 2) result[0] = n[1] result[1] = n[2] result = semAsgn(c, result, noOverloadedAsgn) @@ -553,7 +553,9 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode, result = semArrPut(c, n, flags) of mAsgn: if n[0].sym.name.s == "=": - result = semAsgnOpr(c, n) + result = semAsgnOpr(c, n, nkAsgn) + elif n[0].sym.name.s == "=sink": + result = semAsgnOpr(c, n, nkSinkAsgn) else: result = semShallowCopy(c, n, flags) of mIsPartOf: result = semIsPartOf(c, n, flags) diff --git a/compiler/semparallel.nim b/compiler/semparallel.nim index f696f6a0a..540a06c40 100644 --- a/compiler/semparallel.nim +++ b/compiler/semparallel.nim @@ -323,7 +323,7 @@ proc analyseIf(c: var AnalysisCtx; n: PNode) = proc analyse(c: var AnalysisCtx; n: PNode) = case n.kind - of nkAsgn, nkFastAsgn: + of nkAsgn, nkFastAsgn, nkSinkAsgn: let y = n[1].skipConv if n[0].isSingleAssignable and y.isLocal: let slot = c.getSlot(y.sym) @@ -442,7 +442,7 @@ proc transformSpawn(g: ModuleGraph; idgen: IdGenerator; owner: PSym; n, barrier: else: it[^1] = wrapProcForSpawn(g, idgen, owner, m, b.typ, barrier, nil) if result.isNil: result = n - of nkAsgn, nkFastAsgn: + of nkAsgn, nkFastAsgn, nkSinkAsgn: let b = n[1] if getMagic(b) == mSpawn and (let t = b[1][0].typ[0]; spawnResult(t, true) == srByVar): diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 42c463cd9..8916e2568 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -1053,7 +1053,7 @@ proc track(tracked: PEffects, n: PNode) = checkFieldAccess(tracked.guards, n, tracked.config) of nkTryStmt: trackTryStmt(tracked, n) of nkPragma: trackPragmaStmt(tracked, n) - of nkAsgn, nkFastAsgn: + of nkAsgn, nkFastAsgn, nkSinkAsgn: track(tracked, n[1]) initVar(tracked, n[0], volatileCheck=true) invalidateFacts(tracked.guards, n[0]) diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index ed2475341..c20f01023 100644 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -511,7 +511,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode = result.add newIdentNode(getIdent(c.c.cache, "{}"), n.info) for i in 0..<n.len: result.add(n[i]) result = semTemplBodySons(c, result) - of nkAsgn, nkFastAsgn: + of nkAsgn, nkFastAsgn, nkSinkAsgn: checkSonsLen(n, 2, c.c.config) let a = n[0] let b = n[1] diff --git a/compiler/suggest.nim b/compiler/suggest.nim index b5f787296..829335015 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -53,7 +53,7 @@ proc findDocComment(n: PNode): PNode = if result != nil: return if n.len > 1: result = findDocComment(n[1]) - elif n.kind in {nkAsgn, nkFastAsgn} and n.len == 2: + elif n.kind in {nkAsgn, nkFastAsgn, nkSinkAsgn} and n.len == 2: result = findDocComment(n[1]) proc extractDocComment(g: ModuleGraph; s: PSym): string = diff --git a/compiler/varpartitions.nim b/compiler/varpartitions.nim index 60eed5c78..c83da3277 100644 --- a/compiler/varpartitions.nim +++ b/compiler/varpartitions.nim @@ -686,7 +686,7 @@ proc traverse(c: var Partitions; n: PNode) = for i in 0..<child.len-2: #registerVariable(c, child[i]) deps(c, child[i], last) - of nkAsgn, nkFastAsgn: + of nkAsgn, nkFastAsgn, nkSinkAsgn: traverse(c, n[0]) inc c.inAsgnSource traverse(c, n[1]) @@ -779,7 +779,7 @@ proc traverse(c: var Partitions; n: PNode) = if n.kind == nkWhileStmt: traverse(c, n[0]) - # variables in while condition has longer alive time than local variables + # variables in while condition has longer alive time than local variables # in the while loop body else: for child in n: traverse(c, child) @@ -811,7 +811,7 @@ proc computeLiveRanges(c: var Partitions; n: PNode) = registerVariable(c, child[i]) #deps(c, child[i], last) - of nkAsgn, nkFastAsgn: + of nkAsgn, nkFastAsgn, nkSinkAsgn: computeLiveRanges(c, n[0]) computeLiveRanges(c, n[1]) if n[0].kind == nkSym: @@ -871,7 +871,7 @@ proc computeLiveRanges(c: var Partitions; n: PNode) = if n.kind == nkWhileStmt: computeLiveRanges(c, n[0]) - # variables in while condition has longer alive time than local variables + # variables in while condition has longer alive time than local variables # in the while loop body of nkElifBranch, nkElifExpr, nkElse, nkOfBranch: inc c.inConditional diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index ec2d068b7..a326428f9 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -2045,7 +2045,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) = of nkNilLit: if not n.typ.isEmptyType: genLit(c, getNullValue(n.typ, n.info, c.config), dest) else: unused(c, n, dest) - of nkAsgn, nkFastAsgn: + of nkAsgn, nkFastAsgn, nkSinkAsgn: unused(c, n, dest) genAsgn(c, n[0], n[1], n.kind == nkAsgn) of nkDotExpr: genObjAccess(c, n, dest, flags) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index d09ea2fe2..b26264405 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -79,7 +79,7 @@ type nnkDistinctTy, nnkProcTy, nnkIteratorTy, # iterator type - nnkSharedTy, # 'shared T' + nnkSinkAsgn, nnkEnumTy, nnkEnumFieldDef, nnkArgList, nnkPattern @@ -127,6 +127,7 @@ type const nnkMutableTy* {.deprecated.} = nnkOutTy + nnkSharedTy* {.deprecated.} = nnkSinkAsgn type NimIdent* {.deprecated.} = object of RootObj diff --git a/tests/arc/texplicit_sink.nim b/tests/arc/texplicit_sink.nim new file mode 100644 index 000000000..4b021ed62 --- /dev/null +++ b/tests/arc/texplicit_sink.nim @@ -0,0 +1,29 @@ +discard """ + output: '''de''' + cmd: '''nim c --mm:arc --expandArc:main $file''' + nimout: '''--expandArc: main + +var + a + b_cursor +try: + a = f "abc" + b_cursor = "de" + `=sink`(a, b_cursor) + echo [a] +finally: + `=destroy`(a) +-- end of expandArc ------------------------''' +""" + +# bug #20572 + +proc f(s: string): string = s + +proc main = + var a = f "abc" + var b = "de" + `=sink`(a, b) + echo a + +main() |