summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2020-10-07 14:38:25 +0200
committerGitHub <noreply@github.com>2020-10-07 14:38:25 +0200
commit0426a4d85ab8f9558dee35c657aad0d299748c15 (patch)
tree14dfd278c4e727f50b0d494100043755ccaee5fe
parentacbe27b082c202895df1b78a82951389b4a232a0 (diff)
downloadNim-0426a4d85ab8f9558dee35c657aad0d299748c15.tar.gz
fixes #15508 (#15509)
-rw-r--r--compiler/varpartitions.nim19
-rw-r--r--tests/effects/tfuncs_cannot_mutate_simple.nim21
2 files changed, 34 insertions, 6 deletions
diff --git a/compiler/varpartitions.nim b/compiler/varpartitions.nim
index a172a906e..f831d33cc 100644
--- a/compiler/varpartitions.nim
+++ b/compiler/varpartitions.nim
@@ -48,7 +48,8 @@ proc dec(x: var AbstractTime; diff = 1) {.borrow.}
 type
   SubgraphFlag = enum
     isMutated, # graph might be mutated
-    connectsConstParam, # graph is connected to a non-var parameter.
+    isMutatedDirectly, # graph is mutated directly by a non-var parameter.
+    connectsConstParam # graph is connected to a non-var parameter.
 
   VarFlag = enum
     ownsData,
@@ -99,12 +100,12 @@ type
     config: ConfigRef
 
 proc mutationAfterConnection(g: MutationInfo): bool {.inline.} =
-  #echo g.maxMutation, " ", g.minConnection, " ", g.param
+  #echo g.maxMutation.int, " ", g.minConnection.int, " ", g.param
   g.maxMutation > g.minConnection
 
 proc `$`*(config: ConfigRef; g: MutationInfo): string =
   result = ""
-  if g.flags == {isMutated, connectsConstParam}:
+  if g.flags * {isMutated, connectsConstParam} == {isMutated, connectsConstParam}:
     result.add "\nan object reachable from '"
     result.add g.param.name.s
     result.add "' is potentially mutated"
@@ -119,7 +120,8 @@ proc `$`*(config: ConfigRef; g: MutationInfo): string =
 
 proc hasSideEffect*(c: var Partitions; info: var MutationInfo): bool =
   for g in mitems c.graphs:
-    if g.flags == {isMutated, connectsConstParam} and mutationAfterConnection(g):
+    if g.flags * {isMutated, connectsConstParam} == {isMutated, connectsConstParam} and
+        (mutationAfterConnection(g) or isMutatedDirectly in g.flags):
       info = g
       return true
   return false
@@ -173,11 +175,16 @@ proc potentialMutation(v: var Partitions; s: PSym; info: TLineInfo) =
   let id = variableId(v, s)
   if id >= 0:
     let r = root(v, id)
+    let flags = if s.kind == skParam and isConstParam(s):
+                  {isMutated, isMutatedDirectly}
+                else:
+                  {isMutated}
+
     case v.s[r].con.kind
     of isEmptyRoot:
       v.s[r].con = Connection(kind: isRootOf, graphIndex: v.graphs.len)
       v.graphs.add MutationInfo(param: if isConstParam(s): s else: nil, mutatedHere: info,
-                            connectedVia: unknownLineInfo, flags: {isMutated},
+                            connectedVia: unknownLineInfo, flags: flags,
                             maxMutation: v.abstractTime, minConnection: MaxTime,
                             mutations: @[v.abstractTime])
     of isRootOf:
@@ -187,7 +194,7 @@ proc potentialMutation(v: var Partitions; s: PSym; info: TLineInfo) =
       if v.abstractTime > g.maxMutation:
         g.mutatedHere = info
         g.maxMutation = v.abstractTime
-      g.flags.incl isMutated
+      g.flags.incl flags
       g.mutations.add v.abstractTime
     else:
       assert false, "cannot happen"
diff --git a/tests/effects/tfuncs_cannot_mutate_simple.nim b/tests/effects/tfuncs_cannot_mutate_simple.nim
new file mode 100644
index 000000000..9de20d1ec
--- /dev/null
+++ b/tests/effects/tfuncs_cannot_mutate_simple.nim
@@ -0,0 +1,21 @@
+discard """
+  errormsg: "'edit' can have side effects"
+  nimout: '''an object reachable from 'x' is potentially mutated
+tfuncs_cannot_mutate_simple.nim(17, 4) the mutation is here'''
+  line: 16
+"""
+
+{.experimental: "strictFuncs".}
+
+# bug #15508
+
+type
+  MyType = ref object
+    data: string
+
+func edit(x: MyType) =
+  x.data = "hello"
+
+let x = MyType()
+x.edit()
+echo x.data