summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2012-08-06 18:11:03 +0200
committerAraq <rumpf_a@web.de>2012-08-06 18:11:03 +0200
commitce23b814a0255a1a20eefff5e9b3679d52b8aa43 (patch)
tree7cf5ee8f11d53cd7aa45cebb4e8bbdbb3e6545bf
parent5cd933a44d37b46dd3a1f349777efca6eaaf11e2 (diff)
downloadNim-ce23b814a0255a1a20eefff5e9b3679d52b8aa43.tar.gz
borrow works with generics
-rwxr-xr-xcompiler/procfind.nim70
-rwxr-xr-xcompiler/semcall.nim14
-rwxr-xr-xcompiler/types.nim14
-rw-r--r--tests/run/tborrow.nim21
-rwxr-xr-xtodo.txt1
-rwxr-xr-xweb/news.txt1
6 files changed, 79 insertions, 42 deletions
diff --git a/compiler/procfind.nim b/compiler/procfind.nim
index 34a3482f8..eefe734b3 100755
--- a/compiler/procfind.nim
+++ b/compiler/procfind.nim
@@ -13,14 +13,6 @@
 import 
   ast, astalgo, msgs, semdata, types, trees
 
-proc SearchForProc*(c: PContext, fn: PSym, tos: int): PSym
-  # Searchs for the fn in the symbol table. If the parameter lists are exactly
-  # the same the sym in the symbol table is returned, else nil.
-proc SearchForBorrowProc*(c: PContext, fn: PSym, tos: int): PSym
-  # Searchs for the fn in the symbol table. If the parameter lists are suitable
-  # for borrowing the sym in the symbol table is returned, else nil.
-# implementation
-
 proc equalGenericParams(procA, procB: PNode): bool = 
   var a, b: PSym
   result = procA == procB
@@ -41,7 +33,9 @@ proc equalGenericParams(procA, procB: PNode): bool =
       if not ExprStructuralEquivalent(a.ast, b.ast): return 
   result = true
 
-proc SearchForProc(c: PContext, fn: PSym, tos: int): PSym = 
+proc SearchForProc*(c: PContext, fn: PSym, tos: int): PSym = 
+  # Searchs for the fn in the symbol table. If the parameter lists are exactly
+  # the same the sym in the symbol table is returned, else nil.
   var it: TIdentIter
   result = initIdentIter(it, c.tab.stack[tos], fn.Name)
   while result != nil: 
@@ -58,36 +52,30 @@ proc SearchForProc(c: PContext, fn: PSym, tos: int): PSym =
           nil
     result = NextIdentIter(it, c.tab.stack[tos])
 
-proc paramsFitBorrow(child, parent: PNode): bool = 
-  var length = sonsLen(child)
-  result = false
-  if length == sonsLen(parent): 
-    for i in countup(1, length - 1): 
-      var m = child.sons[i].sym
-      var n = parent.sons[i].sym
-      assert((m.kind == skParam) and (n.kind == skParam))
-      if not compareTypes(m.typ, n.typ, dcEqOrDistinctOf): return 
-    if not compareTypes(child.sons[0].typ, parent.sons[0].typ,
-                        dcEqOrDistinctOf): return
-    result = true
-
-proc SearchForBorrowProc(c: PContext, fn: PSym, tos: int): PSym = 
-  # Searchs for the fn in the symbol table. If the parameter lists are suitable
-  # for borrowing the sym in the symbol table is returned, else nil.
-  var it: TIdentIter
-  for scope in countdown(tos, 0): 
-    result = initIdentIter(it, c.tab.stack[scope], fn.Name)
-    while result != nil: 
-      # watchout! result must not be the same as fn!
-      if (result.Kind == fn.kind) and (result.id != fn.id): 
-        if equalGenericParams(result.ast.sons[genericParamsPos], 
-                              fn.ast.sons[genericParamsPos]): 
-          if paramsFitBorrow(fn.typ.n, result.typ.n): return 
-      result = NextIdentIter(it, c.tab.stack[scope])
+when false:
+  proc paramsFitBorrow(child, parent: PNode): bool = 
+    var length = sonsLen(child)
+    result = false
+    if length == sonsLen(parent): 
+      for i in countup(1, length - 1): 
+        var m = child.sons[i].sym
+        var n = parent.sons[i].sym
+        assert((m.kind == skParam) and (n.kind == skParam))
+        if not compareTypes(m.typ, n.typ, dcEqOrDistinctOf): return 
+      if not compareTypes(child.sons[0].typ, parent.sons[0].typ,
+                          dcEqOrDistinctOf): return
+      result = true
 
-proc SearchForBorrowProc2(c: PContext, fn: PSym, tos: int): PSym = 
-  # Searchs for the fn in the symbol table. If the parameter lists are suitable
-  # for borrowing the sym in the symbol table is returned, else nil.
-  # New approach: generate fn(x, y, z) where x, y, z have the proper types
-  # and use the overloading resolution mechanism:
-  nil
+  proc SearchForBorrowProc*(c: PContext, fn: PSym, tos: int): PSym = 
+    # Searchs for the fn in the symbol table. If the parameter lists are suitable
+    # for borrowing the sym in the symbol table is returned, else nil.
+    var it: TIdentIter
+    for scope in countdown(tos, 0): 
+      result = initIdentIter(it, c.tab.stack[scope], fn.Name)
+      while result != nil: 
+        # watchout! result must not be the same as fn!
+        if (result.Kind == fn.kind) and (result.id != fn.id): 
+          if equalGenericParams(result.ast.sons[genericParamsPos], 
+                                fn.ast.sons[genericParamsPos]): 
+            if paramsFitBorrow(fn.typ.n, result.typ.n): return 
+        result = NextIdentIter(it, c.tab.stack[scope])
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index eca8d75f0..e4655c5ba 100755
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -150,3 +150,17 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
   else:
     result = explicitGenericInstError(n)
 
+proc SearchForBorrowProc(c: PContext, fn: PSym, tos: int): PSym =
+  # Searchs for the fn in the symbol table. If the parameter lists are suitable
+  # for borrowing the sym in the symbol table is returned, else nil.
+  # New approach: generate fn(x, y, z) where x, y, z have the proper types
+  # and use the overloading resolution mechanism:
+  var call = newNode(nkCall)
+  call.add(newIdentNode(fn.name, fn.info))
+  for i in 1.. <fn.typ.n.len:
+    let param = fn.typ.n.sons[i]
+    let t = skipTypes(param.typ, abstractVar)
+    call.add(newNodeIT(nkEmpty, fn.info, t.baseOfDistinct))
+  var resolved = semOverloadedCall(c, call, call, {fn.kind})
+  if resolved != nil:
+    result = resolved.sons[0].sym
diff --git a/compiler/types.nim b/compiler/types.nim
index ce044c2eb..c4d218f2b 100755
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -1108,3 +1108,17 @@ proc containsGenericTypeIter(t: PType, closure: PObject): bool =
 
 proc containsGenericType*(t: PType): bool = 
   result = iterOverType(t, containsGenericTypeIter, nil)
+
+proc baseOfDistinct*(t: PType): PType =
+  if t.kind == tyDistinct:
+    result = t.sons[0]
+  else:
+    result = copyType(t, t.owner, false)
+    var parent: PType = nil
+    var it = result
+    while it.kind in {tyPtr, tyRef}:
+      parent = it
+      it = it.sons[0]
+    if it.kind == tyDistinct:
+      internalAssert parent != nil
+      parent.sons[0] = it.sons[0]
diff --git a/tests/run/tborrow.nim b/tests/run/tborrow.nim
new file mode 100644
index 000000000..8e6aeba74
--- /dev/null
+++ b/tests/run/tborrow.nim
@@ -0,0 +1,21 @@
+discard """
+  output: "4887 true"
+"""
+
+# test the new borrow feature that works with generics:
+
+proc `++`*[T: int | float](a, b: T): T =
+  result = a + b
+  
+type
+  DI = distinct int
+  DF = distinct float
+  DS = distinct string
+  
+proc `++`(x, y: DI): DI {.borrow.}
+proc `++`(x, y: DF): DF {.borrow.}
+
+proc `$`(x: DI): string {.borrow.}
+proc `$`(x: DF): string {.borrow.}
+
+echo  4544.DI ++ 343.di, " ", (4.5.df ++ 0.5.df).float == 5.0
diff --git a/todo.txt b/todo.txt
index 40e9f7003..3cce1721c 100755
--- a/todo.txt
+++ b/todo.txt
@@ -5,7 +5,6 @@ version 0.9.0
   module vars
 - implicit deref for parameter matching
 
-- ``borrow`` needs to take type classes into account
 - optimize genericAssign in the code generator
 - fix remaining closure bugs:
   - fix evals.nim with closures
diff --git a/web/news.txt b/web/news.txt
index b445ff8c4..74d91e601 100755
--- a/web/news.txt
+++ b/web/news.txt
@@ -145,6 +145,7 @@ Language Additions
 - A semicolon can now be used to have multiple simple statements on a single
   line: ``inc i; inc j``.
 - ``bind`` supports overloaded symbols and operators.
+- A ``distinct`` type can now borrow from generic procs.
 
 
 2012-02-09 Version 0.8.14 released