summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2021-11-09 12:43:16 +0100
committerGitHub <noreply@github.com>2021-11-09 12:43:16 +0100
commitb7c66ce860cfbadfa8ed60784fc387a0818e2e5d (patch)
tree9009a0824ea365bc0eda9f67a477a1d66fd3e29c
parent83a9c3ba31d180cd5e31026d8b7603bf7adea18c (diff)
downloadNim-b7c66ce860cfbadfa8ed60784fc387a0818e2e5d.tar.gz
fixes #19013 [backport:1.6] (#19111)
* fixes #19013 [backport:1.6]

* added test case
-rw-r--r--compiler/ast.nim8
-rw-r--r--compiler/isolation_check.nim17
-rw-r--r--compiler/varpartitions.nim7
-rw-r--r--tests/isolate/tisolate2.nim22
4 files changed, 46 insertions, 8 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index abd2ff01e..9086860b9 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -2101,3 +2101,11 @@ proc skipAddr*(n: PNode): PNode {.inline.} =
 proc isNewStyleConcept*(n: PNode): bool {.inline.} =
   assert n.kind == nkTypeClassTy
   result = n[0].kind == nkEmpty
+
+const
+  nodesToIgnoreSet* = {nkNone..pred(nkSym), succ(nkSym)..nkNilLit,
+    nkTypeSection, nkProcDef, nkConverterDef,
+    nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo,
+    nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt,
+    nkExportStmt, nkPragma, nkCommentStmt, nkBreakState,
+    nkTypeOfExpr, nkMixinStmt, nkBindStmt}
diff --git a/compiler/isolation_check.nim b/compiler/isolation_check.nim
index 777e7f6ce..a8c5a3651 100644
--- a/compiler/isolation_check.nim
+++ b/compiler/isolation_check.nim
@@ -77,6 +77,17 @@ proc canAlias*(arg, ret: PType): bool =
     var marker = initIntSet()
     result = canAlias(arg, ret, marker)
 
+proc containsVariable(n: PNode): bool =
+  case n.kind
+  of nodesToIgnoreSet:
+    result = false
+  of nkSym:
+    result = n.sym.kind in {skForVar, skParam, skVar, skLet, skConst, skResult, skTemp}
+  else:
+    for ch in n:
+      if containsVariable(ch): return true
+    result = false
+
 proc checkIsolate*(n: PNode): bool =
   if types.containsTyRef(n.typ):
     # XXX Maybe require that 'n.typ' is acyclic. This is not much
@@ -96,7 +107,11 @@ proc checkIsolate*(n: PNode): bool =
         else:
           let argType = n[i].typ
           if argType != nil and not isCompileTimeOnly(argType) and containsTyRef(argType):
-            if argType.canAlias(n.typ):
+            if argType.canAlias(n.typ) or containsVariable(n[i]):
+              # bug #19013: Alias information is not enough, we need to check for potential
+              # "overlaps". I claim the problem can only happen by reading again from a location
+              # that materialized which is only possible if a variable that contains a `ref`
+              # is involved.
               return false
       result = true
     of nkIfStmt, nkIfExpr:
diff --git a/compiler/varpartitions.nim b/compiler/varpartitions.nim
index 709d00fa0..721de900e 100644
--- a/compiler/varpartitions.nim
+++ b/compiler/varpartitions.nim
@@ -647,13 +647,6 @@ proc deps(c: var Partitions; dest, src: PNode) =
                 when explainCursors: echo "D not a cursor ", d.sym, " reassignedTo ", c.s[srcid].reassignedTo
                 c.s[vid].flags.incl preventCursor
 
-const
-  nodesToIgnoreSet = {nkNone..pred(nkSym), succ(nkSym)..nkNilLit,
-    nkTypeSection, nkProcDef, nkConverterDef,
-    nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo,
-    nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt,
-    nkExportStmt, nkPragma, nkCommentStmt, nkBreakState,
-    nkTypeOfExpr, nkMixinStmt, nkBindStmt}
 
 proc potentialMutationViaArg(c: var Partitions; n: PNode; callee: PType) =
   if constParameters in c.goals and tfNoSideEffect in callee.flags:
diff --git a/tests/isolate/tisolate2.nim b/tests/isolate/tisolate2.nim
new file mode 100644
index 000000000..9bf92d82e
--- /dev/null
+++ b/tests/isolate/tisolate2.nim
@@ -0,0 +1,22 @@
+discard """
+  errormsg: "expression cannot be isolated: a_to_b(a)"
+  line: 22
+"""
+
+# bug #19013
+import std/isolation
+
+type Z = ref object
+  i: int
+
+type A = object
+  z: Z
+
+type B = object
+  z: Z
+
+func a_to_b(a: A): B =
+  result = B(z: a.z)
+
+let a = A(z: Z(i: 3))
+let b = isolate(a_to_b(a))