implemented generic multi methods
This commit is contained in:
parent
c9690864d4
commit
c43697b59a
9 changed files with 81 additions and 31 deletions
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 =
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
|
||||||
|
|
@ -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
30
tests/run/tmultim6.nim
Normal 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)
|
||||||
1
todo.txt
1
todo.txt
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue