summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rwxr-xr-xcompiler/sigmatch.nim137
1 files changed, 75 insertions, 62 deletions
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index d841561ed..b5d4eca8f 100755
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -32,6 +32,7 @@ type
     bindings*: TIdTable      # maps types to types
     baseTypeMatch: bool      # needed for conversions from T to openarray[T]
                              # for example
+    inheritancePenalty: int  # to prefer closest father object type
   
   TTypeRelation* = enum      # order is important!
     isNone, isConvertible,
@@ -53,6 +54,7 @@ proc initCandidateAux(c: var TCandidate, callee: PType) {.inline.} =
   c.callee = callee
   c.call = nil
   c.baseTypeMatch = false
+  c.inheritancePenalty = 0
 
 proc initCandidate*(c: var TCandidate, callee: PType) = 
   initCandidateAux(c, callee)
@@ -100,6 +102,9 @@ 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
+  # the other way round because of other semantics:
+  result = b.inheritancePenalty - a.inheritancePenalty
 
 proc writeMatches*(c: TCandidate) = 
   Writeln(stdout, "exact matches: " & $c.exactMatches)
@@ -133,8 +138,8 @@ proc getNotFoundError*(c: PContext, n: PNode): string =
   if candidates != "": 
     add(result, "\n" & msgKindToString(errButExpected) & "\n" & candidates)
   
-proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation
-proc concreteType(mapping: TIdTable, t: PType): PType = 
+proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation
+proc concreteType(c: TCandidate, t: PType): PType = 
   case t.kind
   of tyArrayConstr: 
     # make it an array
@@ -146,7 +151,7 @@ proc concreteType(mapping: TIdTable, t: PType): PType =
   of tyGenericParam: 
     result = t
     while true: 
-      result = PType(idTableGet(mapping, t))
+      result = PType(idTableGet(c.bindings, t))
       if result == nil:
         break # it's ok, no match
         # example code that triggers it:
@@ -204,28 +209,31 @@ proc handleFloatRange(f, a: PType): TTypeRelation =
     elif k >= tyFloat and k <= tyFloat128: result = isConvertible
     else: result = isNone
   
-proc isObjectSubtype(a, f: PType): bool =
+proc isObjectSubtype(a, f: PType): int =
   var t = a
   assert t.kind == tyObject
+  var depth = 0
   while t != nil and not sameObjectTypes(f, t): 
     assert t.kind == tyObject
     t = t.sons[0]
     if t == nil: break
     t = skipTypes(t, {tyGenericInst})
-  result = t != nil
+    inc depth
+  if t != nil:
+    result = depth
 
 proc minRel(a, b: TTypeRelation): TTypeRelation = 
   if a <= b: result = a
   else: result = b
   
-proc tupleRel(mapping: var TIdTable, f, a: PType): TTypeRelation = 
+proc tupleRel(c: var TCandidate, f, a: PType): TTypeRelation = 
   result = isNone
   if sameType(f, a):
     result = isEqual
   elif sonsLen(a) == sonsLen(f): 
     result = isEqual
     for i in countup(0, sonsLen(f) - 1): 
-      var m = typeRel(mapping, f.sons[i], a.sons[i])
+      var m = typeRel(c, f.sons[i], a.sons[i])
       if m < isSubtype: return isNone
       result = minRel(result, m)
     if f.n != nil and a.n != nil: 
@@ -237,7 +245,7 @@ proc tupleRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
         var y = a.n.sons[i].sym
         if x.name.id != y.name.id: return isNone
 
-proc matchTypeClass(mapping: var TIdTable, f, a: PType): TTypeRelation =
+proc matchTypeClass(c: var TCandidate, f, a: PType): TTypeRelation =
   for i in countup(0, f.sonsLen - 1):
     let son = f.sons[i]
     var match = son.kind == skipTypes(a, {tyRange}).kind
@@ -247,9 +255,9 @@ proc matchTypeClass(mapping: var TIdTable, f, a: PType): TTypeRelation =
       of tyGenericBody:
         if a.kind == tyGenericInst and a.sons[0] == son:
           match = true
-          put(mapping, f, a)
+          put(c.bindings, f, a)
       of tyTypeClass:
-        match = matchTypeClass(mapping, son, a) == isGeneric
+        match = matchTypeClass(c, son, a) == isGeneric
       else: nil
 
     if tfAny in f.flags:
@@ -263,7 +271,7 @@ proc matchTypeClass(mapping: var TIdTable, f, a: PType): TTypeRelation =
   # or none of them matched.
   result = if tfAny in f.flags: isNone else: isGeneric
   
