summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2016-07-18 12:16:54 +0200
committerAndreas Rumpf <rumpf_a@web.de>2016-07-18 12:16:54 +0200
commitd779a9b722f432fff25de9ddb97f57b5179eaaef (patch)
tree8111008de19cd6607c1c195e30871d88874514b9
parent55db59a897b0c61303b65c7af4d8ef9b110861ef (diff)
downloadNim-d779a9b722f432fff25de9ddb97f57b5179eaaef.tar.gz
fixes #4478
-rw-r--r--compiler/sigmatch.nim39
-rw-r--r--tests/typerel/tgeneric_subtype_regression.nim19
2 files changed, 49 insertions, 9 deletions
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 7c57936eb..a3b9de5f4 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -364,22 +364,43 @@ proc isObjectSubtype(a, f: PType): int =
   if t != nil:
     result = depth
 
-proc skipToGenericBody(t: PType): PType =
+type
+  SkippedPtr = enum skippedNone, skippedRef, skippedPtr
+
+proc skipToGenericBody(t: PType; skipped: var SkippedPtr): PType =
   var r = t
+  # we're allowed to skip one level of ptr/ref:
+  var ptrs = 0
   while r != nil:
-    if r.kind in {tyGenericInst, tyGenericInvocation}:
-      return r.sons[0]
-    r = if r.len > 0: r.lastSon else: nil
+    case r.kind
+    of tyGenericInst, tyGenericInvocation:
+      result = r.sons[0]
+      break
+    of tyRef:
+      inc ptrs
+      skipped = skippedRef
+      r = r.lastSon
+    of tyPtr:
+      inc ptrs
+      skipped = skippedPtr
+      r = r.lastSon
+    of tyGenericBody:
+      r = r.lastSon
+    else:
+      break
+  if ptrs > 1: result = 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 askip = skippedNone
+  var fskip = skippedNone
+  var t = if a.kind == tyGenericBody: a else: a.skipToGenericBody(askip)
+  var r = if f.kind == tyGenericBody: f else: f.skipToGenericBody(fskip)
   var depth = 0
-  while t != nil and not sameObjectTypes(r, t):
-    t = t.skipToGenericBody
+  while t != nil and not sameObjectTypes(r, t) and askip == fskip:
+    t = t.skipToGenericBody(askip)
     inc depth
-  if t != nil:
+  if t != nil and askip == fskip:
     d = depth
     result = true
 
diff --git a/tests/typerel/tgeneric_subtype_regression.nim b/tests/typerel/tgeneric_subtype_regression.nim
new file mode 100644
index 000000000..e279c0ad4
--- /dev/null
+++ b/tests/typerel/tgeneric_subtype_regression.nim
@@ -0,0 +1,19 @@
+discard """
+  errormsg: "type mismatch: got (FooRef[system.string])"
+  line: 15
+"""
+
+# bug #4478
+
+type
+  Foo[T] = object
+  FooRef[T] = ref Foo[T]
+
+proc takeFoo[T](foo: Foo[T]): int = discard
+
+proc g(x: FooRef[string]) =
+  echo x.takeFoo() != 8
+
+var x: FooRef[string]
+
+g(x)