summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2020-10-01 15:04:36 +0200
committerGitHub <noreply@github.com>2020-10-01 15:04:36 +0200
commitab405c936e77a875199aa1ee0f99eddd3d5a0c10 (patch)
tree5fb692102a125746bb4a05f767cfa7e16b6d54e3 /compiler
parent79a92da8efdb895ba5762ca9ed0471a3a5846068 (diff)
downloadNim-ab405c936e77a875199aa1ee0f99eddd3d5a0c10.tar.gz
views: yet another bugfix (#15447)
* views: yet another bugfix

* views: extended the spec

* views: take into account potential hidden mutations via proc calls
Diffstat (limited to 'compiler')
-rw-r--r--compiler/semtempl.nim5
-rw-r--r--compiler/trees.nim5
-rw-r--r--compiler/varpartitions.nim26
3 files changed, 27 insertions, 9 deletions
diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim
index 1ec8c07b0..df832c814 100644
--- a/compiler/semtempl.nim
+++ b/compiler/semtempl.nim
@@ -707,11 +707,6 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
       localError(c.c.config, n.info, "invalid expression")
       result = n
 
-  proc stupidStmtListExpr(n: PNode): bool =
-    for i in 0..<n.len-1:
-      if n[i].kind notin {nkEmpty, nkCommentStmt}: return false
-    result = true
-
   result = n
   case n.kind
   of nkIdent:
diff --git a/compiler/trees.nim b/compiler/trees.nim
index c5c1a0d75..473264b52 100644
--- a/compiler/trees.nim
+++ b/compiler/trees.nim
@@ -190,3 +190,8 @@ proc getRoot*(n: PNode): PSym =
   of nkCallKinds:
     if getMagic(n) == mSlice: result = getRoot(n[1])
   else: discard
+
+proc stupidStmtListExpr*(n: PNode): bool =
+  for i in 0..<n.len-1:
+    if n[i].kind notin {nkEmpty, nkCommentStmt}: return false
+  result = true
diff --git a/compiler/varpartitions.nim b/compiler/varpartitions.nim
index b416aa41d..e59c5cb75 100644
--- a/compiler/varpartitions.nim
+++ b/compiler/varpartitions.nim
@@ -29,7 +29,7 @@
 ## for a high-level description of how borrow checking works.
 
 import ast, types, lineinfos, options, msgs, renderer, typeallowed
-from trees import getMagic, whichPragma
+from trees import getMagic, whichPragma, stupidStmtListExpr
 from wordrecg import wNoSideEffect
 from isolation_check import canAlias
 
@@ -309,6 +309,11 @@ proc pathExpr(node: PNode; owner: PSym): PNode =
     of nkHiddenStdConv, nkHiddenSubConv, nkConv,  nkCast,
         nkObjUpConv, nkObjDownConv:
       n = n.lastSon
+    of nkStmtList, nkStmtListExpr:
+      if n.len > 0 and stupidStmtListExpr(n):
+        n = n.lastSon
+      else:
+        break
     of nkCallKinds:
       if n.len > 1:
         if (n.typ != nil and classifyViewType(n.typ) != noView) or getMagic(n) == mSlice:
@@ -551,6 +556,10 @@ proc borrowingAsgn(c: var Partitions; dest, src: PNode) =
       localError(c.config, dest.info, "attempt to mutate a borrowed location from an immutable view")
     of noView: discard "nothing to do"
 
+proc containsPointer(t: PType): bool =
+  proc wrap(t: PType): bool {.nimcall.} = t.kind in {tyRef, tyPtr}
+  result = types.searchTypeFor(t, wrap)
+
 proc deps(c: var Partitions; dest, src: PNode) =
   if borrowChecking in c.goals:
     borrowingAsgn(c, dest, src)
@@ -559,9 +568,7 @@ proc deps(c: var Partitions; dest, src: PNode) =
   allRoots(dest, targets)
   allRoots(src, sources)
 
-  proc wrap(t: PType): bool {.nimcall.} = t.kind in {tyRef, tyPtr}
-
-  let destIsComplex = types.searchTypeFor(dest.typ, wrap)
+  let destIsComplex = containsPointer(dest.typ)
 
   for t in targets:
     if dest.kind != nkSym and c.inNoSideEffectSection == 0:
@@ -607,6 +614,14 @@ const
     nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt,
     nkExportStmt, nkPragma, nkCommentStmt, nkBreakState, nkTypeOfExpr}
 
+proc potentialMutationViaArg(c: var Partitions; n: PNode; callee: PType) =
+  if constParameters in c.goals and tfNoSideEffect in callee.flags:
+    discard "we know there are no hidden mutations through an immutable parameter"
+  elif c.inNoSideEffectSection == 0 and containsPointer(n.typ):
+    var roots: seq[PSym]
+    allRoots(n, roots)
+    for r in roots: potentialMutation(c, r, n.info)
+
 proc traverse(c: var Partitions; n: PNode) =
   inc c.abstractTime
   case n.kind
@@ -640,6 +655,7 @@ proc traverse(c: var Partitions; n: PNode) =
 
     let parameters = n[0].typ
     let L = if parameters != nil: parameters.len else: 0
+    let m = getMagic(n)
 
     for i in 1..<n.len:
       let it = n[i]
@@ -659,6 +675,8 @@ proc traverse(c: var Partitions; n: PNode) =
               # 'paramType[0]' is still a view type, this is not a typo!
               if directViewType(paramType[0]) == noView and classifyViewType(paramType[0]) != noView:
                 borrowingCall(c, paramType[0], n, i)
+        elif borrowChecking in c.goals and m == mNone:
+          potentialMutationViaArg(c, n[i], parameters)
 
   of nkAddr, nkHiddenAddr:
     traverse(c, n[0])