summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/typeallowed.nim6
-rw-r--r--compiler/varpartitions.nim20
-rw-r--r--tests/effects/tcannot_borrow.nim18
3 files changed, 39 insertions, 5 deletions
diff --git a/compiler/typeallowed.nim b/compiler/typeallowed.nim
index 5a192783e..651a21ade 100644
--- a/compiler/typeallowed.nim
+++ b/compiler/typeallowed.nim
@@ -57,7 +57,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
   of tyVar, tyLent:
     if kind in {skProc, skFunc, skConst} and (views notin c.features):
       result = t
-    elif t.kind == tyLent and kind != skResult:
+    elif t.kind == tyLent and kind != skResult and (views notin c.features):
       result = t
     else:
       var t2 = skipTypes(t[0], abstractInst-{tyTypeDesc})
@@ -68,10 +68,10 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
         if (kind != skParam and views notin c.features) or taIsOpenArray in flags: result = t
         else: result = typeAllowedAux(marker, t2[0], kind, c, flags+{taIsOpenArray})
       of tyUncheckedArray:
-        if kind != skParam: result = t
+        if kind != skParam and views notin c.features: result = t
         else: result = typeAllowedAux(marker, t2[0], kind, c, flags)
       else:
-        if kind notin {skParam, skResult}: result = t
+        if kind notin {skParam, skResult} and views notin c.features: result = t
         else: result = typeAllowedAux(marker, t2, kind, c, flags)
   of tyProc:
     if kind in {skVar, skLet, skConst} and taIsTemplateOrMacro in flags:
diff --git a/compiler/varpartitions.nim b/compiler/varpartitions.nim
index 756249c8b..bbde68cbe 100644
--- a/compiler/varpartitions.nim
+++ b/compiler/varpartitions.nim
@@ -375,7 +375,7 @@ proc deps(c: var Partitions; dest, src: PNode) =
   allRoots(src, sources)
 
   proc wrap(t: PType): bool {.nimcall.} = t.kind in {tyRef, tyPtr}
-  let destIsComplex = types.searchTypeFor(dest.typ, wrap)
+  let destIsComplex = types.searchTypeFor(dest.typ, wrap) or isViewType(dest.typ)
 
   for t in targets:
     if dest.kind != nkSym and c.inNoSideEffectSection == 0:
@@ -518,19 +518,35 @@ proc computeGraphPartitions*(s: PSym; n: PNode; cursorInference = false): Partit
   traverse(result, n)
 
 proc dangerousMutation(g: MutationInfo; v: VarIndex): bool =
+  #echo "range ", v.aliveStart, " .. ", v.aliveEnd
   if isMutated in g.flags:
     for m in g.mutations:
+      #echo "mutation ", m
       if m in v.aliveStart..v.aliveEnd:
         return true
   return false
 
+proc cannotBorrow(config: ConfigRef; s: PSym; g: MutationInfo) =
+  var m = "cannot borrow " & s.name.s &
+    "; what it borrows from is potentially mutated"
+
+  if g.mutatedHere != unknownLineInfo:
+    m.add "\n"
+    m.add config $ g.mutatedHere
+    m.add " the mutation is here"
+  if g.connectedVia != unknownLineInfo:
+    m.add "\n"
+    m.add config $ g.connectedVia
+    m.add " is the statement that connected the mutation to the parameter"
+  localError(config, s.info, m)
+
 proc checkBorrowedLocations*(par: var Partitions; config: ConfigRef) =
   for i in 0 ..< par.s.len:
     let s = par.s[i].sym
     if s.kind != skParam and isViewType(s.typ):
       let rid = root(par, i)
       if par.s[rid].kind == isRootOf and dangerousMutation(par.graphs[par.s[rid].graphIndex], par.s[i]):
-        localError(config, s.info, config $ par.graphs[par.s[rid].graphIndex])
+        cannotBorrow(config, s, par.graphs[par.s[rid].graphIndex])
 
 proc computeCursors*(s: PSym; n: PNode; config: ConfigRef) =
   var par = computeGraphPartitions(s, n, true)
diff --git a/tests/effects/tcannot_borrow.nim b/tests/effects/tcannot_borrow.nim
new file mode 100644
index 000000000..699176b04
--- /dev/null
+++ b/tests/effects/tcannot_borrow.nim
@@ -0,0 +1,18 @@
+discard """
+  errormsg: "cannot borrow"
+  nimout: '''tcannot_borrow.nim(16, 7) Error: cannot borrow meh; what it borrows from is potentially mutated
+tcannot_borrow.nim(17, 3) the mutation is here
+tcannot_borrow.nim(16, 7) is the statement that connected the mutation to the parameter'''
+  line: 16
+"""
+
+{.experimental: "views".}
+
+type
+  Foo = object
+    field: string
+
+proc dangerous(s: var seq[Foo]) =
+  let meh: lent Foo = s[0]
+  s.setLen 0
+  echo meh.field