diff options
-rw-r--r-- | compiler/typeallowed.nim | 6 | ||||
-rw-r--r-- | compiler/varpartitions.nim | 20 | ||||
-rw-r--r-- | tests/effects/tcannot_borrow.nim | 18 |
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 |