summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2017-02-24 13:02:36 +0100
committerAndreas Rumpf <rumpf_a@web.de>2017-02-24 13:02:36 +0100
commitf8914cc3b002916c2b9a9cc548eae610d14ef666 (patch)
treeb5ab9dade22a60973e022907c12d857755d45a52
parent46f33515d7ec32215122547bce535e4c91894da3 (diff)
downloadNim-f8914cc3b002916c2b9a9cc548eae610d14ef666.tar.gz
fixes a multimethod regression
-rw-r--r--compiler/cgmeth.nim15
-rw-r--r--compiler/semstmts.nim13
-rw-r--r--tests/metatype/tautonotgeneric.nim13
3 files changed, 33 insertions, 8 deletions
diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim
index 52fd8ab49..3a945ae0a 100644
--- a/compiler/cgmeth.nim
+++ b/compiler/cgmeth.nim
@@ -35,15 +35,18 @@ proc genConv(n: PNode, d: PType, downcast: bool): PNode =
   else:
     result = n
 
+proc getDispatcher*(s: PSym): PSym =
+  ## can return nil if is has no dispatcher.
+  let dispn = lastSon(s.ast)
+  if dispn.kind == nkSym:
+    let disp = dispn.sym
+    if sfDispatcher in disp.flags: result = disp
+
 proc methodCall*(n: PNode): PNode =
   result = n
   # replace ordinary method by dispatcher method:
-  let dispn = lastSon(result.sons[0].sym.ast)
-  if dispn.kind == nkSym:
-    let disp = dispn.sym
-    if sfDispatcher notin disp.flags:
-      localError(n.info, "'" & $result & "' lacks a dispatcher")
-      return
+  let disp = getDispatcher(result.sons[0].sym)
+  if disp != nil:
     result.sons[0].sym = disp
     # change the arguments to up/downcasts to fit the dispatcher's parameters:
     for i in countup(1, sonsLen(result)-1):
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 5ecba3ab0..c28dbf82f 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -1443,6 +1443,19 @@ proc semProc(c: PContext, n: PNode): PNode =
 proc semMethod(c: PContext, n: PNode): PNode =
   if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "method")
   result = semProcAux(c, n, skMethod, methodPragmas)
+  # macros can transform converters to nothing:
+  if namePos >= result.safeLen: return result
+  var s = result.sons[namePos].sym
+  # we need to fix the 'auto' return type for the dispatcher here (see tautonotgeneric
+  # test case):
+  let disp = getDispatcher(s)
+  # auto return type?
+  if disp != nil and disp.typ.sons[0] != nil and disp.typ.sons[0].kind == tyExpr:
+    let ret = s.typ.sons[0]
+    disp.typ.sons[0] = ret
+    if disp.ast[resultPos].kind == nkSym:
+      if isEmptyType(ret): disp.ast.sons[resultPos] = emptyNode
+      else: disp.ast[resultPos].sym.typ = ret
 
 proc semConverterDef(c: PContext, n: PNode): PNode =
   if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "converter")
diff --git a/tests/metatype/tautonotgeneric.nim b/tests/metatype/tautonotgeneric.nim
index a55ae488e..f0d6932f9 100644
--- a/tests/metatype/tautonotgeneric.nim
+++ b/tests/metatype/tautonotgeneric.nim
@@ -1,15 +1,24 @@
 discard """
-  output: "wof!"
+  output: '''wof!
+wof!'''
 """
 
 # bug #1659
 type Animal = ref object {.inheritable.}
 type Dog = ref object of Animal
 
-method say(a: Animal): auto = "wat!"
+method say(a: Animal): auto {.base.} = "wat!"
 method say(a: Dog): auto = "wof!"
 
 proc saySomething(a: Animal): auto = a.say()
 
+
+method ec(a: Animal): auto {.base.} = echo "wat!"
+method ec(a: Dog): auto = echo "wof!"
+
+proc ech(a: Animal): auto = a.ec()
+
+
 var a = Dog()
 echo saySomething(a)
+ech a