diff options
author | Andreas Rumpf <rumpf_a@web.de> | 2017-02-24 13:02:36 +0100 |
---|---|---|
committer | Andreas Rumpf <rumpf_a@web.de> | 2017-02-24 13:02:36 +0100 |
commit | f8914cc3b002916c2b9a9cc548eae610d14ef666 (patch) | |
tree | b5ab9dade22a60973e022907c12d857755d45a52 | |
parent | 46f33515d7ec32215122547bce535e4c91894da3 (diff) | |
download | Nim-f8914cc3b002916c2b9a9cc548eae610d14ef666.tar.gz |
fixes a multimethod regression
-rw-r--r-- | compiler/cgmeth.nim | 15 | ||||
-rw-r--r-- | compiler/semstmts.nim | 13 | ||||
-rw-r--r-- | tests/metatype/tautonotgeneric.nim | 13 |
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 |