nim-lang / Nim

Nim is a statically typed compiled systems programming language. It combines successful concepts from mature languages like Python, Ada and Modula. Its design focuses on efficiency, expressiveness, and elegance (in that order of priority).
https://nim-lang.org
Other
16.62k stars 1.47k forks source link

recursive default call in type sections: invalid type in this context for proc #13048

Open mratsim opened 4 years ago

mratsim commented 4 years ago

The following doesn't compile

type
  Enqueueable* {.explain.} = concept x, type T
    x is ptr
    x.next is T

  Queue*[T: Enqueueable] = object
    count: int
    back: T
    front: typeof(default(T)[])

  Foo = ptr object
    next: Foo

  FooWrapper = ptr object
    next: FooWrapper
    foo: Foo
    bar: Bar

  Bar = ptr object
    queue: Queue[FooWrapper]

While I use concept here I think it's related to the nested default calls.

This builds up on the following issues:

mratsim commented 4 years ago

The following custom deref prevents the issue from happening:

macro deref*(T: typedesc): typedesc =
  echo T.getTypeInst.treerepr
  let instantiated = T.getTypeInst
  instantiated.expectkind(nnkBracketExpr)
  doAssert instantiated[0].eqIdent"typeDesc"

  let ptrT = instantiated[1]
  let ptrTImpl = instantiated[1].getImpl

  ptrTimpl.expectKind(nnkTypeDef)
  ptrTImpl[2].expectKind(nnkPtrTy)
  ptrTImpl[2][0].expectKind(nnkObjectTy)

  result = getType(ptrTImpl[2][0])

type
  Enqueueable* {.explain.} = concept x, type T
    x is ptr
    x.next is T

  Queue*[T: Enqueueable] = object
    count: int
    back: T
    front: deref(T)

  Foo = ptr object
    next: Foo

  FooWrapper = ptr object
    next: FooWrapper
    foo: Foo
    bar: Bar

  Bar = ptr object
    queue: Queue[FooWrapper]

var q: Queue[FooWrapper]
echo q
mratsim commented 4 years ago

But unfortunately, creating a pointer from the "deref"-ed type doesn't match the original

  type
    Task = ptr object
      prev, next: Task
      parent: Task
      fn: proc (param: pointer) {.nimcall.}
      # User data
      data: array[10, byte]

  var t = create(deref(Task))
  doAssert t is Task