From c43697b59a08459fdfe41129b9ed0f96cf0150fa Mon Sep 17 00:00:00 2001 From: Araq Date: Wed, 16 Jan 2013 08:42:30 +0100 Subject: implemented generic multi methods --- compiler/cgmeth.nim | 19 +++++++++---------- compiler/sem.nim | 3 ++- compiler/semcall.nim | 20 +++++++++++++++++--- compiler/seminst.nim | 1 + compiler/semstmts.nim | 29 +++++++++++++++-------------- compiler/types.nim | 8 ++++++-- 6 files changed, 50 insertions(+), 30 deletions(-) (limited to 'compiler') 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 -- cgit 1.4.1-2-gfad0