diff options
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/ast.nim | 2 | ||||
-rw-r--r-- | compiler/ccgexprs.nim | 2 | ||||
-rw-r--r-- | compiler/isolation_check.nim | 117 | ||||
-rw-r--r-- | compiler/jsgen.nim | 2 | ||||
-rw-r--r-- | compiler/sem.nim | 3 | ||||
-rw-r--r-- | compiler/semmagic.nim | 5 | ||||
-rw-r--r-- | compiler/vmgen.nim | 2 |
7 files changed, 127 insertions, 6 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index b57ee542d..d8fe6b1c0 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 dc9617fe2..003b3e240 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 000000000..a77e8c97a --- /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..<n.len: + result = canAliasN(arg, n[i], marker) + if result: return + of nkRecCase: + assert(n[0].kind == nkSym) + result = canAliasN(arg, n[0], marker) + if result: return + for i in 1..<n.len: + case n[i].kind + of nkOfBranch, nkElse: + result = canAliasN(arg, lastSon(n[i]), marker) + if result: return + else: discard + of nkSym: + result = canAlias(arg, n.sym.typ, marker) + else: discard + +proc canAlias(arg, ret: PType; marker: var IntSet): bool = + if containsOrIncl(marker, ret.id): + return false + + if ret.kind in {tyPtr, tyPointer}: + # unsafe so we don't care: + return false + if compareTypes(arg, ret, dcEqIgnoreDistinct): + return true + case ret.kind + of tyObject: + if isFinal(ret): + result = canAliasN(arg, ret.n, marker) + if not result and ret.len > 0 and ret[0] != nil: + result = canAlias(arg, ret[0], marker) + else: + result = true + of tyTuple: + for i in 0..<ret.len: + result = canAlias(arg, ret[i], marker) + if result: break + of tyArray, tySequence, tyDistinct, tyGenericInst, + tyAlias, tyInferred, tySink, tyLent, tyOwned, tyRef: + result = canAlias(arg, ret.lastSon, marker) + of tyProc: + result = ret.callConv == ccClosure + else: + result = false + +proc canAlias(arg, ret: PType): bool = + var marker = initIntSet() + result = canAlias(arg, ret, marker) + +proc checkIsolate*(n: PNode): bool = + if types.containsTyRef(n.typ): + # XXX Maybe require that 'n.typ' is acyclic. This is not much + # worse than the already exisiting inheritance and closure restrictions. + case n.kind + of nkCharLit..nkNilLit: + result = true + of nkCallKinds: + if n[0].typ.flags * {tfGcSafe, tfNoSideEffect} == {}: + return false + for i in 1..<n.len: + if checkIsolate(n[i]): + discard "fine, it is isolated already" + else: + let argType = n[i].typ + if argType != nil and not isCompileTimeOnly(argType) and containsTyRef(argType): + if argType.canAlias(n.typ): + return false + result = true + of nkIfStmt, nkIfExpr: + for it in n: + result = checkIsolate(it.lastSon) + if not result: break + of nkCaseStmt, nkObjConstr: + for i in 1..<n.len: + result = checkIsolate(n[i].lastSon) + if not result: break + of nkBracket, nkTupleConstr, nkPar: + for it in n: + result = checkIsolate(it) + if not result: break + of nkHiddenStdConv, nkHiddenSubConv, nkCast, nkConv: + result = checkIsolate(n[1]) + of nkObjUpConv, nkObjDownConv, nkDotExpr: + result = checkIsolate(n[0]) + of nkStmtList, nkStmtListExpr: + if n.len > 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 57a6b8094..d876531e9 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 a657939a5..1f98b4f87 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 e7a964d81..6aa440aa9 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 52b7b6eb3..4ef510d20 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) |