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