summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/semcall.nim2
-rw-r--r--compiler/semexprs.nim1
-rw-r--r--compiler/sigmatch.nim10
-rw-r--r--tests/converter/tconverter_unique_ptr.nim107
4 files changed, 118 insertions, 2 deletions
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index 4e2a45209..7e0ea5490 100644
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -138,6 +138,7 @@ proc effectProblem(f, a: PType; result: var string) =
 
 proc renderNotLValue(n: PNode): string =
   result = $n
+  let n = if n.kind == nkHiddenDeref: n[0] else: n
   if n.kind == nkHiddenCallConv and n.len > 1:
     result = $n[0] & "(" & result & ")"
   elif n.kind in {nkHiddenStdConv, nkHiddenSubConv} and n.len == 2:
@@ -394,6 +395,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
         args])
 
 proc instGenericConvertersArg*(c: PContext, a: PNode, x: TCandidate) =
+  let a = if a.kind == nkHiddenDeref: a[0] else: a
   if a.kind == nkHiddenCallConv and a.sons[0].kind == nkSym:
     let s = a.sons[0].sym
     if s.ast != nil and s.ast[genericParamsPos].kind != nkEmpty:
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 0e4f0575f..3d77ae524 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -640,6 +640,7 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
 
     return
   for i in countup(1, sonsLen(n) - 1):
+    let n = if n.kind == nkHiddenDeref: n[0] else: n
     if n.sons[i].kind == nkHiddenCallConv:
       # we need to recurse explicitly here as converters can create nested
       # calls and then they wouldn't be analysed otherwise
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index d5b2bb8b4..4adf0bed3 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -13,7 +13,7 @@
 import
   intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst,
   magicsys, condsyms, idents, lexer, options, parampatterns, strutils, trees,
-  linter, lineinfos, modulegraphs
+  linter, lineinfos, lowerings, modulegraphs
 
 when (defined(booting) or defined(nimsuggest)) and not defined(leanCompiler):
   import docgen
@@ -1855,8 +1855,14 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
       else:
         param = copyTree(arg)
       addSon(result, param)
+
+      if dest.kind in {tyVar, tyLent}:
+        dest.flags.incl tfVarIsPtr
+        result = newDeref(result)
+
       inc(m.convMatches)
-      m.genericConverter = srca == isGeneric or destIsGeneric
+      if m.genericConverter == false:
+        m.genericConverter = srca == isGeneric or destIsGeneric
       return result
 
 proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType,
diff --git a/tests/converter/tconverter_unique_ptr.nim b/tests/converter/tconverter_unique_ptr.nim
new file mode 100644
index 000000000..15ec609a3
--- /dev/null
+++ b/tests/converter/tconverter_unique_ptr.nim
@@ -0,0 +1,107 @@
+
+discard """
+  file: "tconverter_unique_ptr.nim"
+  targets: "c cpp"
+  output: '''5
+2.0 5
+'''
+"""
+
+## Bugs 9698 and 9699
+
+type
+  UniquePtr*[T] = object
+    ## non copyable pointer to object T, exclusive ownership of the object is assumed
+    val: ptr T
+
+  MyLen* = distinct int
+
+  MySeq* = object
+    ## Vectorized matrix
+    len: MyLen  # scalar size
+    data: ptr UncheckedArray[float]
+
+proc `$`(x: MyLen): string {.borrow.}
+
+proc `=destroy`*(m: var MySeq) {.inline.} =
+  if m.data != nil:
+    deallocShared(m.data)
+    m.data = nil
+
+proc `=`*(m: var MySeq, m2: MySeq) =
+  if m.data == m2.data: return
+  if m.data != nil:
+    `=destroy`(m)
+
+  m.len = m2.len
+  let bytes = m.len.int * sizeof(float) 
+  if bytes > 0:
+    m.data = cast[ptr UncheckedArray[float]](allocShared(bytes))
+    copyMem(m.data, m2.data, bytes)
+
+proc `=sink`*(m: var MySeq, m2: MySeq) {.inline.} =
+  if m.data != m2.data:
+    if m.data != nil:
+      `=destroy`(m)
+    m.len = m2.len
+    m.data = m2.data
+
+proc len*(m: MySeq): MyLen {.inline.} = m.len
+
+proc lenx*(m: var MySeq): MyLen {.inline.} = m.len
+
+
+proc `[]`*(m: MySeq; i: MyLen): float {.inline.} =
+  m.data[i.int]
+
+proc `[]=`*(m: var MySeq; i: MyLen, val: float) {.inline.} =
+  m.data[i.int] = val
+
+proc setTo(s: var MySeq, val: float) = 
+  for i in 0..<s.len.int:
+    s.data[i] = val
+
+proc newMySeq*(size: int, initial_value = 0.0): MySeq =
+  result.len = size.MyLen
+  if size > 0:
+    result.data = cast[ptr UncheckedArray[float]](createShared(float, size))
+
+  result.setTo(initial_value)
+
+converter literalToLen*(x: int{lit}): MyLen =
+  x.MyLen
+
+
+#-------------------------------------------------------------
+# Unique pointer implementation
+#-------------------------------------------------------------
+
+proc `=destroy`*[T](p: var UniquePtr[T]) =
+  if p.val != nil:
+    `=destroy`(p.val[])
+    dealloc(p.val)
+    p.val = nil
+
+proc `=`*[T](dest: var UniquePtr[T], src: UniquePtr[T]) {.error.}
+
+proc `=sink`*[T](dest: var UniquePtr[T], src: UniquePtr[T]) {.inline.} =
+  if dest.val != nil and dest.val != src.val:
+    `=destroy`(dest)
+  dest.val = src.val
+
+proc newUniquePtr*[T](val: sink T): UniquePtr[T] =
+  result.val = cast[type(result.val)](alloc(sizeof(result.val[])))
+  reset(result.val[])
+  result.val[] = val
+
+converter convertPtrToObj*[T](p: UniquePtr[T]): var T =
+  result = p.val[]
+
+
+var pu = newUniquePtr(newMySeq(5, 1.0))
+echo pu.len
+
+pu[0] = 2.0
+echo pu[0], " ", pu.lenx
+
+