@@ -177,21 +177,20 @@ def self.intersect?(a, b)
177177 def self . type_from_object ( object )
178178 case object
179179 when Array
180- InstanceType . new Array , { Elem : union_type_from_objects ( object ) }
180+ InstanceType . new Array , nil , [ object ]
181181 when Hash
182- InstanceType . new Hash , { K : union_type_from_objects ( object . keys ) , V : union_type_from_objects ( object . values ) }
182+ InstanceType . new Hash , nil , [ object ]
183183 when Module
184184 SingletonType . new object
185185 else
186- klass = Methods ::OBJECT_SINGLETON_CLASS_METHOD . bind_call ( object ) rescue Methods ::OBJECT_CLASS_METHOD . bind_call ( object )
187- InstanceType . new klass
186+ InstanceType . new Methods ::OBJECT_CLASS_METHOD . bind_call ( object ) , nil , [ object ]
188187 end
189188 end
190189
191190 def self . union_type_from_objects ( objects )
192- values = objects . size <= OBJECT_TO_TYPE_SAMPLE_SIZE ? objects : objects . sample ( OBJECT_TO_TYPE_SAMPLE_SIZE )
193- klasses = values . map { Methods ::OBJECT_CLASS_METHOD . bind_call ( _1 ) }
194- UnionType [ *klasses . uniq . map { InstanceType . new _1 } ]
191+ instanes = objects . size <= OBJECT_TO_TYPE_SAMPLE_SIZE ? objects : objects . sample ( OBJECT_TO_TYPE_SAMPLE_SIZE )
192+ class_instanes = instanes . group_by { Methods ::OBJECT_CLASS_METHOD . bind_call ( _1 ) }
193+ UnionType [ *class_instanes . map { InstanceType . new _1 , nil , _2 } ]
195194 end
196195
197196 class SingletonType
@@ -212,25 +211,67 @@ def inspect
212211 end
213212
214213 class InstanceType
215- attr_reader :klass , :params
216- def initialize ( klass , params = { } )
214+ attr_reader :klass , :raw_params , :instances
215+ def initialize ( klass , params = nil , instances = nil )
217216 @klass = klass
218- @params = params
217+ @raw_params = params if params && !params . empty?
218+ @instances = instances if instances && !instances . empty?
219219 end
220+
220221 def transform ( ) = yield ( self )
221- def methods ( ) = rbs_methods . select { _2 . public? } . keys | @klass . instance_methods
222- def all_methods ( ) = rbs_methods . keys | @klass . instance_methods | @klass . private_instance_methods
222+ def methods ( ) = rbs_methods . select { _2 . public? } . keys | @klass . instance_methods | singleton_methods
223+ def all_methods ( ) = rbs_methods . keys | @klass . instance_methods | @klass . private_instance_methods | singleton_methods | instances_private_methods
224+
225+ def singleton_methods
226+ return [ ] unless @instances
227+ @singleton_methods ||= @instances . map do |instance |
228+ Methods ::OBJECT_SINGLETON_METHODS_METHOD . bind_call ( instance )
229+ end . inject ( :| )
230+ end
231+
232+ def instances_private_methods
233+ return [ ] unless @instances
234+ @private_instances_methods ||= @instances . map do |instance |
235+ Methods ::OBJECT_PRIVATE_METHODS_METHOD . bind_call ( instance , false )
236+ end . inject ( :| )
237+ end
238+
239+ def params
240+ @params ||= expand_params
241+ end
242+
243+ def expand_params
244+ params = @raw_params || { }
245+ return params unless @instances
246+
247+ if @klass == Array
248+ type = Types . union_type_from_objects ( @instances . flatten ( 1 ) )
249+ { Elem : UnionType [ *params [ :Elem ] , *type ] }
250+ elsif @klass == Hash
251+ key = Types . union_type_from_objects ( @instances . map ( &:keys ) . flatten ( 1 ) )
252+ value = Types . union_type_from_objects ( @instances . map ( &:values ) . flatten ( 1 ) )
253+ {
254+ K : UnionType [ *params [ :K ] , key ] ,
255+ V : UnionType [ *params [ :V ] , value ]
256+ }
257+ else
258+ params
259+ end
260+ end
261+
223262 def constants ( ) = [ ]
224263 def types ( ) = [ self ]
225264 def nillable? ( ) = ( @klass == NilClass )
226265 def nonnillable ( ) = self
266+
227267 def rbs_methods
228268 return { } unless Types . rbs_builder
229269
230270 name = Types . class_name_of ( @klass )
231271 type_name = Types . rbs_absolute_type_name ( name )
232272 Types . rbs_builder . build_instance ( type_name ) . methods rescue { }
233273 end
274+
234275 def inspect
235276 if params . empty?
236277 inspect_without_params
@@ -239,6 +280,7 @@ def inspect
239280 "#{ inspect_without_params } #{ params_string } "
240281 end
241282 end
283+
242284 def inspect_without_params
243285 if klass == NilClass
244286 'nil'
@@ -247,7 +289,7 @@ def inspect_without_params
247289 elsif klass == FalseClass
248290 'false'
249291 else
250- klass . singleton_class? ? klass . superclass . to_s : klass . to_s
292+ klass . to_s
251293 end
252294 end
253295 end
@@ -275,24 +317,26 @@ class UnionType
275317
276318 def initialize ( *types )
277319 @types = [ ]
278- singletons = [ ]
279- instances = { }
320+ singleton_types = [ ]
321+ instance_types = { }
280322 collect = -> type do
281323 case type
282324 in UnionType
283325 type . types . each ( &collect )
284326 in InstanceType
285- params = ( instances [ type . klass ] ||= { } )
286- type . params . each do |k , v |
327+ params , instances = ( instance_types [ type . klass ] ||= [ { } , [ ] ] )
328+ type . instances &.each { instances << _1 }
329+ type . raw_params &.each do |k , v |
287330 ( params [ k ] ||= [ ] ) << v
288331 end
289332 in SingletonType
290- singletons << type
333+ singleton_types << type
291334 end
292335 end
293336 types . each ( &collect )
294- @types = singletons . uniq + instances . map do |klass , params |
295- InstanceType . new ( klass , params . transform_values { |v | UnionType [ *v ] } )
337+ @types = singleton_types . uniq + instance_types . map do |klass , ( params , instances ) |
338+ params = params . transform_values { |v | UnionType [ *v ] }
339+ InstanceType . new ( klass , params , instances )
296340 end
297341 end
298342
@@ -322,7 +366,7 @@ def self.[](*types)
322366 def methods ( ) = @types . flat_map ( &:methods ) . uniq
323367 def all_methods ( ) = @types . flat_map ( &:all_methods ) . uniq
324368 def constants ( ) = @types . flat_map ( &:constants ) . uniq
325- def inspect ( ) = @types . map ( &:inspect ) . join ( ' | ' )
369+ def inspect ( ) = @types . map ( &:inspect ) . sort . join ( ' | ' )
326370 end
327371
328372 BOOLEAN = UnionType [ TRUE , FALSE ]
0 commit comments