Компилятор Crystal не обнаруживает, что объект не ноль - PullRequest
0 голосов
/ 24 марта 2020

У меня есть следующий класс:

class X
    property son, val
    def initialize(@val : Int32)
        @son = nil.as X?
    end

    def add(other : X?)
        unless other.nil?
            if @son.nil?
                @son = other
            else
                @son.add(other)
            end
        end
    end
end

x = X.new 5
x.add(nil)
x.add(X.new 3)

Но когда я пытаюсь build, я получаю

Showing last frame. Use --error-trace for full trace.

In nil-test.cr:12:22

 12 | @son.add(other)
           ^------
Error: undefined method 'include' for Nil (compile-time type is (X | Nil))

Согласно инструкции , это именно такая ситуация, когда компилятор должен признать, что @son не может быть nil в ветви else, но, по-видимому, этого не происходит.

Что я делаю не так?

Примечание: использование @son.not_nil!.add(other) работает, я просто спрашиваю, почему без компилятора не обойтись.

1 Ответ

4 голосов
/ 25 марта 2020

Это работает только для локальных переменных, а не переменных экземпляра - поскольку переменные экземпляра могут быть изменены другим волокном между условием и доступом к переменной. См. этот раздел (в разделе «Ограничения») в документации Crystal.

Вы можете сделать это следующим образом, назначив переменную экземпляра локальной переменной, которая не изменится из-под вас:

def add(other : X?)
  unless other.nil?
    if s = @son
      s.add(other)
    else
      @son = other
    end
  end
end
...