-proc procTypeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
+proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
   proc inconsistentVarTypes(f, a: PType): bool {.inline.} =
     result = f.kind != a.kind and (f.kind == tyVar or a.kind == tyVar)
 
@@ -276,13 +284,13 @@ proc procTypeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
     result = isEqual      # start with maximum; also correct for no
                           # params at all
     for i in countup(1, sonsLen(f)-1):
-      var m = typeRel(mapping, f.sons[i], a.sons[i])
+      var m = typeRel(c, f.sons[i], a.sons[i])
       if m <= isSubtype or inconsistentVarTypes(f.sons[i], a.sons[i]):
         return isNone
       else: result = minRel(m, result)
     if f.sons[0] != nil:
       if a.sons[0] != nil:
-        var m = typeRel(mapping, f.sons[0], a.sons[0])
+        var m = typeRel(c, f.sons[0], a.sons[0])
         # Subtype is sufficient for return types!
         if m < isSubtype or inconsistentVarTypes(f.sons[0], a.sons[0]):
           result = isNone
@@ -305,7 +313,7 @@ proc procTypeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
         result = isNone
   else: nil
 
-proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation = 
+proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation = 
   # is a subtype of f?
   result = isNone
   assert(f != nil)
@@ -314,9 +322,9 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
       skipTypes(f, {tyVar}).kind notin {
         tyGenericBody, tyGenericInvokation,
         tyGenericParam, tyTypeClass}:
-    return typeRel(mapping, f, lastSon(a))
+    return typeRel(c, f, lastSon(a))
   if a.kind == tyVar and f.kind != tyVar:
-    return typeRel(mapping, f, a.sons[0])
+    return typeRel(c, f, a.sons[0])
   case f.kind
   of tyEnum: 
     if a.kind == f.kind and sameEnumTypes(f, a): result = isEqual
@@ -326,7 +334,7 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
     elif skipTypes(a, {tyRange}).kind == f.kind: result = isSubtype
   of tyRange:
     if a.kind == f.kind:
-      result = typeRel(mapping, base(f), base(a))
+      result = typeRel(c, base(f), base(a))
       # bugfix: accept integer conversions here
       #if result < isGeneric: result = isNone
     elif skipTypes(f, {tyRange}).kind == a.kind:
@@ -348,45 +356,45 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
   of tyFloat64:  result = handleFloatRange(f, a)
   of tyFloat128: result = handleFloatRange(f, a)
   of tyVar: 
-    if a.kind == f.kind: result = typeRel(mapping, base(f), base(a))
-    else: result = typeRel(mapping, base(f), a)
+    if a.kind == f.kind: result = typeRel(c, base(f), base(a))
+    else: result = typeRel(c, base(f), a)
   of tyArray, tyArrayConstr: 
     # tyArrayConstr cannot happen really, but
     # we wanna be safe here
     case a.kind
     of tyArray: 
-      result = minRel(typeRel(mapping, f.sons[0], a.sons[0]), 
-                      typeRel(mapping, f.sons[1], a.sons[1]))
+      result = minRel(typeRel(c, f.sons[0], a.sons[0]), 
+                      typeRel(c, f.sons[1], a.sons[1]))
       if result < isGeneric: result = isNone
     of tyArrayConstr: 
-      result = typeRel(mapping, f.sons[1], a.sons[1])
+      result = typeRel(c, f.sons[1], a.sons[1])
       if result < isGeneric: 
         result = isNone
       else: 
         if (result != isGeneric) and (lengthOrd(f) != lengthOrd(a)): 
           result = isNone
         elif f.sons[0].kind in GenericTypes: 
-          result = minRel(result, typeRel(mapping, f.sons[0], a.sons[0]))
+          result = minRel(result, typeRel(c, f.sons[0], a.sons[0]))
     else: nil
   of tyOpenArray: 
     case a.Kind
     of tyOpenArray: 
-      result = typeRel(mapping, base(f), base(a))
+      result = typeRel(c, base(f), base(a))
       if result < isGeneric: result = isNone
     of tyArrayConstr: 
       if (f.sons[0].kind != tyGenericParam) and (a.sons[1].kind == tyEmpty): 
         result = isSubtype    # [] is allowed here
-      elif typeRel(mapping, base(f), a.sons[1]) >= isGeneric: 
+      elif typeRel(c, base(f), a.sons[1]) >= isGeneric: 
         result = isSubtype
     of tyArray: 
       if (f.sons[0].kind != tyGenericParam) and (a.sons[1].kind == tyEmpty): 
         result = isSubtype
-      elif typeRel(mapping, base(f), a.sons[1]) >= isGeneric: 
+      elif typeRel(c, base(f), a.sons[1]) >= isGeneric: 
         result = isConvertible
     of tySequence: 
       if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty): 
         result = isConvertible
