-
Notifications
You must be signed in to change notification settings - Fork 565
Better detection of enumerable type from an instance #3358
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
Conversation
Your tests are failing because Probably the easiest way around this would be to add a case for Another trick would be to Either one (or something else) works for me. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change looks fine from me, but I'm surprised to hear that it's still a problem on latest versions of sorbet-runtime (i.e., after #3293).
@jez Thanks for the review, I'll make the relevant changes. I believe this is still a user-visible error in the latest released version of require "bundler/inline"
gemfile do
source 'https://rubygems.org'
gem "sorbet-runtime", "0.5.5866"
end
require "sorbet-runtime"
class Bar
include Enumerable
def each
yield "something"
end
end
class Foo
extend T::Sig
sig { returns(T::Array[String]) }
def self.foo
Bar.new
end
end
p Foo.foo with the output: $ ruby foo.rb
Traceback (most recent call last):
5: from foo.rb:27:in `<main>'
4: from /Users/ufuk/.gem/ruby/2.6.5/gems/sorbet-runtime-0.5.5866/lib/types/private/methods/_methods.rb:228:in `block in _on_method_added'
3: from /Users/ufuk/.gem/ruby/2.6.5/gems/sorbet-runtime-0.5.5866/lib/types/private/methods/call_validation.rb:138:in `validate_call'
2: from /Users/ufuk/.gem/ruby/2.6.5/gems/sorbet-runtime-0.5.5866/lib/types/private/methods/call_validation.rb:1125:in `report_error'
1: from /Users/ufuk/.gem/ruby/2.6.5/gems/sorbet-runtime-0.5.5866/lib/types/configuration.rb:226:in `call_validation_error_handler'
/Users/ufuk/.gem/ruby/2.6.5/gems/sorbet-runtime-0.5.5866/lib/types/configuration.rb:219:in `call_validation_error_handler_default': Return value: Expected type T::Array[String], got T::Array[String] (TypeError)
Caller: foo.rb:27
Definition: foo.rb:22 |
This is great, can you add this as a test case? |
When detecting the type of an enumerable from an instance, `TypedEnumerable` tries to match it to a couple of well-known enumerable classes (like `Array`, `Hash`, etc). The fallback case, however, tries to match it to the class of the type that the instance is being validated against, which does not make a lot sense. That behaviour means, if the instance is being compared against `T::Array[Foo]`, we would try to infer the type of the enumerable instance as a kind of `T::Array`. But, if it was being compared against a `T::Set[Foo]`, then the type of the instance would be inferred to be a `T::Set`. This leads to the problem outlined in sorbet#2808. In reality, Sorbet should not try to infer the type based on what type the instance is being compared against, but should return the type of the instance as is.
c7eb400
to
2bf0e64
Compare
@jez I made the changes we discussed above and pushed this branch. Specifically:
Please let me know if more changes are needed. Thanks |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
When detecting the type of an enumerable from an instance,
TypedEnumerable
tries to match it to a couple of well-known enumerable classes (likeArray
,Hash
, etc). The fallback case, however, tries to match it to the class of the type that the instance is being validated against, which does not make a lot sense.That behaviour means, if the instance is being compared against
T::Array[Foo]
, we would try to infer the type of the enumerable instance as a kind ofT::Array
. But, if it was being compared against aT::Set[Foo]
, then the type of the instance would be inferred to be aT::Set
. This leads to the problem outlined in #2808.In reality, Sorbet should not try to infer the type based on what type the instance is being compared against, but should return the type of the instance as is.
Motivation
Fixes: #2808
Test plan
See included automated tests.