lib/steep/type_inference/method_call.rb
module Steep
module TypeInference
module MethodCall
class MethodDecl
attr_reader :method_name
attr_reader :method_def
def initialize(method_name:, method_def:)
@method_name = method_name
@method_def = method_def
end
def hash
method_name.hash
end
def ==(other)
other.is_a?(MethodDecl) && other.method_name == method_name && other.method_def == method_def
end
alias eql? ==
def method_type
method_def.type
end
end
MethodContext = _ = Struct.new(:method_name, keyword_init: true) do
# @implements MethodContext
def to_s
"@#{method_name}"
end
end
ModuleContext = _ = Struct.new(:type_name, keyword_init: true) do
# @implements ModuleContext
def to_s
"@#{type_name}@"
end
end
TopLevelContext = _ = Class.new() do
def to_s
"@<main>"
end
def ==(other)
other.is_a?(TopLevelContext)
end
alias eql? ==
def hash
self.class.hash
end
end
UnknownContext = _ = Class.new() do
def to_s
"@<unknown>"
end
def ==(other)
other.is_a?(UnknownContext)
end
alias eql? ==
def hash
self.class.hash
end
end
class Base
attr_reader :node
attr_reader :context
attr_reader :method_name
attr_reader :return_type
attr_reader :receiver_type
def initialize(node:, context:, method_name:, receiver_type:, return_type:)
@node = node
@context = context
@method_name = method_name
@receiver_type = receiver_type
@return_type = return_type
end
def with_return_type(new_type)
dup.tap do |copy|
copy.instance_eval do
@return_type = new_type
end
end
end
def ==(other)
other.is_a?(Base) &&
other.node == node &&
other.context == context &&
other.method_name == method_name &&
other.return_type == return_type &&
other.receiver_type == receiver_type
end
alias eql? ==
def hash
node.hash ^ context.hash ^ method_name.hash ^ return_type.hash ^ receiver_type.hash
end
end
class Typed < Base
attr_reader :actual_method_type
attr_reader :method_decls
def initialize(node:, context:, method_name:, receiver_type:, actual_method_type:, method_decls:, return_type:)
super(node: node, context: context, method_name: method_name, receiver_type: receiver_type, return_type: return_type)
@actual_method_type = actual_method_type
@method_decls = method_decls
end
def pure?
method_decls.all? do |method_decl|
case member = method_decl.method_def.member
when RBS::AST::Members::MethodDefinition
member.annotations.any? {|annotation| annotation.string == "pure" }
when RBS::AST::Members::Attribute
# The attribute writer is not pure
!method_decl.method_name.method_name.end_with?("=")
end
end
end
def update(node: self.node, return_type: self.return_type)
_ = self.class.new(
node: node,
return_type: return_type,
context: context,
method_name: method_name,
receiver_type: receiver_type,
actual_method_type: actual_method_type,
method_decls: method_decls
)
end
def ==(other)
super &&
other.is_a?(Typed) &&
other.actual_method_type == actual_method_type &&
other.method_decls == method_decls
end
alias eql? ==
def hash
super ^ actual_method_type.hash ^ method_decls.hash
end
end
class Special < Typed
end
class Untyped < Base
def initialize(node:, context:, method_name:)
super(node: node, context: context, method_name: method_name, receiver_type: AST::Types::Any.new, return_type: AST::Types::Any.new)
end
end
class NoMethodError < Base
attr_reader :error
def initialize(node:, context:, method_name:, receiver_type:, error:)
super(node: node, context: context, method_name: method_name, receiver_type: receiver_type, return_type: AST::Types::Any.new)
@error = error
end
end
class Error < Base
attr_reader :errors
attr_reader :method_decls
def initialize(node:, context:, method_name:, receiver_type:, errors:, method_decls: Set[], return_type: AST::Types::Any.new)
super(node: node, context: context, method_name: method_name, receiver_type: receiver_type, return_type: return_type)
@method_decls = method_decls
@errors = errors
end
end
end
end
end