views: yet another bugfix (#15447)
* views: yet another bugfix * views: extended the spec * views: take into account potential hidden mutations via proc calls
This commit is contained in:
parent
79a92da8ef
commit
ab405c936e
5 changed files with 44 additions and 10 deletions
|
|
@ -707,11 +707,6 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
|
||||||
localError(c.c.config, n.info, "invalid expression")
|
localError(c.c.config, n.info, "invalid expression")
|
||||||
result = n
|
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
|
result = n
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkIdent:
|
of nkIdent:
|
||||||
|
|
|
||||||
|
|
@ -190,3 +190,8 @@ proc getRoot*(n: PNode): PSym =
|
||||||
of nkCallKinds:
|
of nkCallKinds:
|
||||||
if getMagic(n) == mSlice: result = getRoot(n[1])
|
if getMagic(n) == mSlice: result = getRoot(n[1])
|
||||||
else: discard
|
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
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@
|
||||||
## for a high-level description of how borrow checking works.
|
## for a high-level description of how borrow checking works.
|
||||||
|
|
||||||
import ast, types, lineinfos, options, msgs, renderer, typeallowed
|
import ast, types, lineinfos, options, msgs, renderer, typeallowed
|
||||||
from trees import getMagic, whichPragma
|
from trees import getMagic, whichPragma, stupidStmtListExpr
|
||||||
from wordrecg import wNoSideEffect
|
from wordrecg import wNoSideEffect
|
||||||
from isolation_check import canAlias
|
from isolation_check import canAlias
|
||||||
|
|
||||||
|
|
@ -309,6 +309,11 @@ proc pathExpr(node: PNode; owner: PSym): PNode =
|
||||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv, nkCast,
|
of nkHiddenStdConv, nkHiddenSubConv, nkConv, nkCast,
|
||||||
nkObjUpConv, nkObjDownConv:
|
nkObjUpConv, nkObjDownConv:
|
||||||
n = n.lastSon
|
n = n.lastSon
|
||||||
|
of nkStmtList, nkStmtListExpr:
|
||||||
|
if n.len > 0 and stupidStmtListExpr(n):
|
||||||
|
n = n.lastSon
|
||||||
|
else:
|
||||||
|
break
|
||||||
of nkCallKinds:
|
of nkCallKinds:
|
||||||
if n.len > 1:
|
if n.len > 1:
|
||||||
if (n.typ != nil and classifyViewType(n.typ) != noView) or getMagic(n) == mSlice:
|
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")
|
localError(c.config, dest.info, "attempt to mutate a borrowed location from an immutable view")
|
||||||
of noView: discard "nothing to do"
|
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) =
|
proc deps(c: var Partitions; dest, src: PNode) =
|
||||||
if borrowChecking in c.goals:
|
if borrowChecking in c.goals:
|
||||||
borrowingAsgn(c, dest, src)
|
borrowingAsgn(c, dest, src)
|
||||||
|
|
@ -559,9 +568,7 @@ proc deps(c: var Partitions; dest, src: PNode) =
|
||||||
allRoots(dest, targets)
|
allRoots(dest, targets)
|
||||||
allRoots(src, sources)
|
allRoots(src, sources)
|
||||||
|
|
||||||
proc wrap(t: PType): bool {.nimcall.} = t.kind in {tyRef, tyPtr}
|
let destIsComplex = containsPointer(dest.typ)
|
||||||
|
|
||||||
let destIsComplex = types.searchTypeFor(dest.typ, wrap)
|
|
||||||
|
|
||||||
for t in targets:
|
for t in targets:
|
||||||
if dest.kind != nkSym and c.inNoSideEffectSection == 0:
|
if dest.kind != nkSym and c.inNoSideEffectSection == 0:
|
||||||
|
|
@ -607,6 +614,14 @@ const
|
||||||
nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt,
|
nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt,
|
||||||
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState, nkTypeOfExpr}
|
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) =
|
proc traverse(c: var Partitions; n: PNode) =
|
||||||
inc c.abstractTime
|
inc c.abstractTime
|
||||||
case n.kind
|
case n.kind
|
||||||
|
|
@ -640,6 +655,7 @@ proc traverse(c: var Partitions; n: PNode) =
|
||||||
|
|
||||||
let parameters = n[0].typ
|
let parameters = n[0].typ
|
||||||
let L = if parameters != nil: parameters.len else: 0
|
let L = if parameters != nil: parameters.len else: 0
|
||||||
|
let m = getMagic(n)
|
||||||
|
|
||||||
for i in 1..<n.len:
|
for i in 1..<n.len:
|
||||||
let it = n[i]
|
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!
|
# 'paramType[0]' is still a view type, this is not a typo!
|
||||||
if directViewType(paramType[0]) == noView and classifyViewType(paramType[0]) != noView:
|
if directViewType(paramType[0]) == noView and classifyViewType(paramType[0]) != noView:
|
||||||
borrowingCall(c, paramType[0], n, i)
|
borrowingCall(c, paramType[0], n, i)
|
||||||
|
elif borrowChecking in c.goals and m == mNone:
|
||||||
|
potentialMutationViaArg(c, n[i], parameters)
|
||||||
|
|
||||||
of nkAddr, nkHiddenAddr:
|
of nkAddr, nkHiddenAddr:
|
||||||
traverse(c, n[0])
|
traverse(c, n[0])
|
||||||
|
|
|
||||||
|
|
@ -1988,6 +1988,22 @@ borrow operation of ``v`` even though a human being can easily see that it
|
||||||
will never do that at runtime.
|
will never do that at runtime.
|
||||||
|
|
||||||
|
|
||||||
|
Start of a borrow
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
A borrow starts with one of the following:
|
||||||
|
|
||||||
|
- The assignment of a non-view-type to a view-type.
|
||||||
|
- The assingment of a location that is derived from a local parameter
|
||||||
|
to a view-type.
|
||||||
|
|
||||||
|
|
||||||
|
End of a borrow
|
||||||
|
---------------
|
||||||
|
|
||||||
|
A borrow operation ends with the last usage of the view variable.
|
||||||
|
|
||||||
|
|
||||||
Reborrows
|
Reborrows
|
||||||
---------
|
---------
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
discard """
|
discard """
|
||||||
cmd: "nim c --experimental:strictFuncs $file"
|
cmd: "nim c --experimental:strictFuncs --experimental:views $file"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import tables, streams, nre, parsecsv
|
import tables, streams, nre, parsecsv
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue