From 71dd5f85b9a13d97ea0c74338722bf08a9ae6286 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 20 Jul 2020 07:50:19 +0200 Subject: [PATCH] 'isolate' builtin; refs https://github.com/nim-lang/RFCs/issues/244 (#15011) --- compiler/ast.nim | 2 +- compiler/ccgexprs.nim | 2 +- compiler/isolation_check.nim | 117 +++++++++++++++++++++++++++++++++++ compiler/jsgen.nim | 2 +- compiler/sem.nim | 3 +- compiler/semmagic.nim | 5 +- compiler/vmgen.nim | 2 +- lib/std/isolation.nim | 31 ++++++++++ tests/isolate/tisolate.nim | 36 +++++++++++ 9 files changed, 194 insertions(+), 6 deletions(-) create mode 100644 compiler/isolation_check.nim create mode 100644 lib/std/isolation.nim create mode 100644 tests/isolate/tisolate.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index b57ee542ddf96..d8fe6b1c08e75 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -658,7 +658,7 @@ type mSwap, mIsNil, mArrToSeq, mNewString, mNewStringOfCap, mParseBiggestFloat, mMove, mWasMoved, mDestroy, - mDefault, mUnown, mAccessEnv, mReset, + mDefault, mUnown, mIsolate, mAccessEnv, mReset, mArray, mOpenArray, mRange, mSet, mSeq, mVarargs, mRef, mPtr, mVar, mDistinct, mVoid, mTuple, mOrdinal, diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index dc9617fe2b4ce..003b3e240c7f2 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -2209,7 +2209,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mCharToStr: genDollar(p, e, d, "#nimCharToStr($1)") of mFloatToStr: genDollar(p, e, d, "#nimFloatToStr($1)") of mCStrToStr: genDollar(p, e, d, "#cstrToNimstr($1)") - of mStrToStr, mUnown: expr(p, e[1], d) + of mStrToStr, mUnown, mIsolate: expr(p, e[1], d) of mEnumToStr: if optTinyRtti in p.config.globalOptions: genEnumToStr(p, e, d) diff --git a/compiler/isolation_check.nim b/compiler/isolation_check.nim new file mode 100644 index 0000000000000..a77e8c97af270 --- /dev/null +++ b/compiler/isolation_check.nim @@ -0,0 +1,117 @@ +# +# +# The Nim Compiler +# (c) Copyright 2020 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## Implementation of the check that `recover` needs, see +## https://github.com/nim-lang/RFCs/issues/244 for more details. + +import + ast, types, renderer, idents, intsets, options, msgs + +proc canAlias(arg, ret: PType; marker: var IntSet): bool + +proc canAliasN(arg: PType; n: PNode; marker: var IntSet): bool = + case n.kind + of nkRecList: + for i in 0.. 0 and ret[0] != nil: + result = canAlias(arg, ret[0], marker) + else: + result = true + of tyTuple: + for i in 0.. 0: + result = checkIsolate(n[^1]) + else: + result = false + else: + # unanalysable expression: + result = false + else: + # no ref, no cry: + result = true + diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 57a6b80942c9c..d876531e94867 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -653,7 +653,7 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) = useMagic(p, "nimFloatToString") applyFormat "cstrToNimstr(nimFloatToString($1))" of mCStrToStr: applyFormat("cstrToNimstr($1)", "cstrToNimstr($1)") - of mStrToStr, mUnown: applyFormat("$1", "$1") + of mStrToStr, mUnown, mIsolate: applyFormat("$1", "$1") else: assert false, $op diff --git a/compiler/sem.nim b/compiler/sem.nim index a657939a5b775..1f98b4f874d47 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -16,7 +16,8 @@ import procfind, lookups, pragmas, passes, semdata, semtypinst, sigmatch, intsets, transf, vmdef, vm, idgen, aliases, cgmeth, lambdalifting, evaltempl, patterns, parampatterns, sempass2, linter, semmacrosanity, - lowerings, plugins/active, rod, lineinfos, strtabs, int128 + lowerings, plugins/active, rod, lineinfos, strtabs, int128, + isolation_check from modulegraphs import ModuleGraph, PPassContext, onUse, onDef, onDefResolveForward diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index e7a964d81bf1d..6aa440aa9ed78 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -558,6 +558,9 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode, let constructed = result[1].typ.base if constructed.requiresInit: message(c.config, n.info, warnUnsafeDefault, typeToString(constructed)) + of mIsolate: + if not checkIsolate(n[1]): + localError(c.config, n.info, "expression cannot be isolated: " & $n[1]) + result = n else: result = n - diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 52b7b6eb3e75f..4ef510d20b0d1 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -997,7 +997,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = c.genNarrow(n[1], d) c.genAsgnPatch(n[1], d) c.freeTemp(d) - of mOrd, mChr, mArrToSeq, mUnown: c.gen(n[1], dest) + of mOrd, mChr, mArrToSeq, mUnown, mIsolate: c.gen(n[1], dest) of mNew, mNewFinalize: unused(c, n, dest) c.genNew(n) diff --git a/lib/std/isolation.nim b/lib/std/isolation.nim new file mode 100644 index 0000000000000..7ca5f008008ba --- /dev/null +++ b/lib/std/isolation.nim @@ -0,0 +1,31 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2020 Nim contributors +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module implements the `Isolated[T]` type for +## safe construction of isolated subgraphs that can be +## passed efficiently to different channels and threads. + +type + Isolated*[T] = object ## Isolated data can only be moved, not copied. + value: T + +proc `=`*[T](dest: var Isolated[T]; src: Isolated[T]) {.error.} + +proc `=sink`*[T](dest: var Isolated[T]; src: Isolated[T]) {.inline.} = + # delegate to value's sink operation + `=sink`(dest.value, src.value) + +proc `=destroy`*[T](dest: var Isolated[T]) {.inline.} = + # delegate to value's destroy operation + `=destroy`(dest.value) + +func isolate*[T](value: sink T): Isolated[T] {.magic: "Isolate".} + ## Create an isolated subgraph from the expression `value`. + ## Please read https://github.com/nim-lang/RFCs/issues/244 + ## for more details. diff --git a/tests/isolate/tisolate.nim b/tests/isolate/tisolate.nim new file mode 100644 index 0000000000000..9f3b154412274 --- /dev/null +++ b/tests/isolate/tisolate.nim @@ -0,0 +1,36 @@ +discard """ + errormsg: "expression cannot be isolated: select(a, b)" + line: 34 +""" + +import std / isolation + +import json, streams + +proc f(): seq[int] = + @[1, 2, 3] + +type + Node = ref object + x: string + +proc g(): Node = nil + +proc select(a, b: Node): Node = + a + +proc main = + discard isolate f() + + + discard isolate g() + + discard isolate select(Node(x: "a"), nil) + discard isolate select(Node(x: "a"), Node(x: "b")) + + discard isolate parseJson(newFileStream("my.json"), "my.json") + + var a, b: Node + discard isolate select(a, b) + +main()