summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAnatoly Galiulin <galiulin.anatoly@gmail.com>2016-06-23 18:37:14 +0600
committerAnatoly Galiulin <galiulin.anatoly@gmail.com>2016-06-23 18:37:14 +0600
commit764668d099a67ef6b877d07e4857c92d5774fe98 (patch)
treea4a3c74cc62784e6bb4f18158b6690282ce7c3bb
parent4b0ba5e3f1b78b3c45a3f1576ed3d60f9a8b6d80 (diff)
downloadNim-764668d099a67ef6b877d07e4857c92d5774fe98.tar.gz
Fix generics inheritance issues
-rw-r--r--compiler/sigmatch.nim25
-rw-r--r--tests/generics/t88.nim25
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"