summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2019-04-26 15:44:06 +0200
committerAraq <rumpf_a@web.de>2019-04-26 15:44:06 +0200
commitb350a9fc52d67cabc778887d8f81d0332eb9db91 (patch)
tree8b87a40962503cedfcf0159e9e287b2f27b46d72
parent1f7615ad9db3e8f90b20aa9932c3c11ee1793218 (diff)
downloadNim-b350a9fc52d67cabc778887d8f81d0332eb9db91.tar.gz
preparations to make the twidgets test work
-rw-r--r--compiler/ccgexprs.nim4
-rw-r--r--compiler/injectdestructors.nim22
-rw-r--r--tests/destructor/twidgets.nim74
3 files changed, 89 insertions, 11 deletions
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 65cc6e42e..0ac6b42f4 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -1918,14 +1918,14 @@ proc genSomeCast(p: BProc, e: PNode, d: var TLoc) =
   var a: TLoc
   initLocExpr(p, e.sons[1], a)
   let etyp = skipTypes(e.typ, abstractRange+{tyOwned})
+  let srcTyp = skipTypes(e.sons[1].typ, abstractRange)
   if etyp.kind in ValueTypes and lfIndirect notin a.flags:
     putIntoDest(p, d, e, "(*($1*) ($2))" %
         [getTypeDesc(p.module, e.typ), addrLoc(p.config, a)], a.storage)
-  elif etyp.kind == tyProc and etyp.callConv == ccClosure:
+  elif etyp.kind == tyProc and etyp.callConv == ccClosure and srcTyp.callConv != ccClosure:
     putIntoDest(p, d, e, "(($1) ($2))" %
         [getClosureType(p.module, etyp, clHalfWithEnv), rdCharLoc(a)], a.storage)
   else:
-    let srcTyp = skipTypes(e.sons[1].typ, abstractRange)
     # C++ does not like direct casts from pointer to shorter integral types
     if srcTyp.kind in {tyPtr, tyPointer} and etyp.kind in IntegralTypes:
       putIntoDest(p, d, e, "(($1) (ptrdiff_t) ($2))" %
diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim
index 73ff0869c..197d15490 100644
--- a/compiler/injectdestructors.nim
+++ b/compiler/injectdestructors.nim
@@ -701,6 +701,15 @@ proc injectDefaultCalls(n: PNode, c: var Con) =
 proc isCursor(n: PNode): bool {.inline.} =
   result = n.kind == nkSym and sfCursor in n.sym.flags
 
+proc keepVar(n, it: PNode, c: var Con): PNode =
+  # keep the var but transform 'ri':
+  result = copyNode(n)
+  var itCopy = copyNode(it)
+  for j in 0..it.len-2:
+    itCopy.add it[j]
+  itCopy.add p(it[it.len-1], c)
+  result.add itCopy
+
 proc p(n: PNode; c: var Con): PNode =
   case n.kind
   of nkVarSection, nkLetSection:
@@ -726,15 +735,10 @@ proc p(n: PNode; c: var Con): PNode =
             if ri.kind != nkEmpty:
               let r = moveOrCopy(v, ri, c)
               result.add r
+          else:
+            result.add keepVar(n, it, c)
       else:
-        # keep it, but transform 'ri':
-        var varSection = copyNode(n)
-        var itCopy = copyNode(it)
-        for j in 0..L-2:
-          itCopy.add it[j]
-        itCopy.add p(ri, c)
-        varSection.add itCopy
-        result.add varSection
+        result.add keepVar(n, it, c)
   of nkCallKinds:
     let parameters = n[0].typ
     let L = if parameters != nil: parameters.len else: 0
@@ -752,7 +756,7 @@ proc p(n: PNode; c: var Con): PNode =
     else:
       result = n
   of nkAsgn, nkFastAsgn:
-    if hasDestructor(n[0].typ):
+    if hasDestructor(n[0].typ) and n[1].kind notin {nkProcDef, nkDo, nkLambda, nkClosure}:
       result = moveOrCopy(n[0], n[1], c)
     else:
       result = copyNode(n)
diff --git a/tests/destructor/twidgets.nim b/tests/destructor/twidgets.nim
new file mode 100644
index 000000000..f7af1f75f
--- /dev/null
+++ b/tests/destructor/twidgets.nim
@@ -0,0 +1,74 @@
+discard """
+  cmd: '''nim c --newruntime $file'''
+  output: '''button
+clicked!'''
+  disabled: "true"
+"""
+
+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)
+  new(result)
+  result.drawImpl = draw
+  result.caption = caption
+  result.onclick = onclick
+
+iterator unitems*[T](a: seq[owned T]): T {.inline.} =
+  ## Iterates over each item of `a`.
+  var i = 0
+  let L = len(a)
+  while i < L:
+    yield a[i]
+    inc(i)
+    assert(len(a) == L, "seq modified while iterating over it")
+
+proc newWindow(): owned Window =
+  proc draw(self: Widget) =
+    let w = Window(self)
+    for e in unitems(w.elements):
+      let d = (proc(self: Widget))e.drawImpl
+      if not d.isNil: d(e)
+
+  result = Window(drawImpl: draw, elements: @[])
+
+proc draw(w: Widget) =
+  let d = (proc(self: Widget))w.drawImpl
+  if not d.isNil: d(w)
+
+proc add*(w: Window; elem: owned Widget) =
+  w.elements.add elem
+
+proc main =
+  var w = newWindow()
+
+  var b = newButton("button", nil)
+  #let u: Button = b
+  b.onclick = proc () =
+    b.caption = "clicked!"
+  w.add b
+
+  w.draw()
+  # simulate button click:
+  #u.onclick()
+
+  w.draw()
+
+main()
+
+let (a, d) = allocCounters()
+discard cprintf("%ld %ld  new: %ld\n", a, d, allocs)