diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index d3d99a355aa80..21697f33d3438 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -1742,7 +1742,17 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, if ff != nil: result = typeRel(c, ff, a, flags) of tyGenericInvocation: - var x = a.skipGenericAlias + var x = a + while x != nil: + if x.kind == tyAlias: + x = x.last + elif x.isGenericAlias: + if f[0] == x[0]: + break + else: + x = x.last + else: + break if x.kind == tyGenericParam and x.len > 0: x = x.last let concpt = f.reduceToBase @@ -1751,7 +1761,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, preventHack = true x = x.last # XXX: This is very hacky. It should be moved back into liftTypeParam - if x.kind in {tyGenericInst, tyArray} and + if x.kind in {tyArray} and c.calleeSym != nil and c.calleeSym.kind in {skProc, skFunc} and c.call != nil and not preventHack: let inst = prepareMetatypeForSigmatch(c.c, c.bindings, c.call.info, f) @@ -1807,10 +1817,12 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, else: let key = f[i] let old = lookup(c.bindings, key) - if old == nil: + if typeRel(c, key, x, flags) == isNone: + result = isNone + elif old == nil or typeRel(c, old, x, flags + {trDontBind}) > isNone: put(c, key, x) - elif typeRel(c, old, x, flags + {trDontBind}) == isNone: - return isNone + else: + result = isNone var depth = -1 if fobj != nil and aobj != nil and askip == fskip: depth = isObjectSubtype(c, aobj, fobj, f) @@ -1891,6 +1903,11 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, return isNone if doBind: put(c, f, a) return isGeneric + elif effectiveArgType.kind == tyOr: + for kid in effectiveArgType.kids: + if typeRel(c, f, kid, flags) >= isSubtype: + result = isGeneric + break else: return isNone of tyUserTypeClassInst, tyUserTypeClass: diff --git a/tests/typerel/tsigmatch.nim b/tests/typerel/tsigmatch.nim index 7541f2028d444..c92c1cc339649 100644 --- a/tests/typerel/tsigmatch.nim +++ b/tests/typerel/tsigmatch.nim @@ -4,3 +4,16 @@ block: # bug #13618 doAssert test(^1) == 1 doAssert test(1) == 1 + +block: # #25174 + type Foo = object + type Bar = object + type Quz = object + + proc bar[T: Foo | Bar](x: T): string = + return $typeof(T) + proc bar[T: object](x: T): string = + return $typeof(T) + doAssert bar(Foo()) == "Foo" + doAssert bar(Bar()) == "Bar" + doAssert bar(Quz()) == "Quz"