fixes #4528
This commit is contained in:
parent
ce4d9e40fe
commit
09f122f68c
2 changed files with 45 additions and 30 deletions
|
|
@ -97,8 +97,8 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PType) =
|
||||||
c.calleeSym = nil
|
c.calleeSym = nil
|
||||||
initIdTable(c.bindings)
|
initIdTable(c.bindings)
|
||||||
|
|
||||||
proc put(t: var TIdTable, key, val: PType) {.inline.} =
|
proc put(c: var TCandidate, key, val: PType) {.inline.} =
|
||||||
idTablePut(t, key, val.skipIntLit)
|
idTablePut(c.bindings, key, val.skipIntLit)
|
||||||
|
|
||||||
proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym,
|
proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym,
|
||||||
binding: PNode, calleeScope = -1) =
|
binding: PNode, calleeScope = -1) =
|
||||||
|
|
@ -130,7 +130,7 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym,
|
||||||
bound = makeTypeDesc(ctx, bound)
|
bound = makeTypeDesc(ctx, bound)
|
||||||
else:
|
else:
|
||||||
bound = bound.skipTypes({tyTypeDesc})
|
bound = bound.skipTypes({tyTypeDesc})
|
||||||
put(c.bindings, formalTypeParam, bound)
|
put(c, formalTypeParam, bound)
|
||||||
|
|
||||||
proc newCandidate*(ctx: PContext, callee: PSym,
|
proc newCandidate*(ctx: PContext, callee: PSym,
|
||||||
binding: PNode, calleeScope = -1): TCandidate =
|
binding: PNode, calleeScope = -1): TCandidate =
|
||||||
|
|
@ -367,15 +367,14 @@ proc isObjectSubtype(a, f: PType): int =
|
||||||
type
|
type
|
||||||
SkippedPtr = enum skippedNone, skippedRef, skippedPtr
|
SkippedPtr = enum skippedNone, skippedRef, skippedPtr
|
||||||
|
|
||||||
proc skipToGenericBody(t: PType; skipped: var SkippedPtr): PType =
|
proc skipToObject(t: PType; skipped: var SkippedPtr): PType =
|
||||||
var r = t
|
var r = t
|
||||||
# we're allowed to skip one level of ptr/ref:
|
# we're allowed to skip one level of ptr/ref:
|
||||||
var ptrs = 0
|
var ptrs = 0
|
||||||
while r != nil:
|
while r != nil:
|
||||||
case r.kind
|
case r.kind
|
||||||
of tyGenericInst, tyGenericInvocation:
|
of tyGenericInvocation:
|
||||||
result = r.sons[0]
|
r = r.sons[0]
|
||||||
break
|
|
||||||
of tyRef:
|
of tyRef:
|
||||||
inc ptrs
|
inc ptrs
|
||||||
skipped = skippedRef
|
skipped = skippedRef
|
||||||
|
|
@ -384,21 +383,26 @@ proc skipToGenericBody(t: PType; skipped: var SkippedPtr): PType =
|
||||||
inc ptrs
|
inc ptrs
|
||||||
skipped = skippedPtr
|
skipped = skippedPtr
|
||||||
r = r.lastSon
|
r = r.lastSon
|
||||||
of tyGenericBody, tyObject:
|
of tyGenericBody, tyGenericInst:
|
||||||
r = r.lastSon
|
r = r.lastSon
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
if ptrs > 1: result = nil
|
if r.kind == tyObject and ptrs <= 1: result = r
|
||||||
|
|
||||||
proc isGenericSubtype(a, f: PType, d: var int): bool =
|
proc isGenericSubtype(a, f: PType, d: var int): bool =
|
||||||
assert f.kind in {tyGenericInst, tyGenericInvocation, tyGenericBody}
|
assert f.kind in {tyGenericInst, tyGenericInvocation, tyGenericBody}
|
||||||
var askip = skippedNone
|
var askip = skippedNone
|
||||||
var fskip = skippedNone
|
var fskip = skippedNone
|
||||||
var t = if a.kind == tyGenericBody: a else: a.skipToGenericBody(askip)
|
var t = a.skipToObject(askip)
|
||||||
var r = if f.kind == tyGenericBody: f else: f.skipToGenericBody(fskip)
|
let r = f.skipToObject(fskip)
|
||||||
|
if r == nil: return false
|
||||||
var depth = 0
|
var depth = 0
|
||||||
while t != nil and not sameObjectTypes(r, t) and askip == fskip:
|
# XXX sameObjectType can return false here. Need to investigate
|
||||||
t = t.skipToGenericBody(askip)
|
# why that is but sameObjectType does way too much work here anyway.
|
||||||
|
while t != nil and r.sym != t.sym and askip == fskip:
|
||||||
|
t = t.sons[0]
|
||||||
|
if t != nil: t = t.skipToObject(askip)
|
||||||
|
else: break
|
||||||
inc depth
|
inc depth
|
||||||
if t != nil and askip == fskip:
|
if t != nil and askip == fskip:
|
||||||
d = depth
|
d = depth
|
||||||
|
|
@ -667,7 +671,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
assert(f != nil)
|
assert(f != nil)
|
||||||
|
|
||||||
if f.kind == tyExpr:
|
if f.kind == tyExpr:
|
||||||
if aOrig != nil: put(c.bindings, f, aOrig)
|
if aOrig != nil: put(c, f, aOrig)
|
||||||
return isGeneric
|
return isGeneric
|
||||||
|
|
||||||
assert(aOrig != nil)
|
assert(aOrig != nil)
|
||||||
|
|
@ -688,7 +692,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
|
||||||
put(c.bindings, f, bound)
|
put(c, f, bound)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
template considerPreviousT(body: untyped) =
|
template considerPreviousT(body: untyped) =
|
||||||
|
|
@ -795,7 +799,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
if fRange.kind == tyGenericParam:
|
if fRange.kind == tyGenericParam:
|
||||||
var prev = PType(idTableGet(c.bindings, fRange))
|
var prev = PType(idTableGet(c.bindings, fRange))
|
||||||
if prev == nil:
|
if prev == nil:
|
||||||
put(c.bindings, fRange, a.sons[0])
|
put(c, fRange, a.sons[0])
|
||||||
fRange = a
|
fRange = a
|
||||||
else:
|
else:
|
||||||
fRange = prev
|
fRange = prev
|
||||||
|
|
@ -813,7 +817,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
# we must correct for the off-by-one discrepancy between
|
# we must correct for the off-by-one discrepancy between
|
||||||
# ranges and static params:
|
# ranges and static params:
|
||||||
replacementT.n = newIntNode(nkIntLit, inputUpperBound + 1)
|
replacementT.n = newIntNode(nkIntLit, inputUpperBound + 1)
|
||||||
put(c.bindings, rangeStaticT, replacementT)
|
put(c, rangeStaticT, replacementT)
|
||||||
return isGeneric
|
return isGeneric
|
||||||
|
|
||||||
let len = tryResolvingStaticExpr(c, fRange.n[1])
|
let len = tryResolvingStaticExpr(c, fRange.n[1])
|
||||||
|
|
@ -981,10 +985,13 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
|
|
||||||
of tyGenericBody:
|
of tyGenericBody:
|
||||||
considerPreviousT:
|
considerPreviousT:
|
||||||
if a.kind == tyGenericInst and a.sons[0] == f:
|
|
||||||
bindingRet isGeneric
|
|
||||||
let ff = lastSon(f)
|
let ff = lastSon(f)
|
||||||
if ff != nil: result = typeRel(c, ff, a)
|
var depth = 0
|
||||||
|
if a.kind == tyGenericInst and (a.sons[0] == f): #or (ff != nil and ff.kind == tyObject and isGenericSubtype(a.sons[0], ff, depth))):
|
||||||
|
c.inheritancePenalty += depth
|
||||||
|
bindingRet isGeneric
|
||||||
|
if ff != nil:
|
||||||
|
result = typeRel(c, ff, a)
|
||||||
|
|
||||||
of tyGenericInvocation:
|
of tyGenericInvocation:
|
||||||
var x = a.skipGenericAlias
|
var x = a.skipGenericAlias
|
||||||
|
|
@ -1023,7 +1030,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
elif x.kind in {tyGenericInvocation, tyGenericParam}:
|
elif x.kind in {tyGenericInvocation, tyGenericParam}:
|
||||||
internalError("wrong instantiated type!")
|
internalError("wrong instantiated type!")
|
||||||
else:
|
else:
|
||||||
put(c.bindings, f.sons[i], x)
|
put(c, f.sons[i], x)
|
||||||
|
|
||||||
of tyAnd:
|
of tyAnd:
|
||||||
considerPreviousT:
|
considerPreviousT:
|
||||||
|
|
@ -1061,7 +1068,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
considerPreviousT:
|
considerPreviousT:
|
||||||
var concrete = concreteType(c, a)
|
var concrete = concreteType(c, a)
|
||||||
if concrete != nil and doBind:
|
if concrete != nil and doBind:
|
||||||
put(c.bindings, f, concrete)
|
put(c, f, concrete)
|
||||||
return isGeneric
|
return isGeneric
|
||||||
|
|
||||||
of tyBuiltInTypeClass:
|
of tyBuiltInTypeClass:
|
||||||
|
|
@ -1069,7 +1076,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
let targetKind = f.sons[0].kind
|
let targetKind = f.sons[0].kind
|
||||||
if targetKind == a.skipTypes({tyRange, tyGenericInst}).kind or
|
if targetKind == a.skipTypes({tyRange, tyGenericInst}).kind or
|
||||||
(targetKind in {tyProc, tyPointer} and a.kind == tyNil):
|
(targetKind in {tyProc, tyPointer} and a.kind == tyNil):
|
||||||
put(c.bindings, f, a)
|
put(c, f, a)
|
||||||
return isGeneric
|
return isGeneric
|
||||||
else:
|
else:
|
||||||
return isNone
|
return isNone
|
||||||
|
|
@ -1078,7 +1085,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
considerPreviousT:
|
considerPreviousT:
|
||||||
result = matchUserTypeClass(c.c, c, f, aOrig)
|
result = matchUserTypeClass(c.c, c, f, aOrig)
|
||||||
if result == isGeneric:
|
if result == isGeneric:
|
||||||
put(c.bindings, f, a)
|
put(c, f, a)
|
||||||
|
|
||||||
of tyCompositeTypeClass:
|
of tyCompositeTypeClass:
|
||||||
considerPreviousT:
|
considerPreviousT:
|
||||||
|
|
@ -1094,7 +1101,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
else:
|
else:
|
||||||
result = typeRel(c, rootf.lastSon, a)
|
result = typeRel(c, rootf.lastSon, a)
|
||||||
if result != isNone:
|
if result != isNone:
|
||||||
put(c.bindings, f, a)
|
put(c, f, a)
|
||||||
result = isGeneric
|
result = isGeneric
|
||||||
of tyGenericParam:
|
of tyGenericParam:
|
||||||
var x = PType(idTableGet(c.bindings, f))
|
var x = PType(idTableGet(c.bindings, f))
|
||||||
|
|
@ -1128,7 +1135,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
if doBind and result notin {isNone, isGeneric}:
|
if doBind and result notin {isNone, isGeneric}:
|
||||||
let concrete = concreteType(c, a)
|
let concrete = concreteType(c, a)
|
||||||
if concrete == nil: return isNone
|
if concrete == nil: return isNone
|
||||||
put(c.bindings, f, concrete)
|
put(c, f, concrete)
|
||||||
else:
|
else:
|
||||||
result = isGeneric
|
result = isGeneric
|
||||||
|
|
||||||
|
|
@ -1142,7 +1149,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
if concrete == nil:
|
if concrete == nil:
|
||||||
return isNone
|
return isNone
|
||||||
if doBind:
|
if doBind:
|
||||||
put(c.bindings, f, concrete)
|
put(c, f, concrete)
|
||||||
elif result > isGeneric:
|
elif result > isGeneric:
|
||||||
result = isGeneric
|
result = isGeneric
|
||||||
elif a.kind == tyEmpty:
|
elif a.kind == tyEmpty:
|
||||||
|
|
@ -1161,7 +1168,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
if result != isNone and f.n != nil:
|
if result != isNone and f.n != nil:
|
||||||
if not exprStructuralEquivalent(f.n, aOrig.n):
|
if not exprStructuralEquivalent(f.n, aOrig.n):
|
||||||
result = isNone
|
result = isNone
|
||||||
if result != isNone: put(c.bindings, f, aOrig)
|
if result != isNone: put(c, f, aOrig)
|
||||||
else:
|
else:
|
||||||
result = isNone
|
result = isNone
|
||||||
elif prev.kind == tyStatic:
|
elif prev.kind == tyStatic:
|
||||||
|
|
@ -1189,7 +1196,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
result = typeRel(c, f.base, a.base)
|
result = typeRel(c, f.base, a.base)
|
||||||
|
|
||||||
if result != isNone:
|
if result != isNone:
|
||||||
put(c.bindings, f, a)
|
put(c, f, a)
|
||||||
else:
|
else:
|
||||||
if tfUnresolved in f.flags:
|
if tfUnresolved in f.flags:
|
||||||
result = typeRel(c, prev.base, a)
|
result = typeRel(c, prev.base, a)
|
||||||
|
|
@ -1207,7 +1214,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
|
|
||||||
of tyStmt:
|
of tyStmt:
|
||||||
if aOrig != nil and tfOldSchoolExprStmt notin f.flags:
|
if aOrig != nil and tfOldSchoolExprStmt notin f.flags:
|
||||||
put(c.bindings, f, aOrig)
|
put(c, f, aOrig)
|
||||||
result = isGeneric
|
result = isGeneric
|
||||||
|
|
||||||
of tyProxy:
|
of tyProxy:
|
||||||
|
|
|
||||||
|
|
@ -23,3 +23,11 @@ let c = ChildClass[string].new("Base", "Child")
|
||||||
|
|
||||||
assert c.baseMethod == "Base"
|
assert c.baseMethod == "Base"
|
||||||
assert c.overridedMethod == "Child"
|
assert c.overridedMethod == "Child"
|
||||||
|
|
||||||
|
|
||||||
|
# bug #4528
|
||||||
|
type GenericBase[T] = ref object of RootObj
|
||||||
|
type GenericSubclass[T] = ref object of GenericBase[T]
|
||||||
|
proc foo[T](g: GenericBase[T]) = discard
|
||||||
|
var bar: GenericSubclass[int]
|
||||||
|
foo(bar)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue