better overloading resolution for generics

This commit is contained in:
Araq
2013-02-28 21:28:19 +01:00
parent 8090b6c027
commit d13bcf6575
4 changed files with 65 additions and 19 deletions

View File

@@ -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)

View File

@@ -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:
##

20
tests/run/toverl3.nim Executable file
View File

@@ -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)

View File

@@ -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