mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-19 22:10:33 +00:00
rework the vtable implementation embedding the vtable array directly with new strictions on methods (#22991)
**TODO** - [x] fixes changelog With the new option `nimPreviewVtables`, `methods` are confined in the same module where the type of the first parameter is defined - [x] make it opt in after CI checks its feasibility ## In the following-up PRs - [ ] in the following PRs, refactor code into a more efficient one - [ ] cpp needs special treatments since it cannot embed array in light of the preceding limits: ref https://github.com/nim-lang/Nim/pull/20977#discussion_r1035528927; we can support cpp backends with vtable implementations later on the comprise that uses indirect vtable access --------- Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
This commit is contained in:
@@ -1 +0,0 @@
|
||||
multimethods:on
|
||||
24
tests/method/tcompilegenerics.nim
Normal file
24
tests/method/tcompilegenerics.nim
Normal file
@@ -0,0 +1,24 @@
|
||||
discard """
|
||||
matrix: "--mm:arc; --mm:refc"
|
||||
output: '''
|
||||
newDNode base
|
||||
'''
|
||||
"""
|
||||
|
||||
type
|
||||
SNodeAny = ref object of RootObj
|
||||
SNode[T] = ref object of SNodeAny
|
||||
m: T
|
||||
DNode[T] = ref object
|
||||
|
||||
method getStr(s: SNode[float]): string {.base.} = "blahblah"
|
||||
|
||||
method newDNode(s: SNodeAny) {.base.} =
|
||||
echo "newDNode base"
|
||||
|
||||
method newDNode[T](s: SNode[T]) =
|
||||
echo "newDNode generic"
|
||||
|
||||
let m = SNode[float]()
|
||||
let s = SNodeAny(m)
|
||||
newDnode(s)
|
||||
@@ -1,42 +1,42 @@
|
||||
discard """
|
||||
matrix: "--mm:arc; --mm:refc"
|
||||
output: '''wow2
|
||||
X 1
|
||||
X 3'''
|
||||
"""
|
||||
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)
|
||||
|
||||
|
||||
# bug #5479
|
||||
type
|
||||
Base[T: static[int]] = ref object of RootObj
|
||||
|
||||
method test[T](t: Base[T]) {.base.} =
|
||||
echo "X ", t.T
|
||||
|
||||
let ab = Base[1]()
|
||||
|
||||
ab.test()
|
||||
|
||||
let ac = Base[3]()
|
||||
ac.test()
|
||||
discard """
|
||||
matrix: "--mm:arc --multimethods:on -u:nimPreviewVtables; --mm:refc --multimethods:on -u:nimPreviewVtables"
|
||||
output: '''wow2
|
||||
X 1
|
||||
X 3'''
|
||||
"""
|
||||
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)
|
||||
|
||||
|
||||
# bug #5479
|
||||
type
|
||||
Base[T: static[int]] = ref object of RootObj
|
||||
|
||||
method test[T](t: Base[T]) {.base.} =
|
||||
echo "X ", t.T
|
||||
|
||||
let ab = Base[1]()
|
||||
|
||||
ab.test()
|
||||
|
||||
let ac = Base[3]()
|
||||
ac.test()
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
discard """
|
||||
matrix: "--mm:arc; --mm:refc"
|
||||
output: '''
|
||||
do nothing
|
||||
HELLO WORLD!
|
||||
'''
|
||||
"""
|
||||
|
||||
|
||||
# tmethods1
|
||||
method somethin(obj: RootObj) {.base.} =
|
||||
echo "do nothing"
|
||||
|
||||
|
||||
type
|
||||
TNode* {.inheritable.} = object
|
||||
@@ -23,8 +20,6 @@ type
|
||||
method foo(a: PNode, b: PSomethingElse) {.base.} = discard
|
||||
method foo(a: PNodeFoo, b: PSomethingElse) = discard
|
||||
|
||||
var o: RootObj
|
||||
o.somethin()
|
||||
|
||||
|
||||
|
||||
|
||||
12
tests/method/tmethods_old.nim
Normal file
12
tests/method/tmethods_old.nim
Normal file
@@ -0,0 +1,12 @@
|
||||
discard """
|
||||
matrix: "--mm:arc -u:nimPreviewVtables"
|
||||
output: '''
|
||||
do nothing
|
||||
'''
|
||||
"""
|
||||
|
||||
# tmethods1
|
||||
method somethin(obj: RootObj) {.base.} =
|
||||
echo "do nothing"
|
||||
var o: RootObj
|
||||
o.somethin()
|
||||
@@ -1,96 +1,97 @@
|
||||
discard """
|
||||
output: '''
|
||||
collide: unit, thing
|
||||
collide: unit, thing
|
||||
collide: thing, unit
|
||||
collide: thing, thing
|
||||
collide: unit, thing |
|
||||
collide: unit, thing |
|
||||
collide: thing, unit |
|
||||
do nothing
|
||||
'''
|
||||
joinable: false
|
||||
disabled: true
|
||||
"""
|
||||
|
||||
|
||||
# tmultim2
|
||||
type
|
||||
TThing {.inheritable.} = object
|
||||
TUnit = object of TThing
|
||||
x: int
|
||||
TParticle = object of TThing
|
||||
a, b: int
|
||||
|
||||
method collide(a, b: TThing) {.base, inline.} =
|
||||
echo "collide: thing, thing"
|
||||
|
||||
method collide(a: TThing, b: TUnit) {.inline.} =
|
||||
echo "collide: thing, unit"
|
||||
|
||||
method collide(a: TUnit, b: TThing) {.inline.} =
|
||||
echo "collide: unit, thing"
|
||||
|
||||
proc test(a, b: TThing) {.inline.} =
|
||||
collide(a, b)
|
||||
|
||||
proc staticCollide(a, b: TThing) {.inline.} =
|
||||
procCall collide(a, b)
|
||||
|
||||
var
|
||||
a: TThing
|
||||
b, c: TUnit
|
||||
collide(b, c) # ambiguous (unit, thing) or (thing, unit)? -> prefer unit, thing!
|
||||
test(b, c)
|
||||
collide(a, b)
|
||||
staticCollide(a, b)
|
||||
|
||||
|
||||
|
||||
# tmultim6
|
||||
type
|
||||
Thing {.inheritable.} = object
|
||||
Unit[T] = object of Thing
|
||||
x: T
|
||||
Particle = object of Thing
|
||||
a, b: int
|
||||
|
||||
method collide(a, b: Thing) {.base, inline.} =
|
||||
quit "to override!"
|
||||
|
||||
method collide[T](a: Thing, b: Unit[T]) {.inline.} =
|
||||
echo "collide: thing, unit |"
|
||||
|
||||
method collide[T](a: Unit[T], b: Thing) {.inline.} =
|
||||
echo "collide: unit, thing |"
|
||||
|
||||
proc test(a, b: Thing) {.inline.} =
|
||||
collide(a, b)
|
||||
|
||||
var
|
||||
aaa: Thing
|
||||
bbb, ccc: Unit[string]
|
||||
collide(bbb, Thing(ccc))
|
||||
test(bbb, ccc)
|
||||
collide(aaa, bbb)
|
||||
|
||||
|
||||
|
||||
# tmethods1
|
||||
method somethin(obj: RootObj) {.base.} =
|
||||
echo "do nothing"
|
||||
|
||||
type
|
||||
TNode* {.inheritable.} = object
|
||||
PNode* = ref TNode
|
||||
|
||||
PNodeFoo* = ref object of TNode
|
||||
|
||||
TSomethingElse = object
|
||||
PSomethingElse = ref TSomethingElse
|
||||
|
||||
method foo(a: PNode, b: PSomethingElse) {.base.} = discard
|
||||
method foo(a: PNodeFoo, b: PSomethingElse) = discard
|
||||
|
||||
var o: RootObj
|
||||
o.somethin()
|
||||
discard """
|
||||
matrix: "--multimethods:on"
|
||||
output: '''
|
||||
collide: unit, thing
|
||||
collide: unit, thing
|
||||
collide: thing, unit
|
||||
collide: thing, thing
|
||||
collide: unit, thing |
|
||||
collide: unit, thing |
|
||||
collide: thing, unit |
|
||||
do nothing
|
||||
'''
|
||||
joinable: false
|
||||
disabled: true
|
||||
"""
|
||||
|
||||
|
||||
# tmultim2
|
||||
type
|
||||
TThing {.inheritable.} = object
|
||||
TUnit = object of TThing
|
||||
x: int
|
||||
TParticle = object of TThing
|
||||
a, b: int
|
||||
|
||||
method collide(a, b: TThing) {.base, inline.} =
|
||||
echo "collide: thing, thing"
|
||||
|
||||
method collide(a: TThing, b: TUnit) {.inline.} =
|
||||
echo "collide: thing, unit"
|
||||
|
||||
method collide(a: TUnit, b: TThing) {.inline.} =
|
||||
echo "collide: unit, thing"
|
||||
|
||||
proc test(a, b: TThing) {.inline.} =
|
||||
collide(a, b)
|
||||
|
||||
proc staticCollide(a, b: TThing) {.inline.} =
|
||||
procCall collide(a, b)
|
||||
|
||||
var
|
||||
a: TThing
|
||||
b, c: TUnit
|
||||
collide(b, c) # ambiguous (unit, thing) or (thing, unit)? -> prefer unit, thing!
|
||||
test(b, c)
|
||||
collide(a, b)
|
||||
staticCollide(a, b)
|
||||
|
||||
|
||||
|
||||
# tmultim6
|
||||
type
|
||||
Thing {.inheritable.} = object
|
||||
Unit[T] = object of Thing
|
||||
x: T
|
||||
Particle = object of Thing
|
||||
a, b: int
|
||||
|
||||
method collide(a, b: Thing) {.base, inline.} =
|
||||
quit "to override!"
|
||||
|
||||
method collide[T](a: Thing, b: Unit[T]) {.inline.} =
|
||||
echo "collide: thing, unit |"
|
||||
|
||||
method collide[T](a: Unit[T], b: Thing) {.inline.} =
|
||||
echo "collide: unit, thing |"
|
||||
|
||||
proc test(a, b: Thing) {.inline.} =
|
||||
collide(a, b)
|
||||
|
||||
var
|
||||
aaa: Thing
|
||||
bbb, ccc: Unit[string]
|
||||
collide(bbb, Thing(ccc))
|
||||
test(bbb, ccc)
|
||||
collide(aaa, bbb)
|
||||
|
||||
|
||||
|
||||
# tmethods1
|
||||
method somethin(obj: RootObj) {.base.} =
|
||||
echo "do nothing"
|
||||
|
||||
type
|
||||
TNode* {.inheritable.} = object
|
||||
PNode* = ref TNode
|
||||
|
||||
PNodeFoo* = ref object of TNode
|
||||
|
||||
TSomethingElse = object
|
||||
PSomethingElse = ref TSomethingElse
|
||||
|
||||
method foo(a: PNode, b: PSomethingElse) {.base.} = discard
|
||||
method foo(a: PNodeFoo, b: PSomethingElse) = discard
|
||||
|
||||
var o: RootObj
|
||||
o.somethin()
|
||||
|
||||
19
tests/method/tvtable.nim
Normal file
19
tests/method/tvtable.nim
Normal file
@@ -0,0 +1,19 @@
|
||||
type FooBase = ref object of RootObj
|
||||
dummy: int
|
||||
type Foo = ref object of FooBase
|
||||
value : float32
|
||||
type Foo2 = ref object of Foo
|
||||
change : float32
|
||||
method bar(x: FooBase, a: float32) {.base.} =
|
||||
discard
|
||||
method bar(x: Foo, a: float32) =
|
||||
x.value += a
|
||||
method bar(x: Foo2, a: float32) =
|
||||
x.value += a
|
||||
|
||||
|
||||
proc test() =
|
||||
var x = new Foo2
|
||||
x.bar(2.3)
|
||||
|
||||
test()
|
||||
Reference in New Issue
Block a user