summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--changelog.md2
-rw-r--r--compiler/sigmatch.nim24
-rw-r--r--tests/overload/tprefer_tygenericinst.nim25
3 files changed, 36 insertions, 15 deletions
diff --git a/changelog.md b/changelog.md
index 758bc6a4e..640cb98c5 100644
--- a/changelog.md
+++ b/changelog.md
@@ -14,3 +14,5 @@
   `getBool`, `getFloat`, `getBiggestInt`. Also `getInt` procedure was added.
 - `reExtended` is no longer default for the `re` constructor in the `re`
   module.
+- The overloading rules changed slightly so that constrained generics are
+  preferred over unconstrained generics. (Bug #6526)
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index b4e79e7e9..09d8ea292 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -1452,8 +1452,13 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
   of tyOr:
     considerPreviousT:
       result = isNone
+      let oldInheritancePenalty = c.inheritancePenalty
+      var maxInheritance = 0
       for branch in f.sons:
+        c.inheritancePenalty = 0
         let x = typeRel(c, branch, aOrig)
+        maxInheritance = max(maxInheritance, c.inheritancePenalty)
+
         # 'or' implies maximum matching result:
         if x > result: result = x
       if result >= isSubtype:
@@ -1461,6 +1466,7 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
         bindingRet result
       else:
         result = isNone
+      c.inheritancePenalty = oldInheritancePenalty + maxInheritance
 
   of tyNot:
     considerPreviousT:
@@ -1551,21 +1557,19 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
           result = isNone
       else:
         if f.sonsLen > 0 and f.sons[0].kind != tyNone:
-          when false:
-            let oldInheritancePenalty = c.inheritancePenalty
+          let oldInheritancePenalty = c.inheritancePenalty
           result = typeRel(c, f.lastSon, a, flags + {trDontBind})
           if doBind and result notin {isNone, isGeneric}:
             let concrete = concreteType(c, a)
             if concrete == nil: return isNone
             put(c, f, concrete)
-          when false:
-            # bug #6526
-            if result in {isEqual, isSubtype}:
-              # 'T: Class' is a *better* match than just 'T'
-              # but 'T: Subclass' is even better:
-              c.inheritancePenalty = oldInheritancePenalty - c.inheritancePenalty -
-                                    100 * ord(result == isEqual)
-              result = isGeneric
+          # bug #6526
+          if result in {isEqual, isSubtype}:
+            # 'T: Class' is a *better* match than just 'T'
+            # but 'T: Subclass' is even better:
+            c.inheritancePenalty = oldInheritancePenalty - c.inheritancePenalty -
+                                  100 * ord(result == isEqual)
+            result = isGeneric
         else:
           result = isGeneric
 
diff --git a/tests/overload/tprefer_tygenericinst.nim b/tests/overload/tprefer_tygenericinst.nim
index 56541c7e8..72f5a94fd 100644
--- a/tests/overload/tprefer_tygenericinst.nim
+++ b/tests/overload/tprefer_tygenericinst.nim
@@ -2,7 +2,9 @@ discard """
   output: '''Version 2 was called.
 This has the highest precedence.
 This has the second-highest precedence.
-This has the lowest precedence.'''
+This has the lowest precedence.
+baseobj ==
+true'''
 """
 
 # bug #2220
@@ -26,13 +28,13 @@ template testPred(a: untyped) =
     type SomeA = A|A # A hack to make "A" a typeclass.
 
     when a >= 3:
-      proc p[X](x: X) =
-        echo "This has the highest precedence."
-    when a >= 2:
       proc p[X: A](x: X) =
+        echo "This has the highest precedence."
+    when a == 2:
+      proc p[X: SomeA](x: X) =
         echo "This has the second-highest precedence."
     when a >= 1:
-      proc p[X: SomeA](x: X) =
+      proc p[X](x: X) =
         echo "This has the lowest precedence."
 
     p(B())
@@ -40,3 +42,16 @@ template testPred(a: untyped) =
 testPred(3)
 testPred(2)
 testPred(1)
+
+# bug #6526
+type
+  BaseObj = ref object of RootObj
+  DerivedObj = ref object of BaseObj
+
+proc `==`*[T1, T2: BaseObj](a: T1, b: T2): bool =
+  echo "baseobj =="
+  return true
+
+let a = DerivedObj()
+let b = DerivedObj()
+echo a == b