class Steep::Interface::MethodType
def &(other)
Returns nil if self and other are incompatible.
(self & other) <: self && (self & other) <: other
Returns a method type which is a sub-type of both self and other.
def &(other) if other.type_params.empty? type_params = self.type_params else other_params, s2 = TypeParam.rename(other.type_params) other = other.instantiate(s2) type_params = self.type_params + other_params end params = self.type.params | other.type.params block = case when self.block && other.block block_params = self.block.type.params & other.block.type.params or return block_return_type = AST::Types::Union.build(types: [self.block.type.return_type, other.block.type.return_type]) block_type = Function.new(params: block_params, return_type: block_return_type, location: nil) Block.new( type: block_type, optional: self.block.optional || other.block.optional ) else self.block || other.block end return_type = AST::Types::Intersection.build(types: [self.type.return_type, other.type.return_type]) MethodType.new( type_params: type_params, type: Function.new(params: params, return_type: return_type, location: nil), block: block, method_decls: method_decls + other.method_decls ) end
def +(other)
def +(other) unify_overload(other) end
def ==(other)
def ==(other) other.is_a?(self.class) && other.type_params == type_params && other.type == type && other.block == block end
def each_type(&block)
def each_type(&block) if block_given? type.each_type(&block) self.block&.tap do self.block.type.params.each_type(&block) yield(self.block.type.return_type) end else enum_for :each_type end end
def free_variables
def free_variables @fvs ||= Set.new.tap do |set| set.merge(type.free_variables) if block set.merge(block.free_variables) end set.subtract(type_params) end end
def hash
def hash type_params.hash ^ type.hash ^ block.hash end
def initialize(type_params:, type:, block:, method_decls:)
def initialize(type_params:, type:, block:, method_decls:) @type_params = type_params @type = type @block = block @method_decls = method_decls end
def instantiate(s)
def instantiate(s) self.class.new(type_params: [], type: type.subst(s), block: block&.subst(s), method_decls: method_decls) end
def map_type(&block)
def map_type(&block) self.class.new(type_params: type_params, type: type.map_type(&block), block: self.block&.yield_self {|blk| blk.map_type(&block) }, method_decls: method_decls) end
def subst(s)
def subst(s) return self if s.empty? return self if free_variables.disjoint?(s.domain) s_ = s.except(type_params) self.class.new( type_params: type_params, type: type.subst(s_), block: block&.subst(s_), method_decls: method_decls ) end
def to_s
def to_s type_params = !self.type_params.empty? ? "[#{self.type_params.join(", ")}] " : "" params = type.params.to_s return_type = type.return_type block = self.block ? " #{self.block}" : "" "#{type_params}#{params}#{block} -> #{return_type}" end
def unify_overload(other)
Returns a new method type which can be used for the method implementation type of both `self` and `other`.
def unify_overload(other) type_params_1, s1 = TypeParam.rename(self.type_params) type_params_2, s2 = TypeParam.rename(other.type_params) type_params = type_params_1 + type_params_2 block = case when self.block && other.block self.block.subst(s1) + other.block.subst(s2) when self.block self.block.to_optional.subst(s1) when other.block other.block.to_optional.subst(s2) end self.class.new( type_params: type_params, type: Function.new( params: type.params.subst(s1) + other.type.params.subst(s2), return_type: AST::Types::Union.build( types: [type.return_type.subst(s1), other.type.return_type.subst(s2)] ), location: nil ), block: block, method_decls: method_decls + other.method_decls ) end
def with(type_params: self.type_params, type: self.type, block: self.block, method_decls: self.method_decls)
def with(type_params: self.type_params, type: self.type, block: self.block, method_decls: self.method_decls) self.class.new(type_params: type_params, type: type, block: block, method_decls: method_decls) end
def |(other)
Returns nil if self and other are incompatible.
self <: (self | other) && other <: (self | other)
Returns a method type which is a super-type of both self and other.
def |(other) if other.type_params.empty? type_params = self.type_params else other_params, s2 = TypeParam.rename(other.type_params) other = other.instantiate(s2) type_params = self.type_params + other_params end params = self.type.params & other.type.params or return block = case when self.block && other.block block_params = self.block.type.params | other.block.type.params block_return_type = AST::Types::Intersection.build(types: [self.block.type.return_type, other.block.type.return_type]) block_type = Function.new(params: block_params, return_type: block_return_type, location: nil) Block.new( type: block_type, optional: self.block.optional && other.block.optional ) when self.block && self.block.optional? self.block when other.block && other.block.optional? other.block when !self.block && !other.block nil else return end return_type = AST::Types::Union.build(types: [self.type.return_type, other.type.return_type]) MethodType.new( type_params: type_params, type: Function.new(params: params, return_type: return_type, location: nil), block: block, method_decls: method_decls + other.method_decls ) end