This commit is contained in:
parent
0cad2896ae
commit
568c954062
2 changed files with 89 additions and 10 deletions
|
|
@ -350,6 +350,14 @@ proc handleFloatRange(f, a: PType): TTypeRelation =
|
||||||
else: result = isIntConv
|
else: result = isIntConv
|
||||||
else: result = isNone
|
else: result = isNone
|
||||||
|
|
||||||
|
proc genericParamPut(c: var TCandidate; last, fGenericOrigin: PType) =
|
||||||
|
if fGenericOrigin != nil and last.kind == tyGenericInst and
|
||||||
|
last.len-1 == fGenericOrigin.len:
|
||||||
|
for i in countup(1, sonsLen(fGenericOrigin) - 1):
|
||||||
|
let x = PType(idTableGet(c.bindings, fGenericOrigin.sons[i]))
|
||||||
|
if x == nil:
|
||||||
|
put(c, fGenericOrigin.sons[i], last.sons[i])
|
||||||
|
|
||||||
proc isObjectSubtype(c: var TCandidate; a, f, fGenericOrigin: PType): int =
|
proc isObjectSubtype(c: var TCandidate; a, f, fGenericOrigin: PType): int =
|
||||||
var t = a
|
var t = a
|
||||||
assert t.kind == tyObject
|
assert t.kind == tyObject
|
||||||
|
|
@ -363,12 +371,7 @@ proc isObjectSubtype(c: var TCandidate; a, f, fGenericOrigin: PType): int =
|
||||||
t = skipTypes(t, skipPtrs)
|
t = skipTypes(t, skipPtrs)
|
||||||
inc depth
|
inc depth
|
||||||
if t != nil:
|
if t != nil:
|
||||||
if fGenericOrigin != nil and last.kind == tyGenericInst and
|
genericParamPut(c, last, fGenericOrigin)
|
||||||
last.len-1 == fGenericOrigin.len:
|
|
||||||
for i in countup(1, sonsLen(fGenericOrigin) - 1):
|
|
||||||
let x = PType(idTableGet(c.bindings, fGenericOrigin.sons[i]))
|
|
||||||
if x == nil:
|
|
||||||
put(c, fGenericOrigin.sons[i], last.sons[i])
|
|
||||||
result = depth
|
result = depth
|
||||||
else:
|
else:
|
||||||
result = -1
|
result = -1
|
||||||
|
|
@ -398,7 +401,7 @@ proc skipToObject(t: PType; skipped: var SkippedPtr): PType =
|
||||||
break
|
break
|
||||||
if r.kind == tyObject and ptrs <= 1: result = r
|
if r.kind == tyObject and ptrs <= 1: result = r
|
||||||
|
|
||||||
proc isGenericSubtype(a, f: PType, d: var int): bool =
|
proc isGenericSubtype(c: var TCandidate; a, f: PType, d: var int, fGenericOrigin: PType = nil): 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
|
||||||
|
|
@ -406,14 +409,17 @@ proc isGenericSubtype(a, f: PType, d: var int): bool =
|
||||||
let r = f.skipToObject(fskip)
|
let r = f.skipToObject(fskip)
|
||||||
if r == nil: return false
|
if r == nil: return false
|
||||||
var depth = 0
|
var depth = 0
|
||||||
|
var last = a
|
||||||
# XXX sameObjectType can return false here. Need to investigate
|
# XXX sameObjectType can return false here. Need to investigate
|
||||||
# why that is but sameObjectType does way too much work here anyway.
|
# why that is but sameObjectType does way too much work here anyway.
|
||||||
while t != nil and r.sym != t.sym and askip == fskip:
|
while t != nil and r.sym != t.sym and askip == fskip:
|
||||||
t = t.sons[0]
|
t = t.sons[0]
|
||||||
if t != nil: t = t.skipToObject(askip)
|
if t == nil: break
|
||||||
else: break
|
last = t
|
||||||
|
t = t.skipToObject(askip)
|
||||||
inc depth
|
inc depth
|
||||||
if t != nil and askip == fskip:
|
if t != nil and askip == fskip:
|
||||||
|
genericParamPut(c, last, fGenericOrigin)
|
||||||
d = depth
|
d = depth
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
|
|
@ -999,7 +1005,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
# 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]) or isGenericSubtype(x, f, depth)) and
|
((f.sons[0] == x.sons[0]) or isGenericSubType(c, 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:
|
||||||
|
|
@ -1039,6 +1045,14 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
else:
|
else:
|
||||||
put(c, f.sons[i], x)
|
put(c, f.sons[i], x)
|
||||||
|
|
||||||
|
if result == isNone:
|
||||||
|
# Here object inheriting from generic/specialized generic object
|
||||||
|
# crossing path with metatypes/aliases, so we need to separate them
|
||||||
|
# by checking sym.id
|
||||||
|
let genericSubtype = isGenericSubType(c, x, f, depth, f)
|
||||||
|
if not (genericSubtype and aobj.sym.id != fobj.sym.id):
|
||||||
|
depth = -1
|
||||||
|
|
||||||
if depth >= 0:
|
if depth >= 0:
|
||||||
c.inheritancePenalty += depth
|
c.inheritancePenalty += depth
|
||||||
# bug #4863: We still need to bind generic alias crap, so
|
# bug #4863: We still need to bind generic alias crap, so
|
||||||
|
|
|
||||||
65
tests/generics/tobjecttyperel.nim
Normal file
65
tests/generics/tobjecttyperel.nim
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
discard """
|
||||||
|
output: '''(peel: 0, color: 15)
|
||||||
|
(color: 15)
|
||||||
|
17
|
||||||
|
(width: 0.0, taste: nil, color: 13)
|
||||||
|
(width: 0.0, taste: nil, color: 15)
|
||||||
|
cool'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
# bug #5241
|
||||||
|
type
|
||||||
|
BaseFruit[T] = object of RootObj
|
||||||
|
color: T
|
||||||
|
|
||||||
|
MidLevel[T] = object of BaseFruit[T]
|
||||||
|
|
||||||
|
Mango = object of MidLevel[int]
|
||||||
|
peel: int
|
||||||
|
|
||||||
|
Peach[X, T, Y] = object of T
|
||||||
|
width: X
|
||||||
|
taste: Y
|
||||||
|
|
||||||
|
proc setColor[T](self: var BaseFruit[T]) =
|
||||||
|
self.color = 15
|
||||||
|
|
||||||
|
proc setColor[T](self: var BaseFruit[T], c: int) =
|
||||||
|
self.color = c
|
||||||
|
|
||||||
|
var c: Mango
|
||||||
|
setColor(c)
|
||||||
|
echo c
|
||||||
|
|
||||||
|
var d: MidLevel[int]
|
||||||
|
setColor(d)
|
||||||
|
echo d
|
||||||
|
|
||||||
|
type
|
||||||
|
FooBase[T] = ref object of RootRef
|
||||||
|
v: T
|
||||||
|
BarClient = ref object of FooBase[int]
|
||||||
|
|
||||||
|
proc getColor[T](f: FooBase[T]): T = 17
|
||||||
|
var b: BarClient
|
||||||
|
echo getColor(b)
|
||||||
|
|
||||||
|
var z: Peach[float64, BaseFruit[int], string]
|
||||||
|
z.setColor(13)
|
||||||
|
echo z
|
||||||
|
|
||||||
|
z.setColor()
|
||||||
|
echo z
|
||||||
|
|
||||||
|
# bug #5411
|
||||||
|
type
|
||||||
|
Foo[T] = ref object of RootRef
|
||||||
|
v: T
|
||||||
|
Bar = ref object of Foo[int]
|
||||||
|
|
||||||
|
method m(o: RootRef) {.base.} = assert(false, "Abstract method called")
|
||||||
|
method m[T](o: Foo[T]) = echo "cool"
|
||||||
|
|
||||||
|
var v: Bar
|
||||||
|
v.new()
|
||||||
|
v.m() # Abstract method not called anymore
|
||||||
Loading…
Add table
Add a link
Reference in a new issue