···2233# @api private
44class Literal::Types::InterfaceType
55- # TODO: We can generate this and make it much more extensive.
66- METHOD_TYPE_MAPPINGS = {
77- :call => Set[Proc, Method],
88- :to_proc => Set[Proc, Method, Symbol],
99- :to_s => Set[String],
1010- }.freeze
55+ include Literal::Type
1161212- include Literal::Type
77+ # List of `===` method owners where the comparison will only match for objects with the same class
88+ OwnClassTypeMethodOwners = Set[String, Integer, Kernel, Float, NilClass, TrueClass, FalseClass].freeze
1391410 def initialize(*methods)
1511 raise Literal::ArgumentError.new("_Interface type must have at least one method.") if methods.size < 1
1616- @methods = methods
1212+ @methods = methods.to_set.freeze
1713 freeze
1814 end
1915···2420 end
25212622 def ===(value)
2727- @methods.all? { |m| value.respond_to?(m) }
2323+ @methods.each do |method|
2424+ return false unless value.respond_to?(method)
2525+ end
2626+2727+ true
2828 end
29293030 def >=(other)
3131 case other
3232 when Literal::Types::InterfaceType
3333- @methods.all? { |m| other.methods.include?(m) }
3333+ @methods.subset?(other.methods)
3434 when Module
3535- @methods.map { |m| METHOD_TYPE_MAPPINGS[m] }.all? { |types| types&.include?(other) }
3535+ public_methods = other.public_instance_methods.to_set
3636+ @methods.subset?(public_methods)
3637 when Literal::Types::IntersectionType
3738 other.types.any? { |type| Literal.subtype?(type, self) }
3839 when Literal::Types::ConstraintType
3940 other.object_constraints.any? { |type| Literal.subtype?(type, self) }
4041 else
4141- false
4242+ if OwnClassTypeMethodOwners.include?(other.method(:===).owner)
4343+ self === other
4444+ else
4545+ false
4646+ end
4247 end
4348 end
4449