diff options
author | Araq <rumpf_a@web.de> | 2013-02-28 21:28:19 +0100 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2013-02-28 21:28:19 +0100 |
commit | d13bcf657503a84f3568b86a7cfce4a28be03f7b (patch) | |
tree | 2c29bb8edfcb944449095e2c92a120663958ed93 | |
parent | 8090b6c02704cd7e8942ac846c9e086874d88241 (diff) | |
download | Nim-d13bcf657503a84f3568b86a7cfce4a28be03f7b.tar.gz |
better overloading resolution for generics
-rwxr-xr-x | compiler/sigmatch.nim | 44 | ||||
-rwxr-xr-x | lib/system.nim | 4 | ||||
-rwxr-xr-x | tests/run/toverl3.nim | 20 | ||||
-rwxr-xr-x | tests/run/toverlop.nim | 16 |
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 - - |