From fb93295344b78d2d45c81bc78bdba8526a893a09 Mon Sep 17 00:00:00 2001 From: metagn Date: Wed, 12 Mar 2025 19:31:33 +0300 Subject: [PATCH] fix compound inheritance penalty (#24775) fixes #24773 `c.inheritancePenalty` is supposed to be used for the entire match, but in these places the inheritance penalty of a single argument overrides the entire match penalty. The `+ ord(c.inheritancePenalty < 0)` is copied from other places that use the same idiom, the intent is that the existing penalty changes from -1 to 0 first to mark that it participates in inheritance before adding the inheritance depth. --------- Co-authored-by: Andreas Rumpf --- compiler/sigmatch.nim | 11 +++++++---- tests/overload/tcompoundinheritance.nim | 26 +++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 tests/overload/tcompoundinheritance.nim diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index da5452b2bf..c7ccf1e209 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -1541,12 +1541,14 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, reduceToBase(a) if effectiveArgType.kind == tyObject: if sameObjectTypes(f, effectiveArgType): - c.inheritancePenalty = if tfFinal in f.flags: -1 else: 0 + if tfFinal notin f.flags: + inc c.inheritancePenalty, ord(c.inheritancePenalty < 0) result = isEqual # elif tfHasMeta in f.flags: result = recordRel(c, f, a) elif trIsOutParam notin flags: - c.inheritancePenalty = isObjectSubtype(c, effectiveArgType, f, nil) - if c.inheritancePenalty > 0: + let depth = isObjectSubtype(c, effectiveArgType, f, nil) + if depth > 0: + inc c.inheritancePenalty, depth + ord(c.inheritancePenalty < 0) result = isSubtype of tyDistinct: a = a.skipTypes({tyOwned, tyGenericInst, tyRange}) @@ -1846,9 +1848,10 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, if c.inheritancePenalty > -1: minInheritance = min(minInheritance, c.inheritancePenalty) result = x + c.inheritancePenalty = oldInheritancePenalty if result >= isIntConv: if minInheritance < maxInheritancePenalty: - c.inheritancePenalty = oldInheritancePenalty + minInheritance + inc c.inheritancePenalty, minInheritance + ord(c.inheritancePenalty < 0) if result > isGeneric: result = isGeneric bindingRet result else: diff --git a/tests/overload/tcompoundinheritance.nim b/tests/overload/tcompoundinheritance.nim new file mode 100644 index 0000000000..8595d13e56 --- /dev/null +++ b/tests/overload/tcompoundinheritance.nim @@ -0,0 +1,26 @@ +# issue #24773 + +import std/assertions + +type + A {.inheritable.} = object + B = object of A + C = object of B + +proc add1(v: B) = + doAssert true + +proc add1(v: A) = + doAssert false + +proc add2(v: B, v2: A) = + doAssert true + +proc add2(v: A, v2: A) = + doAssert false + +var x: C +var y: B + +add1(x) +add2(x, y)