diff options
author | Anatoly Galiulin <galiulin.anatoly@gmail.com> | 2016-06-23 18:37:14 +0600 |
---|---|---|
committer | Anatoly Galiulin <galiulin.anatoly@gmail.com> | 2016-06-23 18:37:14 +0600 |
commit | 764668d099a67ef6b877d07e4857c92d5774fe98 (patch) | |
tree | a4a3c74cc62784e6bb4f18158b6690282ce7c3bb | |
parent | 4b0ba5e3f1b78b3c45a3f1576ed3d60f9a8b6d80 (diff) | |
download | Nim-764668d099a67ef6b877d07e4857c92d5774fe98.tar.gz |
Fix generics inheritance issues
-rw-r--r-- | compiler/sigmatch.nim | 25 | ||||
-rw-r--r-- | tests/generics/t88.nim | 25 |
2 files changed, 48 insertions, 2 deletions
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index df27e3c1d..acbf7d426 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -363,6 +363,25 @@ proc isObjectSubtype(a, f: PType): int = if t != nil: 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 = if a <= b: result = a else: result = b @@ -647,7 +666,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = template bindingRet(res) = if doBind: let bound = aOrig.skipTypes({tyRange}).skipIntLit - if doBind: put(c.bindings, f, bound) + put(c.bindings, f, bound) return res template considerPreviousT(body: stmt) {.immediate.} = @@ -945,17 +964,19 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = of tyGenericInvocation: var x = a.skipGenericAlias + var depth = 0 if x.kind == tyGenericInvocation or f.sons[0].kind != tyGenericBody: #InternalError("typeRel: tyGenericInvocation -> tyGenericInvocation") # simply no match for now: discard elif x.kind == tyGenericInst and - (f.sons[0] == x.sons[0]) and + isGenericSubtype(x, f, depth) and (sonsLen(x) - 1 == sonsLen(f)): for i in countup(1, sonsLen(f) - 1): if x.sons[i].kind == tyGenericParam: internalError("wrong instantiated type!") elif typeRel(c, f.sons[i], x.sons[i]) <= isSubtype: return + c.inheritancePenalty = depth result = isGeneric else: let genericBody = f.sons[0] diff --git a/tests/generics/t88.nim b/tests/generics/t88.nim new file mode 100644 index 000000000..93d93f063 --- /dev/null +++ b/tests/generics/t88.nim @@ -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" |