lib/steep/interface/builder.rb in steep-1.7.0.dev.2 vs lib/steep/interface/builder.rb in steep-1.7.0.dev.3
- old
+ new
@@ -1,350 +1,309 @@
module Steep
module Interface
class Builder
class Config
attr_reader :self_type, :class_type, :instance_type, :variable_bounds
- attr_reader :resolve_self, :resolve_instance, :resolve_class
- def initialize(self_type:, class_type:, instance_type:, resolve_self: true, resolve_class: true, resolve_instance: true, variable_bounds:)
+ def initialize(self_type:, class_type: nil, instance_type: nil, variable_bounds:)
@self_type = self_type
@class_type = class_type
@instance_type = instance_type
- @resolve_self = resolve_self
- @resolve_class = resolve_class
- @resolve_instance = resolve_instance
@variable_bounds = variable_bounds
- end
- def update(self_type: self.self_type, class_type: self.class_type, instance_type: self.instance_type, resolve_self: self.resolve_self, resolve_class: self.resolve_class, resolve_instance: self.resolve_instance, variable_bounds: self.variable_bounds)
- _ = self.class.new(
- self_type: self_type,
- class_type: class_type,
- instance_type: instance_type,
- resolve_self: resolve_self,
- resolve_class: resolve_class,
- resolve_instance: resolve_instance,
- variable_bounds: variable_bounds
- )
+ validate
end
- def no_resolve
- if resolve?
- @no_resolve ||= update(resolve_self: false, resolve_class: false, resolve_instance: false)
- else
- self
- end
+ def self.empty
+ new(self_type: nil, variable_bounds: {})
end
- def resolve?
- resolve_self || resolve_class || resolve_instance
- end
-
- def ==(other)
- other.is_a?(Config) &&
- other.self_type == self_type &&
- other.class_type == class_type &&
- other.instance_type == instance_type &&
- other.resolve_self == resolve_self &&
- other.resolve_class == resolve_class &&
- other.resolve_instance == resolve_instance &&
- other.variable_bounds == variable_bounds
- end
-
- alias eql? ==
-
- def hash
- self_type.hash ^ class_type.hash ^ instance_type.hash ^ resolve_self.hash ^ resolve_class.hash ^ resolve_instance.hash ^ variable_bounds.hash
- end
-
def subst
- @subst ||= begin
- Substitution.build(
- [],
- [],
- self_type: self_type,
- module_type: class_type || AST::Types::Class.instance,
- instance_type: instance_type || AST::Types::Instance.instance
- )
+ if self_type || class_type || instance_type
+ Substitution.build([], [], self_type: self_type, module_type: class_type, instance_type: instance_type)
end
end
- def self_type?
- unless self_type.is_a?(AST::Types::Self)
- self_type
- end
+ def validate
+ validate_fvs(:self_type, self_type)
+ validate_fvs(:instance_type, instance_type)
+ validate_fvs(:class_type, class_type)
+ self
end
- def instance_type?
- unless instance_type.is_a?(AST::Types::Instance)
- instance_type
+ def validate_fvs(name, type)
+ if type
+ fvs = type.free_variables
+ if fvs.include?(AST::Types::Self.instance)
+ raise "#{name} cannot include 'self' type: #{type}"
+ end
+ if fvs.include?(AST::Types::Instance.instance)
+ raise "#{name} cannot include 'instance' type: #{type}"
+ end
+ if fvs.include?(AST::Types::Class.instance)
+ raise "#{name} cannot include 'class' type: #{type}"
+ end
end
end
- def class_type?
- unless class_type.is_a?(AST::Types::Class)
- class_type
- end
+ def upper_bound(a)
+ variable_bounds.fetch(a, nil)
end
end
- attr_reader :factory, :cache, :raw_object_cache
- attr_reader :raw_instance_object_shape_cache, :raw_singleton_object_shape_cache, :raw_interface_object_shape_cache
+ attr_reader :factory, :object_shape_cache, :union_shape_cache, :singleton_shape_cache
def initialize(factory)
@factory = factory
- @cache = {}
- @raw_instance_object_shape_cache = {}
- @raw_singleton_object_shape_cache = {}
- @raw_interface_object_shape_cache = {}
+ @object_shape_cache = {}
+ @union_shape_cache = {}
+ @singleton_shape_cache = {}
end
- def include_self?(type)
- case type
- when AST::Types::Self, AST::Types::Instance, AST::Types::Class
- true
- else
- type.each_child.any? {|t| include_self?(t) }
+ def shape(type, config)
+ Steep.logger.tagged "shape(#{type})" do
+ if shape = raw_shape(type, config)
+ if type.free_variables.include?(AST::Types::Self.instance)
+ shape
+ else
+ if s = config.subst
+ shape.subst(s)
+ else
+ shape
+ end
+ end
+ end
end
end
- def fetch_cache(type, public_only, config)
- has_self = include_self?(type)
- fvs = type.free_variables
-
- # @type var key: cache_key
- key = [
- type,
- public_only,
- has_self ? config.self_type : nil,
- has_self ? config.class_type : nil,
- has_self ? config.instance_type : nil,
- config.resolve_self,
- config.resolve_class,
- config.resolve_instance,
- if config.variable_bounds.each_key.any? {|var| fvs.include?(var)}
- config.variable_bounds.select {|var, _| fvs.include?(var) }
- else
- nil
- end
- ]
-
+ def fetch_cache(cache, key)
if cache.key?(key)
- cache[key]
- else
- cache[key] = yield
+ return cache.fetch(key)
end
+
+ cache[key] = yield
end
- def shape(type, public_only:, config:)
- fetch_cache(type, public_only, config) do
- case type
- when AST::Types::Self
- if self_type = config.self_type?
- self_type = self_type.subst(config.subst)
- shape(self_type, public_only: public_only, config: config.update(resolve_self: false))
+ def raw_shape(type, config)
+ case type
+ when AST::Types::Self
+ self_type = config.self_type or raise
+ self_shape(self_type, config)
+ when AST::Types::Instance
+ instance_type = config.instance_type or raise
+ raw_shape(instance_type, config)
+ when AST::Types::Class
+ klass_type = config.class_type or raise
+ raw_shape(klass_type, config)
+ when AST::Types::Name::Singleton
+ singleton_shape(type.name).subst(class_subst(type))
+ when AST::Types::Name::Instance
+ object_shape(type.name).subst(class_subst(type).merge(app_subst(type)), type: type)
+ when AST::Types::Name::Interface
+ object_shape(type.name).subst(interface_subst(type).merge(app_subst(type)), type: type)
+ when AST::Types::Union
+ groups = type.types.group_by do |type|
+ if type.is_a?(AST::Types::Literal)
+ type.back_type
+ else
+ nil
end
- when AST::Types::Instance
- if instance_type = config.instance_type?
- instance_type = instance_type.subst(config.subst)
- shape(instance_type, public_only: public_only, config: config.update(resolve_instance: false))
- end
- when AST::Types::Class
- if class_type = config.class_type?
- class_type = class_type.subst(config.subst)
- shape(class_type, public_only: public_only, config: config.update(resolve_class: false))
- end
- when AST::Types::Name::Instance, AST::Types::Name::Interface, AST::Types::Name::Singleton
- object_shape(
- type.subst(config.subst),
- public_only,
- !config.resolve_self,
- !config.resolve_instance,
- !config.resolve_class
- )
- when AST::Types::Name::Alias
- if expanded = factory.deep_expand_alias(type)
- shape(expanded, public_only: public_only, config: config)&.update(type: type)
- end
- when AST::Types::Any, AST::Types::Bot, AST::Types::Void, AST::Types::Top
- nil
- when AST::Types::Var
- if bound = config.variable_bounds[type.name]
- shape(bound, public_only: public_only, config: config)&.update(type: type)
- end
- when AST::Types::Union
- if include_self?(type)
- self_var = AST::Types::Var.fresh(:SELF)
- class_var = AST::Types::Var.fresh(:CLASS)
- instance_var = AST::Types::Var.fresh(:INSTANCE)
+ end
- bounds = config.variable_bounds.merge({ self_var.name => config.self_type, instance_var.name => config.instance_type, class_var.name => config.class_type })
- type_ = type.subst(Substitution.build([], [], self_type: self_var, instance_type: instance_var, module_type: class_var)) #: AST::Types::Union
-
- config_ = config.update(resolve_self: false, resolve_class: true, resolve_instance: true, variable_bounds: bounds)
-
- shapes = type_.types.map do |type|
- shape(type, public_only: public_only, config: config_) or return
- end
-
- if shape = union_shape(type, shapes, public_only)
- shape.subst(
- Substitution.build(
- [self_var.name, class_var.name, instance_var.name],
- [AST::Types::Self.instance, AST::Types::Class.instance, AST::Types::Instance.instance],
- self_type: type,
- instance_type: AST::Builtin.any_type,
- module_type: AST::Builtin.any_type
- ),
- type: type.subst(config.subst)
- )
- end
+ shapes = [] #: Array[Shape]
+ groups.each do |name, types|
+ if name
+ union = AST::Types::Union.build(types: types)
+ subst = class_subst(name).update(self_type: union)
+ shapes << object_shape(name.name).subst(subst, type: union)
else
- config_ = config.update(resolve_self: false)
-
- shapes = type.types.map do |type|
- shape(type, public_only: public_only, config: config_) or return
- end
-
- if shape = union_shape(type, shapes, public_only)
- shape.subst(
- Substitution.build(
- [], [],
- self_type: type,
- instance_type: AST::Builtin.any_type,
- module_type: AST::Builtin.any_type
- )
- )
- end
+ shapes.concat(types.map {|ty| raw_shape(ty, config) or return })
end
- when AST::Types::Intersection
- self_var = AST::Types::Var.fresh(:SELF)
- class_var = AST::Types::Var.fresh(:CLASS)
- instance_var = AST::Types::Var.fresh(:INSTANCE)
+ end
- bounds = config.variable_bounds.merge({ self_var.name => config.self_type, instance_var.name => config.instance_type, class_var.name => config.class_type })
- type_ = type.subst(Substitution.build([], [], self_type: self_var, instance_type: instance_var, module_type: class_var)) #: AST::Types::Intersection
-
- config_ = config.update(resolve_self: false, resolve_class: true, resolve_instance: true, variable_bounds: bounds)
-
- shapes = type_.types.map do |type|
- shape(type, public_only: public_only, config: config_) or return
- end
-
- if shape = intersection_shape(type, shapes, public_only)
- shape.subst(
- Substitution.build(
- [self_var.name, class_var.name, instance_var.name],
- [AST::Types::Self.instance, AST::Types::Class.instance, AST::Types::Instance.instance],
- self_type: type,
- instance_type: AST::Builtin.any_type,
- module_type: AST::Builtin.any_type
- ),
- type: type.subst(config.subst)
- )
- end
-
- when AST::Types::Tuple
- tuple_shape(type, public_only, config)
- when AST::Types::Record
- record_shape(type, public_only, config)
- when AST::Types::Literal
- if shape = shape(type.back_type, public_only: public_only, config: config.update(resolve_self: false))
- shape.subst(Substitution.build([], [], self_type: type), type: type)
- end
- when AST::Types::Boolean, AST::Types::Logic::Base
- shape = union_shape(
- type,
- [
- object_shape(AST::Builtin::TrueClass.instance_type, public_only, true, true, true),
- object_shape(AST::Builtin::FalseClass.instance_type, public_only, true, true, true)
- ],
- public_only
+ fetch_cache(union_shape_cache, type) do
+ union_shape(type, shapes)
+ end
+ when AST::Types::Intersection
+ shapes = type.types.map do |type|
+ raw_shape(type, config) or return
+ end
+ intersection_shape(type, shapes)
+ when AST::Types::Name::Alias
+ expanded = factory.expand_alias(type)
+ if shape = raw_shape(expanded, config)
+ shape.update(type: type)
+ end
+ when AST::Types::Literal
+ instance_type = type.back_type
+ subst = class_subst(instance_type).update(self_type: type)
+ object_shape(instance_type.name).subst(subst, type: type)
+ when AST::Types::Boolean
+ true_shape =
+ (object_shape(RBS::BuiltinNames::TrueClass.name)).
+ subst(class_subst(AST::Builtin::TrueClass.instance_type).update(self_type: type))
+ false_shape =
+ (object_shape(RBS::BuiltinNames::FalseClass.name)).
+ subst(class_subst(AST::Builtin::FalseClass.instance_type).update(self_type: type))
+ union_shape(type, [true_shape, false_shape])
+ when AST::Types::Proc
+ shape = object_shape(AST::Builtin::Proc.module_name).subst(class_subst(AST::Builtin::Proc.instance_type).update(self_type: type))
+ proc_shape(type, shape)
+ when AST::Types::Tuple
+ tuple_shape(type) do |array|
+ object_shape(array.name).subst(
+ class_subst(array).update(self_type: type).merge(app_subst(array))
)
-
- if shape
- shape.subst(Substitution.build([], [], self_type: type))
- end
- when AST::Types::Nil
- if shape = object_shape(AST::Builtin::NilClass.instance_type, public_only, true, !config.resolve_instance, !config.resolve_class)
- if config.resolve_self
- shape.subst(Substitution.build([], [], self_type: type), type: type)
- else
- shape.update(type: type)
- end
- end
- when AST::Types::Proc
- proc_shape(type, public_only, config)
- else
- raise "Unknown type is given: #{type}"
end
+ when AST::Types::Record
+ record_shape(type) do |hash|
+ object_shape(hash.name).subst(
+ class_subst(hash).update(self_type: type).merge(app_subst(hash))
+ )
+ end
+ when AST::Types::Var
+ if bound = config.upper_bound(type.name)
+ new_config = Config.new(self_type: bound, variable_bounds: config.variable_bounds)
+ sub = Substitution.build([], self_type: type)
+ # We have to use `self_shape` insead of `raw_shape` here.
+ # Keep the `self` types included in the `bound`'s shape, and replace it to the type variable.
+ self_shape(bound, new_config)&.subst(sub, type: type)
+ end
+ when AST::Types::Nil
+ subst = class_subst(AST::Builtin::NilClass.instance_type).update(self_type: type)
+ object_shape(AST::Builtin::NilClass.module_name).subst(subst, type: type)
+ when AST::Types::Logic::Base
+ true_shape =
+ (object_shape(RBS::BuiltinNames::TrueClass.name)).
+ subst(class_subst(AST::Builtin::TrueClass.instance_type).update(self_type: type))
+ false_shape =
+ (object_shape(RBS::BuiltinNames::FalseClass.name)).
+ subst(class_subst(AST::Builtin::FalseClass.instance_type).update(self_type: type))
+ union_shape(type, [true_shape, false_shape])
+ else
+ nil
end
end
- def definition_builder
- factory.definition_builder
- end
-
- def object_shape(type, public_only, keep_self, keep_instance, keep_singleton)
+ def self_shape(type, config)
case type
+ when AST::Types::Self, AST::Types::Instance, AST::Types::Class
+ raise
+ when AST::Types::Name::Singleton
+ singleton_shape(type.name).subst(class_subst(type).update(self_type: nil))
when AST::Types::Name::Instance
- definition = definition_builder.build_instance(type.name)
- subst = Interface::Substitution.build(
- definition.type_params,
- type.args,
- self_type: keep_self ? AST::Types::Self.instance : type,
- module_type: keep_singleton ? AST::Types::Class.instance : AST::Types::Name::Singleton.new(name: type.name),
- instance_type: keep_instance ? AST::Types::Instance.instance : factory.instance_type(type.name)
- )
+ object_shape(type.name)
+ .subst(
+ class_subst(type).update(self_type: nil).merge(app_subst(type)),
+ type: type
+ )
when AST::Types::Name::Interface
- definition = definition_builder.build_interface(type.name)
- subst = Interface::Substitution.build(
- definition.type_params,
- type.args,
- self_type: keep_self ? AST::Types::Self.instance : type
- )
- when AST::Types::Name::Singleton
- subst = Interface::Substitution.build(
- [],
- [],
- self_type: keep_self ? AST::Types::Self.instance : type,
- module_type: keep_singleton ? AST::Types::Class.instance : AST::Types::Name::Singleton.new(name: type.name),
- instance_type: keep_instance ? AST::Types::Instance.instance : factory.instance_type(type.name)
- )
+ object_shape(type.name).subst(app_subst(type), type: type)
+ when AST::Types::Literal
+ instance_type = type.back_type
+ subst = class_subst(instance_type).update(self_type: nil)
+ object_shape(instance_type.name).subst(subst, type: type)
+ when AST::Types::Boolean
+ true_shape =
+ (object_shape(RBS::BuiltinNames::TrueClass.name)).
+ subst(class_subst(AST::Builtin::TrueClass.instance_type).update(self_type: nil))
+ false_shape =
+ (object_shape(RBS::BuiltinNames::FalseClass.name)).
+ subst(class_subst(AST::Builtin::FalseClass.instance_type).update(self_type: nil))
+ union_shape(type, [true_shape, false_shape])
+ when AST::Types::Proc
+ shape = object_shape(AST::Builtin::Proc.module_name).subst(class_subst(AST::Builtin::Proc.instance_type).update(self_type: nil))
+ proc_shape(type, shape)
+ when AST::Types::Var
+ if bound = config.upper_bound(type.name)
+ self_shape(bound, config)&.update(type: type)
+ end
+ else
+ raw_shape(type, config)
end
-
- raw_object_shape(type, public_only, subst)
end
- def raw_object_shape(type, public_only, subst)
- cache =
+ def app_subst(type)
+ if type.args.empty?
+ return Substitution.empty
+ end
+
+ vars =
case type
when AST::Types::Name::Instance
- raw_instance_object_shape_cache
+ entry = factory.env.normalized_module_class_entry(type.name) or raise
+ entry.primary.decl.type_params.map { _1.name }
when AST::Types::Name::Interface
- raw_interface_object_shape_cache
- when AST::Types::Name::Singleton
- raw_singleton_object_shape_cache
+ entry = factory.env.interface_decls.fetch(type.name)
+ entry.decl.type_params.map { _1.name }
+ when AST::Types::Name::Alias
+ entry = factory.env.type_alias_decls.fetch(type.name)
+ entry.decl.type_params.map { _1.name }
end
- raw_shape = cache[[type.name, public_only]] ||= begin
- shape = Interface::Shape.new(type: AST::Builtin.bottom_type, private: !public_only)
+ Substitution.build(vars, type.args)
+ end
- case type
- when AST::Types::Name::Instance
- definition = definition_builder.build_instance(type.name)
- when AST::Types::Name::Interface
- definition = definition_builder.build_interface(type.name)
- when AST::Types::Name::Singleton
- definition = definition_builder.build_singleton(type.name)
- end
+ def class_subst(type)
+ case type
+ when AST::Types::Name::Singleton
+ self_type = type
+ singleton_type = type
+ instance_type = factory.instance_type(type.name)
+ when AST::Types::Name::Instance
+ self_type = type
+ singleton_type = type.to_module
+ instance_type = factory.instance_type(type.name)
+ end
+ Substitution.build([], self_type: self_type, module_type: singleton_type, instance_type: instance_type)
+ end
+
+ def interface_subst(type)
+ Substitution.build([], self_type: type)
+ end
+
+ def singleton_shape(type_name)
+ singleton_shape_cache[type_name] ||= begin
+ shape = Interface::Shape.new(type: AST::Types::Name::Singleton.new(name: type_name), private: true)
+ definition = factory.definition_builder.build_singleton(type_name)
+
definition.methods.each do |name, method|
- next if method.private? && public_only
+ Steep.logger.tagged "method = #{type_name}.#{name}" do
+ shape.methods[name] = Interface::Shape::Entry.new(
+ private_method: method.private?,
+ method_types: method.defs.map do |type_def|
+ method_name = method_name_for(type_def, name)
+ decl = TypeInference::MethodCall::MethodDecl.new(method_name: method_name, method_def: type_def)
+ method_type = factory.method_type(type_def.type, method_decls: Set[decl])
+ replace_primitive_method(method_name, type_def, method_type)
+ end
+ )
+ end
+ end
- Steep.logger.tagged "method = #{type}##{name}" do
+ shape
+ end
+ end
+
+ def object_shape(type_name)
+ object_shape_cache[type_name] ||= begin
+ shape = Interface::Shape.new(type: AST::Builtin.bottom_type, private: true)
+
+ case
+ when type_name.class?
+ definition = factory.definition_builder.build_instance(type_name)
+ when type_name.interface?
+ definition = factory.definition_builder.build_interface(type_name)
+ end
+
+ definition or raise
+
+ definition.methods.each do |name, method|
+ Steep.logger.tagged "method = #{type_name}##{name}" do
shape.methods[name] = Interface::Shape::Entry.new(
+ private_method: method.private?,
method_types: method.defs.map do |type_def|
method_name = method_name_for(type_def, name)
decl = TypeInference::MethodCall::MethodDecl.new(method_name: method_name, method_def: type_def)
method_type = factory.method_type(type_def.type, method_decls: Set[decl])
replace_primitive_method(method_name, type_def, method_type)
@@ -353,14 +312,90 @@
end
end
shape
end
+ end
- raw_shape.subst(subst, type: type)
+ def union_shape(shape_type, shapes)
+ s0, *sx = shapes
+ s0 or raise
+ all_common_methods = Set.new(s0.methods.each_name)
+ sx.each do |shape|
+ all_common_methods &= shape.methods.each_name
+ end
+
+ shape = Interface::Shape.new(type: shape_type, private: true)
+ all_common_methods.each do |method_name|
+ method_typess = [] #: Array[Array[MethodType]]
+ private_method = false
+ shapes.each do |shape|
+ entry = shape.methods[method_name] || raise
+ method_typess << entry.method_types
+ private_method ||= entry.private_method?
+ end
+
+ shape.methods[method_name] = Interface::Shape::Entry.new(private_method: private_method) do
+ method_typess.inject do |types1, types2|
+ # @type break: nil
+
+ if types1 == types2
+ decl_array1 = types1.map(&:method_decls)
+ decl_array2 = types2.map(&:method_decls)
+
+ if decl_array1 == decl_array2
+ next types1
+ end
+
+ decls1 = decl_array1.each.with_object(Set[]) {|array, decls| decls.merge(array) } #$ Set[TypeInference::MethodCall::MethodDecl]
+ decls2 = decl_array2.each.with_object(Set[]) {|array, decls| decls.merge(array) } #$ Set[TypeInference::MethodCall::MethodDecl]
+
+ if decls1 == decls2
+ next types1
+ end
+ end
+
+ method_types = {} #: Hash[MethodType, bool]
+
+ types1.each do |type1|
+ types2.each do |type2|
+ if type1 == type2
+ method_types[type1.with(method_decls: type1.method_decls + type2.method_decls)] = true
+ else
+ if type = MethodType.union(type1, type2, subtyping)
+ method_types[type] = true
+ end
+ end
+ end
+ end
+
+ break nil if method_types.empty?
+
+ method_types.keys
+ end
+ end
+ end
+
+ shape
end
+ def intersection_shape(type, shapes)
+ shape = Interface::Shape.new(type: type, private: true)
+
+ shapes.each do |s|
+ shape.methods.merge!(s.methods) do |name, old_entry, new_entry|
+ if old_entry.public_method? && new_entry.private_method?
+ old_entry
+ else
+ new_entry
+ end
+ end
+ end
+
+ shape
+ end
+
def method_name_for(type_def, name)
type_name = type_def.implemented_in || type_def.defined_in
if name == :new && type_def.member.is_a?(RBS::AST::Members::MethodDefinition) && type_def.member.name == :initialize
return SingletonMethodName.new(type_name: type_name, method_name: name)
@@ -381,67 +416,23 @@
def subtyping
@subtyping ||= Subtyping::Check.new(builder: self)
end
- def union_shape(shape_type, shapes, public_only)
- shapes.inject do |shape1, shape2|
- Interface::Shape.new(type: shape_type, private: !public_only).tap do |shape|
- common_methods = Set.new(shape1.methods.each_name) & Set.new(shape2.methods.each_name)
- common_methods.each do |name|
- Steep.logger.tagged(name.to_s) do
- types1 = shape1.methods[name]&.method_types or raise
- types2 = shape2.methods[name]&.method_types or raise
-
- if types1 == types2 && types1.map {|type| type.method_decls.to_a }.to_set == types2.map {|type| type.method_decls.to_a }.to_set
- shape.methods[name] = (shape1.methods[name] or raise)
- else
- method_types = {} #: Hash[MethodType, true]
-
- types1.each do |type1|
- types2.each do |type2|
- if type1 == type2
- method_types[type1.with(method_decls: type1.method_decls + type2.method_decls)] = true
- else
- if type = MethodType.union(type1, type2, subtyping)
- method_types[type] = true
- end
- end
- end
- end
-
- unless method_types.empty?
- shape.methods[name] = Interface::Shape::Entry.new(method_types: method_types.keys)
- end
- end
- end
- end
- end
- end
- end
-
- def intersection_shape(type, shapes, public_only)
- shapes.inject do |shape1, shape2|
- Interface::Shape.new(type: type, private: !public_only).tap do |shape|
- shape.methods.merge!(shape1.methods)
- shape.methods.merge!(shape2.methods)
- end
- end
- end
-
- def tuple_shape(tuple, public_only, config)
+ def tuple_shape(tuple)
element_type = AST::Types::Union.build(types: tuple.types, location: nil)
array_type = AST::Builtin::Array.instance_type(element_type)
- array_shape = shape(array_type, public_only: public_only, config: config.no_resolve) or raise
- shape = Shape.new(type: tuple, private: !public_only)
+ array_shape = yield(array_type) or raise
+ shape = Shape.new(type: tuple, private: true)
shape.methods.merge!(array_shape.methods)
aref_entry = array_shape.methods[:[]].yield_self do |aref|
raise unless aref
Shape::Entry.new(
+ private_method: false,
method_types: tuple.types.map.with_index {|elem_type, index|
MethodType.new(
type_params: [],
type: Function.new(
params: Function::Params.build(required: [AST::Types::Literal.new(value: index)]),
@@ -457,10 +448,11 @@
aref_update_entry = array_shape.methods[:[]=].yield_self do |update|
raise unless update
Shape::Entry.new(
+ private_method: false,
method_types: tuple.types.map.with_index {|elem_type, index|
MethodType.new(
type_params: [],
type: Function.new(
params: Function::Params.build(required: [AST::Types::Literal.new(value: index), elem_type]),
@@ -476,10 +468,11 @@
fetch_entry = array_shape.methods[:fetch].yield_self do |fetch|
raise unless fetch
Shape::Entry.new(
+ private_method: false,
method_types: tuple.types.flat_map.with_index {|elem_type, index|
[
MethodType.new(
type_params: [],
type: Function.new(
@@ -528,10 +521,11 @@
)
end
first_entry = array_shape.methods[:first].yield_self do |first|
Shape::Entry.new(
+ private_method: false,
method_types: [
MethodType.new(
type_params: [],
type: Function.new(
params: Function::Params.empty,
@@ -545,10 +539,11 @@
)
end
last_entry = array_shape.methods[:last].yield_self do |last|
Shape::Entry.new(
+ private_method: false,
method_types: [
MethodType.new(
type_params: [],
type: Function.new(
params: Function::Params.empty,
@@ -566,35 +561,29 @@
shape.methods[:[]=] = aref_update_entry
shape.methods[:fetch] = fetch_entry
shape.methods[:first] = first_entry
shape.methods[:last] = last_entry
- shape.subst(
- Substitution.build(
- [], [],
- self_type: config.resolve_self ? tuple : AST::Types::Self.instance,
- instance_type: AST::Builtin::Array.instance_type(fill_untyped: true),
- module_type: AST::Builtin::Array.module_type
- )
- )
+ shape
end
- def record_shape(record, public_only, config)
+ def record_shape(record)
all_key_type = AST::Types::Union.build(
types: record.elements.each_key.map {|value| AST::Types::Literal.new(value: value, location: nil) },
location: nil
)
all_value_type = AST::Types::Union.build(types: record.elements.values, location: nil)
hash_type = AST::Builtin::Hash.instance_type(all_key_type, all_value_type)
- hash_shape = shape(hash_type, public_only: public_only, config: config.no_resolve) or raise
- shape = Shape.new(type: record, private: !public_only)
+ hash_shape = yield(hash_type) or raise
+ shape = Shape.new(type: record, private: true)
shape.methods.merge!(hash_shape.methods)
shape.methods[:[]] = hash_shape.methods[:[]].yield_self do |aref|
aref or raise
Shape::Entry.new(
+ private_method: false,
method_types: record.elements.map do |key_value, value_type|
key_type = AST::Types::Literal.new(value: key_value, location: nil)
MethodType.new(
type_params: [],
@@ -612,10 +601,11 @@
shape.methods[:[]=] = hash_shape.methods[:[]=].yield_self do |update|
update or raise
Shape::Entry.new(
+ private_method: false,
method_types: record.elements.map do |key_value, value_type|
key_type = AST::Types::Literal.new(value: key_value, location: nil)
MethodType.new(
type_params: [],
type: Function.new(
@@ -631,10 +621,11 @@
shape.methods[:fetch] = hash_shape.methods[:fetch].yield_self do |update|
update or raise
Shape::Entry.new(
+ private_method: false,
method_types: record.elements.flat_map {|key_value, value_type|
key_type = AST::Types::Literal.new(value: key_value, location: nil)
[
MethodType.new(
@@ -678,37 +669,22 @@
]
} + update.method_types
)
end
- shape.subst(
- Substitution.build(
- [], [],
- self_type: config.resolve_self ? record : AST::Types::Self.instance,
- instance_type: AST::Builtin::Hash.instance_type(fill_untyped: true),
- module_type: AST::Builtin::Hash.module_type
- )
- )
+ shape
end
- def proc_shape(proc, public_only, config)
- proc_shape = shape(AST::Builtin::Proc.instance_type, public_only: public_only, config: config.no_resolve) or raise
-
- shape = Shape.new(type: proc, private: !public_only)
+ def proc_shape(proc, proc_shape)
+ shape = Shape.new(type: proc, private: true)
shape.methods.merge!(proc_shape.methods)
shape.methods[:[]] = shape.methods[:call] = Shape::Entry.new(
+ private_method: false,
method_types: [MethodType.new(type_params: [], type: proc.type, block: proc.block, method_decls: Set[])]
)
- shape.subst(
- Substitution.build(
- [], [],
- self_type: config.resolve_self ? proc : AST::Types::Self.instance,
- instance_type: AST::Builtin::Proc.instance_type(fill_untyped: true),
- module_type: AST::Builtin::Proc.module_type
- )
- )
+ shape
end
def replace_primitive_method(method_name, method_def, method_type)
defined_in = method_def.defined_in
member = method_def.member