diff options
-rwxr-xr-x | compiler/cgmeth.nim | 19 | ||||
-rwxr-xr-x | compiler/sem.nim | 3 | ||||
-rwxr-xr-x | compiler/semcall.nim | 20 | ||||
-rwxr-xr-x | compiler/seminst.nim | 1 | ||||
-rwxr-xr-x | compiler/semstmts.nim | 29 | ||||
-rwxr-xr-x | compiler/types.nim | 8 | ||||
-rw-r--r-- | tests/run/tmultim6.nim | 30 | ||||
-rwxr-xr-x | todo.txt | 1 | ||||
-rwxr-xr-x | web/news.txt | 1 |
9 files changed, 81 insertions, 31 deletions
diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim index 687653aaf..e7bd54ef0 100755 --- a/compiler/cgmeth.nim +++ b/compiler/cgmeth.nim @@ -1,7 +1,7 @@ # # # The Nimrod Compiler -# (c) Copyright 2012 Andreas Rumpf +# (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -65,10 +65,10 @@ proc sameMethodBucket(a, b: PSym): bool = break if sameType(aa, bb) or (aa.kind == tyObject) and (bb.kind == tyObject) and - (inheritanceDiff(bb, aa) < 0): + (inheritanceDiff(bb, aa) < 0): nil - else: - return + else: + return result = true proc attachDispatcher(s: PSym, dispatcher: PNode) = @@ -106,17 +106,16 @@ proc methodDef*(s: PSym, fromCache: bool) = # attach to itself to prevent bugs: attachDispatcher(disp, newSymNode(disp)) -proc relevantCol(methods: TSymSeq, col: int): bool = +proc relevantCol(methods: TSymSeq, col: int): bool = # returns true iff the position is relevant var t = methods[0].typ.sons[col] - result = false - if skipTypes(t, skipPtrs).kind == tyObject: - for i in countup(1, high(methods)): - if not SameType(methods[i].typ.sons[col], t): + if skipTypes(t, skipPtrs).kind == tyObject: + for i in countup(1, high(methods)): + let t2 = skipTypes(methods[i].typ.sons[col], skipPtrs) + if not SameType(t2, t): return true proc cmpSignatures(a, b: PSym, relevantCols: TIntSet): int = - result = 0 for col in countup(1, sonsLen(a.typ) - 1): if Contains(relevantCols, col): var aa = skipTypes(a.typ.sons[col], skipPtrs) diff --git a/compiler/sem.nim b/compiler/sem.nim index c70cbf61e..77e93a066 100755 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -1,7 +1,7 @@ # # # The Nimrod Compiler -# (c) Copyright 2012 Andreas Rumpf +# (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -45,6 +45,7 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode proc fixImmediateParams(n: PNode): PNode proc activate(c: PContext, n: PNode) proc semQuoteAst(c: PContext, n: PNode): PNode +proc finishMethod(c: PContext, s: PSym) proc IndexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 0a5f19822..67d157261 100755 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -1,7 +1,7 @@ # # # The Nimrod Compiler -# (c) Copyright 2012 Andreas Rumpf +# (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -15,8 +15,22 @@ proc sameMethodDispatcher(a, b: PSym): bool = if a.kind == skMethod and b.kind == skMethod: var aa = lastSon(a.ast) var bb = lastSon(b.ast) - if aa.kind == nkSym and bb.kind == nkSym and aa.sym == bb.sym: - result = true + if aa.kind == nkSym and bb.kind == nkSym: + if aa.sym == bb.sym: + result = true + else: + nil + # generics have no dispatcher yet, so we need to compare the method + # names; however, the names are equal anyway because otherwise we + # wouldn't even consider them to be overloaded. But even this does + # not work reliably! See tmultim6 for an example: + # method collide[T](a: TThing, b: TUnit[T]) is instantiated and not + # method collide[T](a: TUnit[T], b: TThing)! This means we need to + # *instantiate* every candidate! However, we don't keep more than 2-3 + # candidated around so we cannot implement that for now. So in order + # to avoid subtle problems, the call remains ambiguous and needs to + # be disambiguated by the programmer; this way the right generic is + # instantiated. proc resolveOverloads(c: PContext, n, orig: PNode, filter: TSymKinds): TCandidate = diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 0a1a17f72..b54170435 100755 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -186,6 +186,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, popOwner() c.friendModule = oldFriend dec(c.InstCounter) + if result.kind == skMethod: finishMethod(c, result) proc instGenericContainer(c: PContext, n: PNode, header: PType): PType = var cl: TReplTypeVars diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index c86e3eb91..363cff89a 100755 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -867,25 +867,26 @@ proc semIterator(c: PContext, n: PNode): PNode = proc semProc(c: PContext, n: PNode): PNode = result = semProcAux(c, n, skProc, procPragmas) +proc hasObjParam(s: PSym): bool = + var t = s.typ + for col in countup(1, sonsLen(t)-1): + if skipTypes(t.sons[col], skipPtrs).kind == tyObject: + return true + +proc finishMethod(c: PContext, s: PSym) = + if hasObjParam(s): + methodDef(s, false) + proc semMethod(c: PContext, n: PNode): PNode = if not isTopLevel(c): LocalError(n.info, errXOnlyAtModuleScope, "method") result = semProcAux(c, n, skMethod, methodPragmas) var s = result.sons[namePos].sym - var t = s.typ - var hasObjParam = false - - for col in countup(1, sonsLen(t)-1): - if skipTypes(t.sons[col], skipPtrs).kind == tyObject: - hasObjParam = true - break - - # XXX this not really correct way to do it: Perhaps it should be done after - # generic instantiation. Well it's good enough for now: - if hasObjParam: - methodDef(s, false) - else: - LocalError(n.info, errXNeedsParamObjectType, "method") + if not isGenericRoutine(s): + if hasObjParam(s): + methodDef(s, false) + else: + LocalError(n.info, errXNeedsParamObjectType, "method") proc semConverterDef(c: PContext, n: PNode): PNode = if not isTopLevel(c): LocalError(n.info, errXOnlyAtModuleScope, "converter") diff --git a/compiler/types.nim b/compiler/types.nim index 23d202fdf..998ba43d2 100755 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -1,7 +1,7 @@ # # # The Nimrod Compiler -# (c) Copyright 2012 Andreas Rumpf +# (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -876,20 +876,24 @@ proc inheritanceDiff*(a, b: PType): int = # | returns: -x iff `a` is the x'th direct superclass of `b` # | returns: +x iff `a` is the x'th direct subclass of `b` # | returns: `maxint` iff `a` and `b` are not compatible at all + assert a.kind == tyObject + assert b.kind == tyObject var x = a result = 0 while x != nil: + x = skipTypes(x, skipPtrs) if sameObjectTypes(x, b): return x = x.sons[0] dec(result) var y = b result = 0 while y != nil: + y = skipTypes(y, skipPtrs) if sameObjectTypes(y, a): return y = y.sons[0] inc(result) result = high(int) - + proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool proc typeAllowedNode(marker: var TIntSet, n: PNode, kind: TSymKind): bool = result = true diff --git a/tests/run/tmultim6.nim b/tests/run/tmultim6.nim new file mode 100644 index 000000000..a55b69e37 --- /dev/null +++ b/tests/run/tmultim6.nim @@ -0,0 +1,30 @@ +discard """ + output: "collide: unit, thing | collide: unit, thing | collide: thing, unit" +""" +# Test multi methods + +type + TThing = object {.inheritable.} + TUnit[T] = object of TThing + x: T + TParticle = object of TThing + a, b: int + +method collide(a, b: TThing) {.inline.} = + quit "to override!" + +method collide[T](a: TThing, b: TUnit[T]) {.inline.} = + write stdout, "collide: thing, unit | " + +method collide[T](a: TUnit[T], b: TThing) {.inline.} = + write stdout, "collide: unit, thing | " + +proc test(a, b: TThing) {.inline.} = + collide(a, b) + +var + a: TThing + b, c: TUnit[string] +collide(b, TThing(c)) +test(b, c) +collide(a, b) diff --git a/todo.txt b/todo.txt index dd3290117..ab7c4f2f7 100755 --- a/todo.txt +++ b/todo.txt @@ -15,7 +15,6 @@ version 0.9.X - test&finish first class iterators: * nested iterators - implement the missing features wrt inheritance -- implement generic methods - improve the compiler as a service - ``=`` should be overloadable; requires specialization for ``=`` - implement constructors + full 'not nil' checking diff --git a/web/news.txt b/web/news.txt index 824e0c3a3..e4e9108e0 100755 --- a/web/news.txt +++ b/web/news.txt @@ -57,6 +57,7 @@ Language Additions symbol forwarding so client modules don't have to import a module's dependencies explicitly. - Overloading based on ASTs has been implemented. +- Generics are now supported for multi methods. 2012-09-23 Version 0.9.0 released |