Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

generic type instance contains RecWhen, causing internal errors during code generation #9678

Closed
mratsim opened this issue Nov 10, 2018 · 5 comments

Comments

@mratsim
Copy link
Collaborator

mratsim commented Nov 10, 2018

Maybe related to #7378, another issue with when in type section, this time with generics.

Error is Error: illformed AST: result.my_enum when assigning
or internal error: (filename: "semobjconstr.nim", line: 242, column: 19) if constructing the object.

Solving the error requires either not using generics or not using when

type
  Foo*[T] = object                        # Remove generic to solve the issue
    bar*: int
    when defined(i386) or defined(amd64): # or Remove this to solve the issue
      my_enum: MyEnum

  MyEnum* = enum
    choice1,
    choice2

func fails_IllformedAST*(
      T: type,
      choice: MyEnum
    ): Foo[T] =
  result.my_enum = choice

func fails_ICE*(
      T: type,
      choice: MyEnum
    ): Foo[T] =
  Foo[T](bar: 1, my_enum: choice)

# let test1 = fails_IllformedAST(int, choice1) # Error: illformed AST: result.my_enum
let test2 = fails_ICE(int, choice1)            # Error: internal error: (filename: "semobjconstr.nim", line: 242, column: 19)


############################################
# The following works

# type
#   FooNoGeneric* = object                  # Remove generic to solve the issue
#     bar*: int
#     when defined(i386) or defined(amd64): # or Remove this to solve the issue
#       my_enum*: MyEnum

#   MyEnum* = enum
#     choice1,
#     choice2

# func works1*(
#       T: type,
#       choice: MyEnum
#     ): FooNoGeneric =
#   result.my_enum = choice

# func works2*(
#       T: type,
#       choice: MyEnum
#     ): FooNoGeneric =
#   FooNoGeneric(bar: 1, my_enum: choice)

# let test1_nogen = works1(int, choice1)
# let test2_nogen = works2(int, choice1)
@mratsim
Copy link
Collaborator Author

mratsim commented Nov 10, 2018

Dropping to low priority, we can "solve" the issue with a dummy field:

type
  Foo*[T] = object                        # Remove generic to solve the issue
    bar*: int
    dummy: T
    when defined(i386) or defined(amd64): # or Remove this to solve the issue
      my_enum: MyEnum

@krux02
Copy link
Contributor

krux02 commented Nov 12, 2018

type
  Foo*[T] = object                        # Remove generic to solve the issue
    bar*: int
    when defined(i386) or defined(amd64): # or Remove this to solve the issue
      my_enum: MyEnum

  MyEnum* = enum
    choice1,
    choice2

import macros

macro foobar(arg: typed): untyped =
  echo arg.getTypeImpl.treeRepr

var x : Foo[int]

foobar(x)

This still crashes during code generation pass. Aparently the when statement is not unrolled properly during gerenic expansion. This is the internal type AST.

ObjectTy
  Empty
  Empty
  RecList
    IdentDefs
      Sym "bar"
      Sym "int"
      Empty
    RecWhen
      ElifBranch
        IntLit 1
        IdentDefs
          Sym "my_enum"
          Sym "MyEnum"
          Empty

A generic instance should never contain a when statement.

@krux02 krux02 changed the title when + generics in type section: illformed AST on assignation or ICE on object construction generic type instance contains RecWhen, causing internal errors during code generation Nov 12, 2018
@mratsim
Copy link
Collaborator Author

mratsim commented Nov 13, 2018

Your last sentence is a bit ambiguous:
Do you mean "Once instantiated, the RecWhen should be 'resolved' and not appear in the AST" or do you mean "Generic types should not have when in a type section".

Note that when the fields exist in both when branches and are just merely reordered, there is no issue. The following type as been working daily since March: https://github.com/status-im/nim-stint/blob/edb1ade37309390cc641cee07ab62e5459d9ca44/stint/private/datatypes.nim#L141-L164

type
  # ### Private ### #
  UintImpl*[BaseUint] = object
    when system.cpuEndian == littleEndian:
      lo*, hi*: BaseUint
    else:
      hi*, lo*: BaseUint

  # ### Private ### #

  StUint*[bits: static[int]] = object
    data*: uintImpl(bits)

@krux02
Copy link
Contributor

krux02 commented Nov 15, 2018

I mean "Once instantiated, the RecWhen should be 'resolved' and not appear in the AST". It can and must be resolved during template instantiation. Any RecWhen that can't be resolved during template instantiation must be a compile error, because the correct set of members can't be figured out. Just think of it that a RecWhen would be allowed, every macro that accesses the type ast would be forced to special case for the RecWhen, almost every macro would do it initially wrong, because the developers won't be aware that this is a thing. And I can't imagine any benefit for it.

@LemonBoy
Copy link
Contributor

This has been fixed by #8748! 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants