generic multi-methods should work now

This commit is contained in:
Andreas Rumpf 2016-07-28 20:23:16 +02:00
commit f5fa5dae85
9 changed files with 67 additions and 21 deletions

View file

@ -850,6 +850,7 @@ type
# see instantiateDestructor in semdestruct.nim # see instantiateDestructor in semdestruct.nim
deepCopy*: PSym # overriden 'deepCopy' operation deepCopy*: PSym # overriden 'deepCopy' operation
assignment*: PSym # overriden '=' operator assignment*: PSym # overriden '=' operator
methods*: seq[(int,PSym)] # attached methods
size*: BiggestInt # the size of the type in bytes size*: BiggestInt # the size of the type in bytes
# -1 means that the size is unkwown # -1 means that the size is unkwown
align*: int16 # the type's alignment requirements align*: int16 # the type's alignment requirements

View file

@ -63,7 +63,7 @@ proc sameMethodBucket(a, b: PSym): MethodResult =
while true: while true:
aa = skipTypes(aa, {tyGenericInst}) aa = skipTypes(aa, {tyGenericInst})
bb = skipTypes(bb, {tyGenericInst}) bb = skipTypes(bb, {tyGenericInst})
if (aa.kind == bb.kind) and (aa.kind in {tyVar, tyPtr, tyRef}): if aa.kind == bb.kind and aa.kind in {tyVar, tyPtr, tyRef}:
aa = aa.lastSon aa = aa.lastSon
bb = bb.lastSon bb = bb.lastSon
else: else:
@ -187,7 +187,7 @@ proc cmpSignatures(a, b: PSym, relevantCols: IntSet): int =
var aa = skipTypes(a.typ.sons[col], skipPtrs) var aa = skipTypes(a.typ.sons[col], skipPtrs)
var bb = skipTypes(b.typ.sons[col], skipPtrs) var bb = skipTypes(b.typ.sons[col], skipPtrs)
var d = inheritanceDiff(aa, bb) var d = inheritanceDiff(aa, bb)
if (d != high(int)): if (d != high(int)) and d != 0:
return d return d
proc sortBucket(a: var TSymSeq, relevantCols: IntSet) = proc sortBucket(a: var TSymSeq, relevantCols: IntSet) =

View file

@ -104,7 +104,7 @@ type
hloLoopDetector*: int # used to prevent endless loops in the HLO hloLoopDetector*: int # used to prevent endless loops in the HLO
inParallelStmt*: int inParallelStmt*: int
instTypeBoundOp*: proc (c: PContext; dc: PSym; t: PType; info: TLineInfo; instTypeBoundOp*: proc (c: PContext; dc: PSym; t: PType; info: TLineInfo;
op: TTypeAttachedOp): PSym {.nimcall.} op: TTypeAttachedOp; col: int): PSym {.nimcall.}
selfName*: PIdent selfName*: PIdent
signatures*: TStrTable signatures*: TStrTable

View file

@ -1352,7 +1352,19 @@ proc semMethod(c: PContext, n: PNode): PNode =
# macros can transform methods to nothing: # macros can transform methods to nothing:
if namePos >= result.safeLen: return result if namePos >= result.safeLen: return result
var s = result.sons[namePos].sym var s = result.sons[namePos].sym
if not isGenericRoutine(s): if isGenericRoutine(s):
let tt = s.typ
var foundObj = false
for col in countup(0, sonsLen(tt)-1):
let t = tt.sons[col]
if t != nil and t.kind == tyGenericInvocation:
var x = skipTypes(t.sons[0], {tyVar, tyPtr, tyRef, tyGenericInst, tyGenericInvocation, tyGenericBody})
if x.kind == tyObject:
foundObj = true
x.methods.safeAdd((col,s))
if not foundObj:
message(n.info, warnDeprecated, "generic method not attachable to object type")
else:
# why check for the body? bug #2400 has none. Checking for sfForward makes # why check for the body? bug #2400 has none. Checking for sfForward makes
# no sense either. # no sense either.
# and result.sons[bodyPos].kind != nkEmpty: # and result.sons[bodyPos].kind != nkEmpty:

View file

