implemented generic multi methods

This commit is contained in:
Araq 2013-01-16 08:42:30 +01:00
commit c43697b59a
9 changed files with 81 additions and 31 deletions

View file

@ -1,7 +1,7 @@
# #
# #
# The Nimrod Compiler # The Nimrod Compiler
# (c) Copyright 2012 Andreas Rumpf # (c) Copyright 2013 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
@ -109,14 +109,13 @@ proc methodDef*(s: PSym, fromCache: bool) =
proc relevantCol(methods: TSymSeq, col: int): bool = proc relevantCol(methods: TSymSeq, col: int): bool =
# returns true iff the position is relevant # returns true iff the position is relevant
var t = methods[0].typ.sons[col] var t = methods[0].typ.sons[col]
result = false
if skipTypes(t, skipPtrs).kind == tyObject: if skipTypes(t, skipPtrs).kind == tyObject:
for i in countup(1, high(methods)): for i in countup(1, high(methods)):
if not SameType(methods[i].typ.sons[col], t): let t2 = skipTypes(methods[i].typ.sons[col], skipPtrs)
if not SameType(t2, t):
return true return true
proc cmpSignatures(a, b: PSym, relevantCols: TIntSet): int = proc cmpSignatures(a, b: PSym, relevantCols: TIntSet): int =
result = 0
for col in countup(1, sonsLen(a.typ) - 1): for col in countup(1, sonsLen(a.typ) - 1):
if Contains(relevantCols, col): if Contains(relevantCols, col):
var aa = skipTypes(a.typ.sons[col], skipPtrs) var aa = skipTypes(a.typ.sons[col], skipPtrs)

View file

@ -1,7 +1,7 @@
# #
# #
# The Nimrod Compiler # The Nimrod Compiler
# (c) Copyright 2012 Andreas Rumpf # (c) Copyright 2013 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # 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 fixImmediateParams(n: PNode): PNode
proc activate(c: PContext, n: PNode) proc activate(c: PContext, n: PNode)
proc semQuoteAst(c: PContext, n: PNode): PNode proc semQuoteAst(c: PContext, n: PNode): PNode
proc finishMethod(c: PContext, s: PSym)
proc IndexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode proc IndexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode

View file

@ -1,7 +1,7 @@
# #
# #
# The Nimrod Compiler # The Nimrod Compiler
# (c) Copyright 2012 Andreas Rumpf # (c) Copyright 2013 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
@ -15,8 +15,22 @@ proc sameMethodDispatcher(a, b: PSym): bool =
if a.kind == skMethod and b.kind == skMethod: if a.kind == skMethod and b.kind == skMethod:
var aa = lastSon(a.ast) var aa = lastSon(a.ast)
var bb = lastSon(b.ast) var bb = lastSon(b.ast)
if aa.kind == nkSym and bb.kind == nkSym and aa.sym == bb.sym: if aa.kind == nkSym and bb.kind == nkSym:
result = true 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, proc resolveOverloads(c: PContext, n, orig: PNode,
filter: TSymKinds): TCandidate = filter: TSymKinds): TCandidate =

View file

@ -186,6 +186,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
popOwner() popOwner()
c.friendModule = oldFriend c.friendModule = oldFriend
dec(c.InstCounter) dec(c.InstCounter)
if result.kind == skMethod: finishMethod(c, result)
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType = proc instGenericContainer(c: PContext, n: PNode, header: PType): PType =
var cl: TReplTypeVars var cl: TReplTypeVars

View file

@ -867,25 +867,26 @@ proc semIterator(c: PContext, n: PNode): PNode =
proc semProc(c: PContext, n: PNode): PNode = proc semProc(c: PContext, n: PNode): PNode =
result = semProcAux(c, n, skProc, procPragmas) 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 = proc semMethod(c: PContext, n: PNode): PNode =
if not isTopLevel(c): LocalError(n.info, errXOnlyAtModuleScope, "method") if not isTopLevel(c): LocalError(n.info, errXOnlyAtModuleScope, "method")
result = semProcAux(c, n, skMethod, methodPragmas) result = semProcAux(c, n, skMethod, methodPragmas)
var s = result.sons[namePos].sym var s = result.sons[namePos].sym
var t = s.typ if not isGenericRoutine(s):
var hasObjParam = false if hasObjParam(s):
methodDef(s, false)
for col in countup(1, sonsLen(t)-1): else:
if skipTypes(t.sons[col], skipPtrs).kind == tyObject: LocalError(n.info, errXNeedsParamObjectType, "method")
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")
proc semConverterDef(c: PContext, n: PNode): PNode = proc semConverterDef(c: PContext, n: PNode): PNode =
if not isTopLevel(c): LocalError(n.info, errXOnlyAtModuleScope, "converter") if not isTopLevel(c): LocalError(n.info, errXOnlyAtModuleScope, "converter")

View file

@ -1,7 +1,7 @@
# #
# #
# The Nimrod Compiler # The Nimrod Compiler
# (c) Copyright 2012 Andreas Rumpf # (c) Copyright 2013 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
@ -876,15 +876,19 @@ 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 superclass of `b`
# | returns: +x iff `a` is the x'th direct subclass 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 # | returns: `maxint` iff `a` and `b` are not compatible at all
assert a.kind == tyObject
assert b.kind == tyObject
var x = a var x = a
result = 0 result = 0
while x != nil: while x != nil:
x = skipTypes(x, skipPtrs)
if sameObjectTypes(x, b): return if sameObjectTypes(x, b): return
x = x.sons[0] x = x.sons[0]
dec(result) dec(result)
var y = b var y = b
result = 0 result = 0
while y != nil: while y != nil:
y = skipTypes(y, skipPtrs)
if sameObjectTypes(y, a): return if sameObjectTypes(y, a): return
y = y.sons[0] y = y.sons[0]
inc(result) inc(result)

30
tests/run/tmultim6.nim Normal file
View file

@ -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)

View file

@ -15,7 +15,6 @@ version 0.9.X
- test&finish first class iterators: - test&finish first class iterators:
* nested iterators * nested iterators
- implement the missing features wrt inheritance - implement the missing features wrt inheritance
- implement generic methods
- improve the compiler as a service - improve the compiler as a service
- ``=`` should be overloadable; requires specialization for ``=`` - ``=`` should be overloadable; requires specialization for ``=``
- implement constructors + full 'not nil' checking - implement constructors + full 'not nil' checking

View file

@ -57,6 +57,7 @@ Language Additions
symbol forwarding so client modules don't have to import a module's symbol forwarding so client modules don't have to import a module's
dependencies explicitly. dependencies explicitly.
- Overloading based on ASTs has been implemented. - Overloading based on ASTs has been implemented.
- Generics are now supported for multi methods.
2012-09-23 Version 0.9.0 released 2012-09-23 Version 0.9.0 released