-      elif typeRel(mapping, base(f), a.sons[0]) >= isGeneric: 
+      elif typeRel(c, base(f), a.sons[0]) >= isGeneric: 
         result = isConvertible
     else: nil
   of tySequence: 
@@ -397,49 +405,53 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
       if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty): 
         result = isSubtype
       else: 
-        result = typeRel(mapping, f.sons[0], a.sons[0])
+        result = typeRel(c, f.sons[0], a.sons[0])
         if result < isGeneric: result = isNone
     else: nil
   of tyOrdinal:
     if isOrdinalType(a):
       var x = if a.kind == tyOrdinal: a.sons[0] else: a
-      result = typeRel(mapping, f.sons[0], x)
+      result = typeRel(c, f.sons[0], x)
       if result < isGeneric: result = isNone
   of tyForward: InternalError("forward type in typeRel()")
   of tyNil: 
     if a.kind == f.kind: result = isEqual
   of tyTuple: 
-    if a.kind == tyTuple: result = tupleRel(mapping, f, a)
-  of tyObject: 
+    if a.kind == tyTuple: result = tupleRel(c, f, a)
+  of tyObject:
     if a.kind == tyObject:
       if sameObjectTypes(f, a): result = isEqual
-      elif isObjectSubtype(a, f): result = isSubtype
-  of tyDistinct: 
+      else:
+        var depth = isObjectSubtype(a, f)
+        if depth > 0:
+          inc(c.inheritancePenalty, depth)
+          result = isSubtype
+  of tyDistinct:
     if (a.kind == tyDistinct) and sameDistinctTypes(f, a): result = isEqual
   of tySet: 
     if a.kind == tySet: 
       if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty): 
         result = isSubtype
       else: 
-        result = typeRel(mapping, f.sons[0], a.sons[0])
+        result = typeRel(c, f.sons[0], a.sons[0])
         if result <= isConvertible: 
           result = isNone     # BUGFIX!
   of tyPtr: 
     case a.kind
     of tyPtr: 
-      result = typeRel(mapping, base(f), base(a))
+      result = typeRel(c, base(f), base(a))
       if result <= isConvertible: result = isNone
     of tyNil: result = isSubtype
     else: nil
   of tyRef: 
     case a.kind
     of tyRef: 
-      result = typeRel(mapping, base(f), base(a))
+      result = typeRel(c, base(f), base(a))
       if result <= isConvertible: result = isNone
     of tyNil: result = isSubtype
     else: nil
   of tyProc: 
-    result = procTypeRel(mapping, f, a)
+    result = procTypeRel(c, f, a)
   of tyPointer: 
     case a.kind
     of tyPointer: result = isEqual
@@ -468,10 +480,10 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
   of tyEmpty: 
     if a.kind == tyEmpty: result = isEqual
   of tyGenericInst: 
-    result = typeRel(mapping, lastSon(f), a)
+    result = typeRel(c, lastSon(f), a)
   of tyGenericBody: 
     let ff = lastSon(f)
-    if ff != nil: result = typeRel(mapping, ff, a)
+    if ff != nil: result = typeRel(c, ff, a)
   of tyGenericInvokation:
     assert(f.sons[0].kind == tyGenericBody)
     if a.kind == tyGenericInvokation: 
@@ -485,40 +497,40 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
       for i in countup(1, sonsLen(f) - 1): 
         if a.sons[i].kind == tyGenericParam: 
           InternalError("wrong instantiated type!")
-        if typeRel(mapping, f.sons[i], a.sons[i]) <= isSubtype: return 
+        if typeRel(c, f.sons[i], a.sons[i]) <= isSubtype: return 
       result = isGeneric
     else:
-      result = typeRel(mapping, f.sons[0], a)
+      result = typeRel(c, f.sons[0], a)
       if result != isNone:
         # we steal the generic parameters from the tyGenericBody:
         for i in countup(1, sonsLen(f) - 1):
-          var x = PType(idTableGet(mapping, f.sons[0].sons[i - 1]))
+          var x = PType(idTableGet(c.bindings, f.sons[0].sons[i - 1]))
           if x == nil or x.kind in {tyGenericInvokation, tyGenericParam}:
             InternalError("wrong instantiated type!")
-          put(mapping, f.sons[i], x)
+          put(c.bindings, f.sons[i], x)
   of tyGenericParam, tyTypeClass:
-    var x = PType(idTableGet(mapping, f))
+    var x = PType(idTableGet(c.bindings, f))
     if x == nil:
