From 568c954062c203383be0073126b2e7090721364f Mon Sep 17 00:00:00 2001 From: andri lim Date: Fri, 24 Mar 2017 05:39:29 +0700 Subject: fixes #5241, fixes #5411 inherit from specialized generic typeRel problem (#5573) --- compiler/sigmatch.nim | 34 ++++++++++++++------ tests/generics/tobjecttyperel.nim | 65 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+), 10 deletions(-) create mode 100644 tests/generics/tobjecttyperel.nim diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index ae7be3c6d..164fd0999 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -350,6 +350,14 @@ proc handleFloatRange(f, a: PType): TTypeRelation = else: result = isIntConv 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 = var t = a assert t.kind == tyObject @@ -363,12 +371,7 @@ proc isObjectSubtype(c: var TCandidate; a, f, fGenericOrigin: PType): int = t = skipTypes(t, skipPtrs) inc depth if t != nil: - 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]) + genericParamPut(c, last, fGenericOrigin) result = depth else: result = -1 @@ -398,7 +401,7 @@ proc skipToObject(t: PType; skipped: var SkippedPtr): PType = break 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} var askip = skippedNone var fskip = skippedNone @@ -406,14 +409,17 @@ proc isGenericSubtype(a, f: PType, d: var int): bool = let r = f.skipToObject(fskip) if r == nil: return false var depth = 0 + var last = a # XXX sameObjectType can return false here. Need to investigate # 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 + if t == nil: break + last = t + t = t.skipToObject(askip) inc depth if t != nil and askip == fskip: + genericParamPut(c, last, fGenericOrigin) d = depth result = true @@ -999,7 +1005,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = # simply no match for now: discard 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)): for i in countup(1, sonsLen(f) - 1): if x.sons[i].kind == tyGenericParam: @@ -1039,6 +1045,14 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = else: 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: c.inheritancePenalty += depth # bug #4863: We still need to bind generic alias crap, so diff --git a/tests/generics/tobjecttyperel.nim b/tests/generics/tobjecttyperel.nim new file mode 100644 index 000000000..8c8f90098 --- /dev/null +++ b/tests/generics/tobjecttyperel.nim @@ -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 \ No newline at end of file -- cgit 1.4.1-2-gfad0