@ -289,7 +289,8 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
# but we already raised an error! # but we already raised an error!
rawAddSon(result, header.sons[i]) rawAddSon(result, header.sons[i])
var newbody = replaceTypeVarsT(cl, lastSon(body)) let bbody = lastSon body
var newbody = replaceTypeVarsT(cl, bbody)
cl.skipTypedesc = oldSkipTypedesc cl.skipTypedesc = oldSkipTypedesc
newbody.flags = newbody.flags + (t.flags + body.flags - tfInstClearedFlags) newbody.flags = newbody.flags + (t.flags + body.flags - tfInstClearedFlags)
result.flags = result.flags + newbody.flags - tfInstClearedFlags result.flags = result.flags + newbody.flags - tfInstClearedFlags
@ -306,12 +307,18 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
# 'deepCopy' needs to be instantiated for # 'deepCopy' needs to be instantiated for
# generics *when the type is constructed*: # generics *when the type is constructed*:
newbody.deepCopy = cl.c.instTypeBoundOp(cl.c, dc, result, cl.info, newbody.deepCopy = cl.c.instTypeBoundOp(cl.c, dc, result, cl.info,
attachedDeepCopy) attachedDeepCopy, 1)
let asgn = newbody.assignment let asgn = newbody.assignment
if asgn != nil and sfFromGeneric notin asgn.flags: if asgn != nil and sfFromGeneric notin asgn.flags:
# '=' needs to be instantiated for generics when the type is constructed: # '=' needs to be instantiated for generics when the type is constructed:
newbody.assignment = cl.c.instTypeBoundOp(cl.c, asgn, result, cl.info, newbody.assignment = cl.c.instTypeBoundOp(cl.c, asgn, result, cl.info,
attachedAsgn) attachedAsgn, 1)
let methods = skipTypes(bbody, abstractPtrs).methods
for col, meth in items(methods):
# we instantiate the known methods belonging to that type, this causes
# them to be registered and that's enough, so we 'discard' the result.
discard cl.c.instTypeBoundOp(cl.c, meth, result, cl.info,
attachedAsgn, col)
proc eraseVoidParams*(t: PType) = proc eraseVoidParams*(t: PType) =
# transform '(): void' into '()' because old parts of the compiler really # transform '(): void' into '()' because old parts of the compiler really

View file

@ -1796,16 +1796,19 @@ proc argtypeMatches*(c: PContext, f, a: PType): bool =
result = res != nil result = res != nil
proc instTypeBoundOp*(c: PContext; dc: PSym; t: PType; info: TLineInfo; proc instTypeBoundOp*(c: PContext; dc: PSym; t: PType; info: TLineInfo;
op: TTypeAttachedOp): PSym {.procvar.} = op: TTypeAttachedOp; col: int): PSym {.procvar.} =
var m: TCandidate var m: TCandidate
initCandidate(c, m, dc.typ) initCandidate(c, m, dc.typ)
var f = dc.typ.sons[1] if col >= dc.typ.len:
localError(info, errGenerated, "cannot instantiate '" & dc.name.s & "'")
return nil
var f = dc.typ.sons[col]
if op == attachedDeepCopy: if op == attachedDeepCopy:
if f.kind in {tyRef, tyPtr}: f = f.lastSon if f.kind in {tyRef, tyPtr}: f = f.lastSon
else: else:
if f.kind == tyVar: f = f.lastSon if f.kind == tyVar: f = f.lastSon
if typeRel(m, f, t) == isNone: if typeRel(m, f, t) == isNone:
localError(info, errGenerated, "cannot instantiate 'deepCopy'") localError(info, errGenerated, "cannot instantiate '" & dc.name.s & "'")
else: else:
result = c.semGenerateInstance(c, dc, m.bindings, info) result = c.semGenerateInstance(c, dc, m.bindings, info)
assert sfFromGeneric in result.flags assert sfFromGeneric in result.flags

View file

@ -0,0 +1,24 @@
discard """
output: "wow2"
"""
type
First[T] = ref object of RootObj
value: T
Second[T] = ref object of First[T]
value2: T
method wow[T](y: int; x: First[T]) {.base.} =
echo "wow1"
method wow[T](y: int; x: Second[T]) =
echo "wow2"
var
x: Second[int]
new(x)
proc takeFirst(x: First[int]) =
wow(2, x)
takeFirst(x)

View file

@ -4,27 +4,27 @@ discard """
# Test multi methods # Test multi methods
type type
TThing = object {.inheritable.} Thing = object {.inheritable.}
TUnit[T] = object of TThing Unit[T] = object of Thing
x: T x: T
TParticle = object of TThing Particle = object of Thing
a, b: int a, b: int
method collide(a, b: TThing) {.base, inline.} = method collide(a, b: Thing) {.base, inline.} =
quit "to override!" quit "to override!"
method collide[T](a: TThing, b: TUnit[T]) {.inline.} = method collide[T](a: Thing, b: Unit[T]) {.inline.} =
write stdout, "collide: thing, unit | " write stdout, "collide: thing, unit | "
method collide[T](a: TUnit[T], b: TThing) {.inline.} = method collide[T](a: Unit[T], b: Thing) {.inline.} =
write stdout, "collide: unit, thing | " write stdout, "collide: unit, thing | "
proc test(a, b: TThing) {.inline.} = proc test(a, b: Thing) {.inline.} =
collide(a, b) collide(a, b)
var var
a: TThing a: Thing
b, c: TUnit[string] b, c: Unit[string]
collide(b, TThing(c)) collide(b, Thing(c))
test(b, c) test(b, c)
collide(a, b) collide(a, b)

View file

@ -2,7 +2,6 @@ version 1.0 battle plan
======================= =======================
- Deprecate ``immediate`` for templates and macros - Deprecate ``immediate`` for templates and macros
- fix generic multi-methods
- fix "high priority" bugs - fix "high priority" bugs
- try to fix as many compiler crashes as reasonable - try to fix as many compiler crashes as reasonable