diff --git a/compiler/sem/sigmatch.nim b/compiler/sem/sigmatch.nim index 8ab39d6b255..b4a36d6e743 100644 --- a/compiler/sem/sigmatch.nim +++ b/compiler/sem/sigmatch.nim @@ -475,19 +475,23 @@ proc isSubtypeOfGenericInstance(c: var TCandidate; a, f: PType, fGenericOrigin: ## where `f` is a ``tyGenericInst``. The inheritance depth is returned, ## or, if the types are not related, -1. ## - ## In case of a match, the unresolved generic parameters of `f` are bound to - ## the arguments taken from the base type of actual that matched. + ## In case of a subtype relationship existing, the unbound generic parameters + ## of `f` are bound to the respective parameters of `a`. assert f.kind == tyGenericInst var askip = skippedNone fskip = skippedNone t = a.skipToObject(askip) - last = t ## the unskipped type + last = t ## the most recently compared unskipped type assert t != nil, "'a' is not object-like type" discard f.skipToObject(fskip) # only compute the skip kind + if fskip != askip: + # one is a ref|ptr object while the other is not -> no relationship + return -1 + proc isEqual(c: var TCandidate, f, a: PType): bool {.nimcall.} = if f.id == a.id: # fast equality check result = true @@ -507,15 +511,16 @@ proc isSubtypeOfGenericInstance(c: var TCandidate; a, f: PType, fGenericOrigin: # traverse the type hieararchy until we either reach the end or find a type # that is equal to `f` - while t != nil and askip == fskip and not isEqual(c, f, last): + while t != nil and not isEqual(c, f, last): t = t.base if t.isNil: break # we reached the end last = t - t = t.skipToObject(askip) + var skip: SkippedPtr # ignore skip + t = t.skipToObject(skip) inc result - if t != nil and askip == fskip: + if t != nil: genericParamPut(c, last, f) else: result = -1 # no relationship diff --git a/tests/typerel/tphantom_type_as_base.nim b/tests/typerel/tphantom_type_as_base.nim index ec7e8b74eb9..7c3e754ff5c 100644 --- a/tests/typerel/tphantom_type_as_base.nim +++ b/tests/typerel/tphantom_type_as_base.nim @@ -72,4 +72,25 @@ block with_ptr_object: proc p(x: ptr Sub): int = 3 # the more precise overload matches: - doAssert p(addr obj) == 3 \ No newline at end of file + doAssert p(addr obj) == 3 + +block with_intermediate_non_object_base: + # test the case where an intermediate base type is a ``ref`` or + # ``ptr`` while formal type is not + type + Root[T] = object of RootObj + + First = ref object of Root[int] + Second = object of First + + GFirst[T] = ref object of Root[T] + GSecond = object of GFirst[float] + + proc p(x: Root[int]): int = 1 + proc p(x: Root[float]): int = 2 + + # test with non-generic intermediate base: + doAssert p(Second()) == 1 + + # test with generic intermediate base: + doAssert p(GSecond()) == 2 \ No newline at end of file