-      result = matchTypeClass(mapping, f, a)
+      result = matchTypeClass(c, f, a)
       if result == isGeneric:
-        var concrete = concreteType(mapping, a)
+        var concrete = concreteType(c, a)
         if concrete == nil:
           result = isNone
         else:
-          put(mapping, f, concrete)
+          put(c.bindings, f, concrete)
     elif a.kind == tyEmpty:
       result = isGeneric
     elif x.kind == tyGenericParam:
       result = isGeneric
     else:
-      result = typeRel(mapping, x, a) # check if it fits
+      result = typeRel(c, x, a) # check if it fits
   of tyTypeDesc:
     if a.kind == tyTypeDesc:
       if f.sonsLen == 0:
         result = isGeneric
       else:
-        result = matchTypeClass(mapping, f, a.sons[0])
-      if result == isGeneric: put(mapping, f, a)
+        result = matchTypeClass(c, f, a.sons[0])
+      if result == isGeneric: put(c.bindings, f, a)
     else:
       result = isNone
   of tyExpr, tyStmt:
@@ -526,9 +538,9 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
   else: internalError("typeRel(" & $f.kind & ')')
   
 proc cmpTypes*(f, a: PType): TTypeRelation = 
-  var mapping: TIdTable
-  InitIdTable(mapping)
-  result = typeRel(mapping, f, a)
+  var c: TCandidate
+  InitCandidate(c, f)
+  result = typeRel(c, f, a)
 
 proc getInstantiatedType(c: PContext, arg: PNode, m: TCandidate, 
                          f: PType): PType = 
@@ -552,8 +564,8 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
   for i in countup(0, len(c.converters) - 1): 
     var src = c.converters[i].typ.sons[1]
     var dest = c.converters[i].typ.sons[0]
-    if (typeRel(m.bindings, f, dest) == isEqual) and
-        (typeRel(m.bindings, src, a) == isEqual): 
+    if (typeRel(m, f, dest) == isEqual) and
+        (typeRel(m, src, a) == isEqual):
       markUsed(arg, c.converters[i])
       var s = newSymNode(c.converters[i])
       s.typ = c.converters[i].typ
@@ -562,7 +574,7 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
       addSon(result, s)
       addSon(result, copyTree(arg))
       inc(m.convMatches)
-      return 
+      return
 
 
 proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType, 
@@ -572,7 +584,7 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
     if f.sonsLen == 0:
       r = isGeneric
     else:
-      let match = matchTypeClass(m.bindings, f, a)
+      let match = matchTypeClass(m, f, a)
       if match != isGeneric: r = isNone
       else:
         # XXX: Ideally, this should happen much earlier somewhere near 
@@ -590,7 +602,7 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
     if r == isGeneric:
       put(m.bindings, f, arg.typ)
   else:
-    r = typeRel(m.bindings, f, a)
+    r = typeRel(m, f, a)
   
   case r
   of isConvertible: 
@@ -633,13 +645,13 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
     # check for a base type match, which supports openarray[T] without []
     # constructor in a call:
     if result == nil and f.kind == tyOpenArray:
-      r = typeRel(m.bindings, base(f), a)
+      r = typeRel(m, base(f), a)
       if r >= isGeneric: 
         inc(m.convMatches)
         result = copyTree(arg)
         if r == isGeneric: result.typ = getInstantiatedType(c, arg, m, base(f))
         m.baseTypeMatch = true
-      else: 
+      else:
         result = userConvMatch(c, m, base(f), a, arg)
 
 proc ParamTypesMatch(c: PContext, m: var TCandidate, f, a: PType, 
@@ -663,7 +675,7 @@ proc ParamTypesMatch(c: PContext, m: var TCandidate, f, a: PType,
       # iterators are not first class yet, so ignore them
       if arg.sons[i].sym.kind in {skProc, skMethod, skConverter}: 
         copyCandidate(z, m)
-        var r = typeRel(z.bindings, f, arg.sons[i].typ)
+        var r = typeRel(z, f, arg.sons[i].typ)
         if r != isNone: 
           case x.state
           of csEmpty, csNoMatch: 
@@ -687,7 +699,8 @@ proc ParamTypesMatch(c: PContext, m: var TCandidate, f, a: PType,
     else: 
       # only one valid interpretation found:
       markUsed(arg, arg.sons[best].sym)
-      result = ParamTypesMatchAux(c, m, f, arg.sons[best].typ, arg.sons[best], argOrig)
+      result = ParamTypesMatchAux(c, m, f, arg.sons[best].typ, arg.sons[best],
+                                  argOrig)
 
 proc IndexTypesMatch*(c: PContext, f, a: PType, arg: PNode): PNode = 
   var m: TCandidate