diff options
-rw-r--r-- | compiler/semcall.nim | 13 | ||||
-rw-r--r-- | compiler/seminst.nim | 6 | ||||
-rw-r--r-- | compiler/transf.nim | 8 | ||||
-rw-r--r-- | tests/borrow/typeclassborrow.nim | 32 |
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 |