Может ли сорбет обрабатывать частные определения initialize() при вызове с новым?

Я получаю сообщение об ошибке при вызове метода инициализации:

# typed: true
class A
  extend T::Sig

  sig {params(x: Integer).void}
  private def initialize(x)
  end
end

def main
  A.new(91)  
end

Вот результат шербета:

editor.rb:11: Non-private call to private method initialize on A https://srb.help/7031
11 |  A.new(91)  
      ^^^^^^^^^
editor.rb:6: Defined in A here
 6 |  private def initialize(x)
              ^^^^^^^^^^^^^^^^^
Errors: 1

https://sorbet.run/#%23%20typed%3A%20true%0Aclass%20A%0A%20%20extend%20T%3A%3ASig%%5B%E2%80%A6%5D0A%20%20end%0Aend%0A%0Adef%20main%0A%20%20A.new(91)%20%20%0Aend


person momoruby    schedule 22.12.2020    source источник


Ответы (1)


Это похоже на ошибку в Sorbet, так как initialize обрабатывается языком особым образом и, таким образом, всегда private по умолчанию в любом случае. Другими словами, ваш код на 100 % идентичен тому же коду без private:

# typed: true
class A
  extend T::Sig

  sig {params(x: Integer).void}
  def initialize(x)
  end
end

def main
  A.new(91)  
end

p A.private_instance_methods(false).include?(:initialize)
#=> true

Который успешно проходит проверку типов.

Я предполагаю, что Sorbet не знает о специальной обработке initialize в Ruby и поэтому рассматривает его как обычный метод. Мое второе предположение заключается в том, что Sorbet содержит определение Class#new, которое выглядит так:

class Class
  def new(...)
    obj = allocate
    obj.initialize(...)
    obj
  end
end

Это означает, что пока Sorbet думает, что initialize есть public, все в порядке, но как только он думает, что это private, он терпит неудачу.

Однако фактическая реализация Class#new выглядит примерно так:

class Class
  def new(...)
    obj = allocate
    obj.__send__(:initialize, ...)
    obj
  end
end

Если мои предположения верны, в Sorbet есть две ошибки, которые обычно компенсируют друг друга:

  • Определение Class#new неверно. Это означает, что вы всегда будете получать сообщение об ошибке, потому что initialize всегда равно private, за исключением
  • Видимость по умолчанию для initialize также неверна.

Однако я не проверял эти предположения, поэтому могу ошибаться.

person Jörg W Mittag    schedule 22.12.2020
comment
github.com/sorbet/sorbet/issues/3837 - person Jörg W Mittag; 22.12.2020
comment
Спасибо за подробное объяснение и открытие вопроса. - person momoruby; 23.12.2020