mirror of
https://github.com/nim-lang/Nim.git
synced 2026-06-02 01:48:00 +00:00
make move-analysis smarter; see tuse_ownedref_after_move test case
This commit is contained in:
@@ -32,7 +32,6 @@
|
||||
import ast, astalgo, types, intsets, tables, msgs, options, lineinfos, renderer
|
||||
|
||||
from patterns import sameTrees
|
||||
from aliases import isPartOf, TAnalysisResult
|
||||
|
||||
type
|
||||
InstrKind* = enum
|
||||
@@ -570,7 +569,8 @@ const
|
||||
InterestingSyms = {skVar, skResult, skLet, skParam, skForVar, skTemp}
|
||||
PathKinds* = {nkDotExpr, nkCheckedFieldExpr,
|
||||
nkBracketExpr, nkDerefExpr, nkHiddenDeref,
|
||||
nkAddr, nkHiddenAddr}
|
||||
nkAddr, nkHiddenAddr,
|
||||
nkHiddenStdConv, nkHiddenSubConv, nkObjDownConv, nkObjUpConv}
|
||||
|
||||
proc genUse(c: var Con; orig: PNode) =
|
||||
var n = orig
|
||||
@@ -581,6 +581,27 @@ proc genUse(c: var Con; orig: PNode) =
|
||||
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)
|
||||
|
||||
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 =
|
||||
assert ins.kind in {def, use}
|
||||
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.
|
||||
# use x.f; question: does it affect the full 'x'? No.
|
||||
# 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 =
|
||||
var n = n
|
||||
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]
|
||||
elif n.kind == nkBracketExpr:
|
||||
of nkBracketExpr:
|
||||
let x = n[0]
|
||||
if x.typ != nil and x.typ.skipTypes(abstractInst).kind == tyTuple:
|
||||
n = x
|
||||
@@ -710,10 +733,9 @@ proc gen(c: var Con; n: PNode) =
|
||||
for x in n: gen(c, x)
|
||||
of nkPragmaBlock: gen(c, n.lastSon)
|
||||
of nkDiscardStmt: gen(c, n.sons[0])
|
||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv, nkExprColonExpr, nkExprEqExpr,
|
||||
nkCast:
|
||||
of nkConv, nkExprColonExpr, nkExprEqExpr, nkCast:
|
||||
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 nkDefer:
|
||||
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)
|
||||
Reference in New Issue
Block a user