summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/semcall.nim13
-rw-r--r--compiler/seminst.nim6
-rw-r--r--compiler/transf.nim8
-rw-r--r--tests/borrow/typeclassborrow.nim32
4 files changed, 56 insertions, 3 deletions
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index a3064788e..36658d472 100644
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -703,7 +703,16 @@ proc searchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): PSym =
   call.add(newIdentNode(fn.name, fn.info))
   for i in 1..<fn.typ.n.len:
     let param = fn.typ.n[i]
-    let t = skipTypes(param.typ, abstractVar-{tyTypeDesc, tyDistinct})
+    const desiredTypes = abstractVar + {tyCompositeTypeClass} - {tyTypeDesc, tyDistinct}
+    #[.
+      # We only want the type not any modifiers such as `ptr`, `var`, `ref` ...
+      # tyCompositeTypeClass is here for
+      # when using something like:
+      type Foo[T] = distinct int
+      proc `$`(f: Foo): string {.borrow.}
+      # We want to skip the `Foo` to get `int`
+    ]#
+    let t = skipTypes(param.typ, desiredTypes)
     if t.kind == tyDistinct or param.typ.kind == tyDistinct: hasDistinct = true
     var x: PType
     if param.typ.kind == tyVar:
@@ -721,4 +730,4 @@ proc searchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): PSym =
         result = nil
       elif result.magic in {mArrPut, mArrGet}:
         # cannot borrow these magics for now
-        result = nil
+        result = nil
\ No newline at end of file
diff --git a/compiler/seminst.nim b/compiler/seminst.nim
index 456e40a94..6fae0583d 100644
--- a/compiler/seminst.nim
+++ b/compiler/seminst.nim
@@ -145,7 +145,11 @@ proc instantiateBody(c: PContext, n, params: PNode, result, orig: PSym) =
         if sfGenSym in param.flags:
           idTablePut(symMap, params[i].sym, result.typ.n[param.position+1].sym)
     freshGenSyms(c, b, result, orig, symMap)
-    b = semProcBody(c, b)
+    
+    if sfBorrow notin orig.flags: 
+      # We do not want to generate a body for generic borrowed procs.
+      # As body is a sym to the borrowed proc.
+      b = semProcBody(c, b)
     result.ast[bodyPos] = hloBody(c, b)
     excl(result.flags, sfForward)
     trackProc(c, result, result.ast[bodyPos])
diff --git a/compiler/transf.nim b/compiler/transf.nim
index 89fa89701..edb8d3573 100644
--- a/compiler/transf.nim
+++ b/compiler/transf.nim
@@ -124,6 +124,14 @@ proc transformSymAux(c: PTransf, n: PNode): PNode =
   var tc = c.transCon
   if sfBorrow in s.flags and s.kind in routineKinds:
     # simply exchange the symbol:
+    var s = s
+    while true:
+      # Skips over all borrowed procs getting the last proc symbol without an implementation
+      let body = getBody(c.graph, s)
+      if body.kind == nkSym and sfBorrow in body.sym.flags and getBody(c.graph, body.sym).kind == nkSym:
+        s = body.sym
+      else:
+        break
     b = getBody(c.graph, s)
     if b.kind != nkSym: internalError(c.graph.config, n.info, "wrong AST for borrowed symbol")
     b = newSymNode(b.sym, n.info)
diff --git a/tests/borrow/typeclassborrow.nim b/tests/borrow/typeclassborrow.nim
new file mode 100644
index 000000000..62cb77d67
--- /dev/null
+++ b/tests/borrow/typeclassborrow.nim
@@ -0,0 +1,32 @@
+type
+  Foo = distinct seq[int]
+  Bar[N: static[int]] = distinct seq[int]
+  Baz = distinct Bar[10]
+
+proc newSeq(s: var Foo, n: Natural) {.borrow.}
+proc newSeq(s: var Bar, n: Natural) {.borrow.}
+proc newSeq(s: var Baz, n: Natural) {.borrow.}
+
+
+proc `$`(s: Foo): string {.borrow.}
+proc `$`(s: Bar): string {.borrow.}
+proc `$`(s: Baz): string {.borrow.}
+
+proc doThing(b: Bar) = discard
+proc doThing(b: Baz) {.borrow.}
+
+var
+  foo: Foo
+  bar: Bar[10]
+  baz: Baz
+
+newSeq(foo, 100)
+newSeq(bar, bar.N)
+newSeq(baz, 10)
+
+bar.doThing()
+baz.doThing()
+
+assert $seq[int](foo) == $foo
+assert $seq[int](bar) == $bar
+assert $seq[int](baz) == $baz
\ No newline at end of file