make move-analysis smarter; see tuse_ownedref_after_move test case
This commit is contained in:
parent
a520eb7766
commit
ce024a73bf
2 changed files with 90 additions and 8 deletions
|
|
@ -32,7 +32,6 @@
|
||||||
import ast, astalgo, types, intsets, tables, msgs, options, lineinfos, renderer
|
import ast, astalgo, types, intsets, tables, msgs, options, lineinfos, renderer
|
||||||
|
|
||||||
from patterns import sameTrees
|
from patterns import sameTrees
|
||||||
from aliases import isPartOf, TAnalysisResult
|
|
||||||
|
|
||||||
type
|
type
|
||||||
InstrKind* = enum
|
InstrKind* = enum
|
||||||
|
|
@ -570,7 +569,8 @@ const
|
||||||
InterestingSyms = {skVar, skResult, skLet, skParam, skForVar, skTemp}
|
InterestingSyms = {skVar, skResult, skLet, skParam, skForVar, skTemp}
|
||||||
PathKinds* = {nkDotExpr, nkCheckedFieldExpr,
|
PathKinds* = {nkDotExpr, nkCheckedFieldExpr,
|
||||||
nkBracketExpr, nkDerefExpr, nkHiddenDeref,
|
nkBracketExpr, nkDerefExpr, nkHiddenDeref,
|
||||||
nkAddr, nkHiddenAddr}
|
nkAddr, nkHiddenAddr,
|
||||||
|
nkHiddenStdConv, nkHiddenSubConv, nkObjDownConv, nkObjUpConv}
|
||||||
|
|
||||||
proc genUse(c: var Con; orig: PNode) =
|
proc genUse(c: var Con; orig: PNode) =
|
||||||
var n = orig
|
var n = orig
|
||||||
|
|
@ -581,6 +581,27 @@ proc genUse(c: var Con; orig: PNode) =
|
||||||
if n.kind == nkSym and n.sym.kind in InterestingSyms:
|
if n.kind == nkSym and n.sym.kind in InterestingSyms:
|
||||||
c.code.add Instr(n: orig, kind: use, sym: if iters > 0: nil else: n.sym)
|
c.code.add Instr(n: orig, kind: use, sym: if iters > 0: nil else: n.sym)
|
||||||
|
|
||||||
|
proc aliases(obj, field: PNode): bool =
|
||||||
|
var n = field
|
||||||
|
var obj = obj
|
||||||
|
while obj.kind in {nkHiddenSubConv, nkHiddenStdConv, nkObjDownConv, nkObjUpConv}:
|
||||||
|
obj = obj[0]
|
||||||
|
while true:
|
||||||
|
if sameTrees(obj, n): return true
|
||||||
|
case n.kind
|
||||||
|
of nkDotExpr, nkCheckedFieldExpr, nkHiddenSubConv, nkHiddenStdConv,
|
||||||
|
nkObjDownConv, nkObjUpConv, nkHiddenDeref:
|
||||||
|
n = n[0]
|
||||||
|
of nkBracketExpr:
|
||||||
|
let x = n[0]
|
||||||
|
if x.typ != nil and x.typ.skipTypes(abstractInst).kind == tyTuple:
|
||||||
|
n = x
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
return false
|
||||||
|
|
||||||
proc instrTargets*(ins: Instr; loc: PNode): bool =
|
proc instrTargets*(ins: Instr; loc: PNode): bool =
|
||||||
assert ins.kind in {def, use}
|
assert ins.kind in {def, use}
|
||||||
if ins.sym != nil and loc.kind == nkSym:
|
if ins.sym != nil and loc.kind == nkSym:
|
||||||
|
|
@ -593,14 +614,16 @@ proc instrTargets*(ins: Instr; loc: PNode): bool =
|
||||||
# def x; question: does it affect the 'x.f'? Yes.
|
# def x; question: does it affect the 'x.f'? Yes.
|
||||||
# use x.f; question: does it affect the full 'x'? No.
|
# use x.f; question: does it affect the full 'x'? No.
|
||||||
# use x; question does it affect 'x.f'? Yes.
|
# use x; question does it affect 'x.f'? Yes.
|
||||||
result = isPartOf(ins.n, loc) == arYes
|
result = aliases(ins.n, loc) or aliases(loc, ins.n)
|
||||||
|
|
||||||
proc isAnalysableFieldAccess*(n: PNode; owner: PSym): bool =
|
proc isAnalysableFieldAccess*(n: PNode; owner: PSym): bool =
|
||||||
var n = n
|
var n = n
|
||||||
while true:
|
while true:
|
||||||
if n.kind in {nkDotExpr, nkCheckedFieldExpr, nkHiddenSubConv, nkHiddenStdConv, nkObjDownConv, nkObjUpConv}:
|
case n.kind
|
||||||
|
of nkDotExpr, nkCheckedFieldExpr, nkHiddenSubConv, nkHiddenStdConv,
|
||||||
|
nkObjDownConv, nkObjUpConv, nkHiddenDeref:
|
||||||
n = n[0]
|
n = n[0]
|
||||||
elif n.kind == nkBracketExpr:
|
of nkBracketExpr:
|
||||||
let x = n[0]
|
let x = n[0]
|
||||||
if x.typ != nil and x.typ.skipTypes(abstractInst).kind == tyTuple:
|
if x.typ != nil and x.typ.skipTypes(abstractInst).kind == tyTuple:
|
||||||
n = x
|
n = x
|
||||||
|
|
@ -710,10 +733,9 @@ proc gen(c: var Con; n: PNode) =
|
||||||
for x in n: gen(c, x)
|
for x in n: gen(c, x)
|
||||||
of nkPragmaBlock: gen(c, n.lastSon)
|
of nkPragmaBlock: gen(c, n.lastSon)
|
||||||
of nkDiscardStmt: gen(c, n.sons[0])
|
of nkDiscardStmt: gen(c, n.sons[0])
|
||||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv, nkExprColonExpr, nkExprEqExpr,
|
of nkConv, nkExprColonExpr, nkExprEqExpr, nkCast:
|
||||||
nkCast:
|
|
||||||
gen(c, n.sons[1])
|
gen(c, n.sons[1])
|
||||||
of nkObjDownConv, nkStringToCString, nkCStringToString: gen(c, n.sons[0])
|
of nkStringToCString, nkCStringToString: gen(c, n.sons[0])
|
||||||
of nkVarSection, nkLetSection: genVarSection(c, n)
|
of nkVarSection, nkLetSection: genVarSection(c, n)
|
||||||
of nkDefer:
|
of nkDefer:
|
||||||
doAssert false, "dfa construction pass requires the elimination of 'defer'"
|
doAssert false, "dfa construction pass requires the elimination of 'defer'"
|
||||||
|
|
|
||||||
60
tests/destructor/tuse_ownedref_after_move.nim
Normal file
60
tests/destructor/tuse_ownedref_after_move.nim
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
discard """
|
||||||
|
cmd: '''nim c --newruntime $file'''
|
||||||
|
errormsg: "'=' is not available for type <owned Widget>; requires a copy because it's not the last read of ':env.b1()'; another read is done here: tuse_ownedref_after_move.nim(53, 4)"
|
||||||
|
line: 49
|
||||||
|
"""
|
||||||
|
|
||||||
|
import core / allocators
|
||||||
|
import system / ansi_c
|
||||||
|
|
||||||
|
type
|
||||||
|
Widget* = ref object of RootObj
|
||||||
|
drawImpl: owned(proc (self: Widget))
|
||||||
|
|
||||||
|
Button* = ref object of Widget
|
||||||
|
caption: string
|
||||||
|
onclick: owned(proc())
|
||||||
|
|
||||||
|
Window* = ref object of Widget
|
||||||
|
elements: seq[owned Widget]
|
||||||
|
|
||||||
|
|
||||||
|
proc newButton(caption: string; onclick: owned(proc())): owned Button =
|
||||||
|
proc draw(self: Widget) =
|
||||||
|
let b = Button(self)
|
||||||
|
echo b.caption
|
||||||
|
|
||||||
|
result = Button(drawImpl: draw, caption: caption, onclick: onclick)
|
||||||
|
|
||||||
|
proc newWindow(): owned Window =
|
||||||
|
proc draw(self: Widget) =
|
||||||
|
let w = Window(self)
|
||||||
|
for e in w.elements:
|
||||||
|
if not e.drawImpl.isNil: e.drawImpl(e)
|
||||||
|
|
||||||
|
result = Window(drawImpl: draw, elements: @[])
|
||||||
|
|
||||||
|
proc draw(w: Widget) =
|
||||||
|
if not w.drawImpl.isNil: w.drawImpl(w)
|
||||||
|
|
||||||
|
proc add*(w: Window; elem: owned Widget) =
|
||||||
|
w.elements.add elem
|
||||||
|
|
||||||
|
proc main =
|
||||||
|
var w = newWindow()
|
||||||
|
|
||||||
|
var b = newButton("button", nil)
|
||||||
|
b.onclick = proc () =
|
||||||
|
b.caption = "clicked!"
|
||||||
|
w.add b
|
||||||
|
|
||||||
|
w.draw()
|
||||||
|
# simulate button click:
|
||||||
|
b.onclick()
|
||||||
|
|
||||||
|
w.draw()
|
||||||
|
|
||||||
|
main()
|
||||||
|
|
||||||
|
let (a, d) = allocCounters()
|
||||||
|
discard cprintf("%ld %ld new: %ld\n", a, d, allocs)
|
||||||
Loading…
Add table
Add a link
Reference in a new issue