Type parameter is not correctly inferred for private inner class?

class Parent(T)
  private class Node(T)
    @child : Node(T) | Nil

    property :child

    def initialize(@child)

  def initialize
    node = Node(T).new(nil)
    node.child = node


With crystal 1.7.2, this results in compilation error.

$ crystal build temp.cr
Showing last frame. Use --error-trace for full trace.

In temp.cr:13:18

 13 | node.child = node
Error: expected argument #1 to 'Parent::Node(Int32)#child=' to be ::Nil | Parent::Node(T), not Parent::Node(Int32)

Overloads are:
 - Parent::Node(T)#child=(child : ::Nil | Parent::Node(T))

If I remove private from Node class, the compilation succeeds.

Is this a bug, or documented behavior?

It also seems to work if you do property child : Node(T) | Nil instead of:

@child : Node(T) | Nil

property :child

So i’d say that’s unexpected? Maybe it’s messing up the type so the compiler thinks node isn’t actually Node(T) or something along those lines.

Yeah, this very much looks like unintended behaviour, i.e. a bug.
Could you report it in the issue tracker, please? https://github.com/crystal-lang/crystal/issues/new