summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2013-02-28 21:28:19 +0100
committerAraq <rumpf_a@web.de>2013-02-28 21:28:19 +0100
commitd13bcf657503a84f3568b86a7cfce4a28be03f7b (patch)
tree2c29bb8edfcb944449095e2c92a120663958ed93
parent8090b6c02704cd7e8942ac846c9e086874d88241 (diff)
downloadNim-d13bcf657503a84f3568b86a7cfce4a28be03f7b.tar.gz
better overloading resolution for generics
-rwxr-xr-xcompiler/sigmatch.nim44
-rwxr-xr-xlib/system.nim4
-rwxr-xr-xtests/run/toverl3.nim20
-rwxr-xr-xtests/run/toverlop.nim16
4 files changed, 65 insertions, 19 deletions
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 953dcfa74..2159abecd 100755
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -97,6 +97,45 @@ proc copyCandidate(a: var TCandidate, b: TCandidate) =
   a.baseTypeMatch = b.baseTypeMatch
   copyIdTable(a.bindings, b.bindings)
 
+proc sumGeneric(t: PType): int =
+  var t = t
+  while true:
+    case t.kind
+    of tyGenericInst, tyArray, tyRef, tyPtr, tyDistinct, tyArrayConstr,
+        tyOpenArray, tyVarargs, tySet, tyRange, tySequence, tyGenericBody:
+      t = t.lastSon
+      inc result
+    of tyVar:
+      # but do not make 'var T' more specific than 'T'!
+      t = t.sons[0]
+    of tyGenericInvokation, tyTuple:
+      result = ord(t.kind == tyGenericInvokation)
+      for i in 0 .. <t.len: result += t.sons[i].sumGeneric
+      break
+    of tyGenericParam, tyExpr, tyStmt, tyTypeDesc, tyTypeClass: break
+    else: return 0
+
+proc complexDisambiguation(a, b: PType): int =
+  var x, y: int
+  for i in 1 .. <a.len: x += a.sons[i].sumGeneric
+  for i in 1 .. <b.len: y += b.sons[i].sumGeneric
+  result = x - y
+  when false:
+    proc betterThan(a, b: PType): bool {.inline.} = a.sumGeneric > b.sumGeneric
+
+    if a.len > 1 and b.len > 1:
+      let aa = a.sons[1].sumGeneric
+      let bb = b.sons[1].sumGeneric
+      var a = a
+      var b = b
+      
+      if aa < bb: swap(a, b)
+      # all must be better
+      for i in 2 .. <min(a.len, b.len):
+        if not a.sons[i].betterThan(b.sons[i]): return 0
+      # a must be longer or of the same length as b:
+      result = a.len - b.len
+
 proc cmpCandidates*(a, b: TCandidate): int =
   result = a.exactMatches - b.exactMatches
   if result != 0: return
@@ -110,9 +149,12 @@ proc cmpCandidates*(a, b: TCandidate): int =
   if result != 0: return
   if (a.calleeScope != -1) and (b.calleeScope != -1):
     result = a.calleeScope - b.calleeScope
-  if result != 0: return
+    if result != 0: return
   # the other way round because of other semantics:
   result = b.inheritancePenalty - a.inheritancePenalty
+  if result != 0: return
+  # prefer more specialized generic over more general generic:
+  result = complexDisambiguation(a.callee, b.callee)
 
 proc writeMatches*(c: TCandidate) = 
   Writeln(stdout, "exact matches: " & $c.exactMatches)
diff --git a/lib/system.nim b/lib/system.nim
index 5f9a24ba9..db78d2740 100755
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -1532,7 +1532,7 @@ iterator fieldPairs*[S: tuple|object, T: tuple|object](x: S, y: T): tuple[
   ## The current implementation also has a bug that affects symbol binding
   ## in the loop body.
 
-proc `==`*[T: tuple](x, y: T): bool = 
+proc `==`*[T: tuple|object](x, y: T): bool = 
   ## generic ``==`` operator for tuples that is lifted from the components
   ## of `x` and `y`.
   for a, b in fields(x, y):
@@ -1557,7 +1557,7 @@ proc `<`*[T: tuple](x, y: T): bool =
     if c > 0: return false
   return false
 
-proc `$`*[T: tuple](x: T): string = 
+proc `$`*[T: tuple|object](x: T): string = 
   ## generic ``$`` operator for tuples that is lifted from the components
   ## of `x`. Example:
   ##
diff --git a/tests/run/toverl3.nim b/tests/run/toverl3.nim
new file mode 100755
index 000000000..b3e0f2fa7
--- /dev/null
+++ b/tests/run/toverl3.nim
@@ -0,0 +1,20 @@
+discard """
+  file: "toverl3.nim"
+  output: '''m1
+tup1'''
+"""
+
+# Tests more specific generic match:

+

+proc m[T](x: T) = echo "m2"
+proc m[T](x: var ref T) = echo "m1"
+
+proc tup[S, T](x: tuple[a: S, b: ref T]) = echo "tup1"
+proc tup[S, T](x: tuple[a: S, b: T]) = echo "tup2"
+
+var
+  obj: ref int
+  tu: tuple[a: int, b: ref bool]
+  
+m(obj)
+tup(tu)
diff --git a/tests/run/toverlop.nim b/tests/run/toverlop.nim
deleted file mode 100755
index ce302345f..000000000
--- a/tests/run/toverlop.nim
+++ /dev/null
@@ -1,16 +0,0 @@
-discard """
-  file: "toverlop.nim"
-  output: "3"
-"""
-# Test operator overloading

-

-proc `%` (a, b: int): int =

-  return a mod b

-

-var x, y: int

-x = 15

-y = 6

-write(stdout, x % y)

-#OUT 3

-
-