summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorandri lim <jangko128@gmail.com>2017-03-24 05:39:29 +0700
committerAndreas Rumpf <rumpf_a@web.de>2017-03-23 23:39:29 +0100
commit568c954062c203383be0073126b2e7090721364f (patch)
treeab9a597f2a8304c026e22ffc11ef1ae06d95f05d
parent0cad2896ae7aa7d9b2561785f9243ceb546abf99 (diff)
downloadNim-568c954062c203383be0073126b2e7090721364f.tar.gz
fixes #5241, fixes #5411 inherit from specialized generic typeRel problem (#5573)
-rw-r--r--compiler/sigmatch.nim34
-rw-r--r--tests/generics/tobjecttyperel.nim65
2 files changed, 89 insertions, 10 deletions
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