A compiler problem when I using generic. the code:
import sequtils, typetraits
type
Point = object
x,y: int
rseq[T] = ref object
inq: ref seq[T]
Vector[T] = rseq[T]
proc P(x, y: int): Point = Point(x: x, y: y)
proc `+`(p1, p2: Point): Point = P(p1.x+p2.x, p1.y+p2.y)
template init(x) =
when (x is rseq):
new(x); new(x.inq); x.inq[] = @[]
else:
x = @[]
proc `$`*[T](rq: rseq[T]): string = "rseq[" & ($rq.inq[])[2 .. ^2] & "]"
proc add*[T](rq: rseq[T], it: T) = rq.inq[].add(it)
proc len*[T](rq: rseq[T]): int = len(rq.inq[])
proc `[]`*[T](rq: rseq[T], i: int): T = rq.inq[][i]
proc `[]=`*[T](rq: rseq[T], i: int, it: T) = rq.inq[][i] = it
converter to_seq*[T](rq: rseq[T]): seq[T] = rq.inq[]
proc `@@`*[T](a: openArray[T]): rseq[T] =
init(result)
for x in a: result.add(x)
iterator items*[T](rq: rseq[T]): T {.inline.} =
var i = 0
let L = len(rq.inq[])
while i < L:
yield rq.inq[][i]
inc(i)
proc sum[T](v: Vector[T]): Point =
static: echo "In sum type of T is ", name(T)
foldl(v, a + b)
# Here is the problem
# The following code doesn't compile, because the compiler
# will treat the T is type rseq[Point] rather than Point
#
# But if I change the type of the vv to rseq[Vector[T]], everything
# is ok.
# Or if I change the type Vectors[T] to seq[Vector[T]], everything
# is ok too.
type Vectors[T] = rseq[Vector[T]]
proc core[T](vv: Vectors[T]): Vector[T] =
static: echo "In core type of vv is ", name(type(vv))
static: echo "In core type of T is ", name(T)
init(result)
for v in vv: result.add(sum(v))
when isMainModule:
let v1 = @@[P(1,2), P(3,4)]
let v2 = @@[P(4,5), P(6,7)]
let vv = @@[v1, v2]
let x = core(vv)
echo x
When compile this code, compiler say:
In core type of vv is Vectors[rseq[code1.Point]]
In core type of T is rseq[code1.Point]
In sum type of T is rseq[code1.Point]
code1.nim(61, 16) template/generic instantiation from here
code1.nim(55, 31) template/generic instantiation from here
code1.nim(40, 15) Error: type mismatch: got (rseq[code1.Point], rseq[code1.Point])
The compiler think the T of function core is rseq[Point], in fact, it should be Point.
When I change the type of Vectors[T] as:
type Vectors[T] = seq[Vector[T]]
The compiler seems works.
And if I change the function core define to:
proc core[T](vv: rseq[Vector[T]]): Vector[T] =
The compiler works too.
Is there something I do is wrong, or it's a bug of compiler?
Thanks for help.
There is simple version to show the problem.
import typetraits
type Foo[T] = ref object
x: T
proc `@@`*[T](a: T): Foo[T] = new(result); result.x = a
proc `$`*[T](f: Foo[T]): string = "Foo[" & $f.x & "]"
type Bar[T] = Foo[Foo[T]]
# OOPS
# Change the Bar[T] to Foo[Foo[T]] will make compiler happy
proc core[T](vv: Bar[T]): Foo[T] =
static: echo "In core type of vv is ", name(type(vv))
# OOPS
# Should be "int" rather than "Foo[system.int]"
static: echo "In core type of T is ", name(T)
new(result)
result.x = vv.x.x
when isMainModule:
let vv = @@(@@5)
static: echo "In main type of vv is ", name(type(vv))
# OOPS
# change to "let x = core[int](vv)" will make compiler happy
let x = core(vv)
echo x