generic multi-methods should work now
This commit is contained in:
parent
34afaeeedd
commit
f5fa5dae85
9 changed files with 67 additions and 21 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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) =
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
24
tests/method/tgeneric_methods.nim
Normal file
24
tests/method/tgeneric_methods.nim
Normal 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)
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
1
todo.txt
1
todo.txt
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue