Fix generics inheritance issues
This commit is contained in:
parent
4b0ba5e3f1
commit
764668d099
2 changed files with 48 additions and 2 deletions
|
|
@ -363,6 +363,25 @@ proc isObjectSubtype(a, f: PType): int =
|
||||||
if t != nil:
|
if t != nil:
|
||||||
result = depth
|
result = depth
|
||||||
|
|
||||||
|
proc skipToGenericBody(t: PType): PType =
|
||||||
|
var r = t
|
||||||
|
while r != nil:
|
||||||
|
if r.kind in {tyGenericInst, tyGenericInvocation}:
|
||||||
|
return r.sons[0]
|
||||||
|
r = if r.len > 0: r.lastSon else: nil
|
||||||
|
|
||||||
|
proc isGenericSubtype(a, f: PType, d: var int): bool =
|
||||||
|
assert f.kind in {tyGenericInst, tyGenericInvocation, tyGenericBody}
|
||||||
|
var t = if a.kind == tyGenericBody: a else: a.skipToGenericBody
|
||||||
|
var r = if f.kind == tyGenericBody: f else: f.skipToGenericBody
|
||||||
|
var depth = 0
|
||||||
|
while t != nil and not sameObjectTypes(r, t):
|
||||||
|
t = t.skipToGenericBody
|
||||||
|
inc depth
|
||||||
|
if t != nil:
|
||||||
|
d = depth
|
||||||
|
result = true
|
||||||
|
|
||||||
proc minRel(a, b: TTypeRelation): TTypeRelation =
|
proc minRel(a, b: TTypeRelation): TTypeRelation =
|
||||||
if a <= b: result = a
|
if a <= b: result = a
|
||||||
else: result = b
|
else: result = b
|
||||||
|
|
@ -647,7 +666,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
template bindingRet(res) =
|
template bindingRet(res) =
|
||||||
if doBind:
|
if doBind:
|
||||||
let bound = aOrig.skipTypes({tyRange}).skipIntLit
|
let bound = aOrig.skipTypes({tyRange}).skipIntLit
|
||||||
if doBind: put(c.bindings, f, bound)
|
put(c.bindings, f, bound)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
template considerPreviousT(body: stmt) {.immediate.} =
|
template considerPreviousT(body: stmt) {.immediate.} =
|
||||||
|
|
@ -945,17 +964,19 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
|
|
||||||
of tyGenericInvocation:
|
of tyGenericInvocation:
|
||||||
var x = a.skipGenericAlias
|
var x = a.skipGenericAlias
|
||||||
|
var depth = 0
|
||||||
if x.kind == tyGenericInvocation or f.sons[0].kind != tyGenericBody:
|
if x.kind == tyGenericInvocation or f.sons[0].kind != tyGenericBody:
|
||||||
#InternalError("typeRel: tyGenericInvocation -> tyGenericInvocation")
|
#InternalError("typeRel: tyGenericInvocation -> tyGenericInvocation")
|
||||||
# simply no match for now:
|
# simply no match for now:
|
||||||
discard
|
discard
|
||||||
elif x.kind == tyGenericInst and
|
elif x.kind == tyGenericInst and
|
||||||
(f.sons[0] == x.sons[0]) and
|
isGenericSubtype(x, f, depth) and
|
||||||
(sonsLen(x) - 1 == sonsLen(f)):
|
(sonsLen(x) - 1 == sonsLen(f)):
|
||||||
for i in countup(1, sonsLen(f) - 1):
|
for i in countup(1, sonsLen(f) - 1):
|
||||||
if x.sons[i].kind == tyGenericParam:
|
if x.sons[i].kind == tyGenericParam:
|
||||||
internalError("wrong instantiated type!")
|
internalError("wrong instantiated type!")
|
||||||
elif typeRel(c, f.sons[i], x.sons[i]) <= isSubtype: return
|
elif typeRel(c, f.sons[i], x.sons[i]) <= isSubtype: return
|
||||||
|
c.inheritancePenalty = depth
|
||||||
result = isGeneric
|
result = isGeneric
|
||||||
else:
|
else:
|
||||||
let genericBody = f.sons[0]
|
let genericBody = f.sons[0]
|
||||||
|
|
|
||||||
25
tests/generics/t88.nim
Normal file
25
tests/generics/t88.nim
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
# Issue 88
|
||||||
|
|
||||||
|
type
|
||||||
|
BaseClass[V] = object of RootObj
|
||||||
|
b: V
|
||||||
|
|
||||||
|
proc new[V](t: typedesc[BaseClass], v: V): BaseClass[V] =
|
||||||
|
BaseClass[V](b: v)
|
||||||
|
|
||||||
|
proc baseMethod[V](v: BaseClass[V]): V = v.b
|
||||||
|
proc overridedMethod[V](v: BaseClass[V]): V = v.baseMethod
|
||||||
|
|
||||||
|
type
|
||||||
|
ChildClass[V] = object of BaseClass[V]
|
||||||
|
c: V
|
||||||
|
|
||||||
|
proc new[V](t: typedesc[ChildClass], v1, v2: V): ChildClass[V] =
|
||||||
|
ChildClass[V](b: v1, c: v2)
|
||||||
|
|
||||||
|
proc overridedMethod[V](v: ChildClass[V]): V = v.c
|
||||||
|
|
||||||
|
let c = ChildClass[string].new("Base", "Child")
|
||||||
|
|
||||||
|
assert c.baseMethod == "Base"
|
||||||
|
assert c.overridedMethod == "Child"
|
||||||
Loading…
Add table
Add a link
Reference in a new issue