lib/steep/interface/builder.rb in steep-1.8.0.dev.2 vs lib/steep/interface/builder.rb in steep-1.8.0.pre.1

- old
+ new

@@ -275,19 +275,18 @@ 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| 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 - ) + overloads = method.defs.map do |type_def| + method_name = method_name_for(type_def, name) + method_type = factory.method_type(type_def.type) + method_type = replace_primitive_method(method_name, type_def, method_type) + Shape::MethodOverload.new(method_type, [type_def]) + end + + shape.methods[name] = Interface::Shape::Entry.new(method_name: name, private_method: method.private?, overloads: overloads) end end shape end @@ -306,19 +305,18 @@ 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) - end - ) + overloads = method.defs.map do |type_def| + method_name = method_name_for(type_def, name) + method_type = factory.method_type(type_def.type) + method_type = replace_primitive_method(method_name, type_def, method_type) + Shape::MethodOverload.new(method_type, [type_def]) + end + + shape.methods[name] = Interface::Shape::Entry.new(method_name: name, private_method: method.private?, overloads: overloads) end end shape end @@ -332,55 +330,53 @@ 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]] + overloadss = [] #: Array[Array[Shape::MethodOverload]] private_method = false shapes.each do |shape| entry = shape.methods[method_name] || raise - method_typess << entry.method_types + overloadss << entry.overloads 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| + shape.methods[method_name] = Interface::Shape::Entry.new(method_name: method_name, private_method: private_method) do + overloadss.inject do |overloads1, overloads2| # @type break: nil + types1 = overloads1.map(&:method_type) + types2 = overloads2.map(&:method_type) + if types1 == types2 - decl_array1 = types1.map(&:method_decls) - decl_array2 = types2.map(&:method_decls) + defs1 = overloads1.flat_map(&:method_defs) + defs2 = overloads2.flat_map(&:method_defs) - if decl_array1 == decl_array2 - next types1 + if defs1 == defs2 + next overloads1 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] + method_overloads = {} #: Hash[Shape::MethodOverload, 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 + overloads1.each do |overload1| + overloads2.each do |overload2| + if overload1.method_type == overload2.method_type + overload = Shape::MethodOverload.new(overload1.method_type, overload1.method_defs + overload2.method_defs) + method_overloads[overload] = true else - if type = MethodType.union(type1, type2, subtyping) - method_types[type] = true + if type = MethodType.union(overload1.method_type, overload2.method_type, subtyping) + overload = Shape::MethodOverload.new(type, overload1.method_defs + overload2.method_defs) + method_overloads[overload] = true end end end end - break nil if method_types.empty? + break nil if method_overloads.empty? - method_types.keys + method_overloads.keys end end end shape @@ -425,91 +421,96 @@ def subtyping @subtyping ||= Subtyping::Check.new(builder: self) end def tuple_shape(tuple) - element_type = AST::Types::Union.build(types: tuple.types, location: nil) + element_type = AST::Types::Union.build(types: tuple.types) array_type = AST::Builtin::Array.instance_type(element_type) 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( + method_name: :[], 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)]), - return_type: elem_type, - location: nil + overloads: tuple.types.map.with_index {|elem_type, index| + Shape::MethodOverload.new( + MethodType.new( + type_params: [], + type: Function.new( + params: Function::Params.build(required: [AST::Types::Literal.new(value: index)]), + return_type: elem_type, + location: nil + ), + block: nil ), - block: nil, - method_decls: Set[] + [] ) - } + aref.method_types + } + aref.overloads ) end aref_update_entry = array_shape.methods[:[]=].yield_self do |update| raise unless update Shape::Entry.new( + method_name: :[]=, 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]), - return_type: elem_type, - location: nil + overloads: tuple.types.map.with_index {|elem_type, index| + Shape::MethodOverload.new( + MethodType.new( + type_params: [], + type: Function.new( + params: Function::Params.build(required: [AST::Types::Literal.new(value: index), elem_type]), + return_type: elem_type, + location: nil + ), + block: nil ), - block: nil, - method_decls: Set[] + [] ) - } + update.method_types + } + update.overloads ) end fetch_entry = array_shape.methods[:fetch].yield_self do |fetch| raise unless fetch Shape::Entry.new( + method_name: :fetch, private_method: false, - method_types: tuple.types.flat_map.with_index {|elem_type, index| + overloads: tuple.types.flat_map.with_index {|elem_type, index| [ MethodType.new( type_params: [], type: Function.new( params: Function::Params.build(required: [AST::Types::Literal.new(value: index)]), return_type: elem_type, location: nil ), - block: nil, - method_decls: Set[] + block: nil ), MethodType.new( - type_params: [TypeParam.new(name: :T, upper_bound: nil, variance: :invariant, unchecked: false)], + type_params: [TypeParam.new(name: :T, upper_bound: nil, variance: :invariant, unchecked: false, default_type: nil)], type: Function.new( params: Function::Params.build( required: [ AST::Types::Literal.new(value: index), AST::Types::Var.new(name: :T) ] ), return_type: AST::Types::Union.build(types: [elem_type, AST::Types::Var.new(name: :T)]), location: nil ), - block: nil, - method_decls: Set[] + block: nil ), MethodType.new( - type_params: [TypeParam.new(name: :T, upper_bound: nil, variance: :invariant, unchecked: false)], + type_params: [TypeParam.new(name: :T, upper_bound: nil, variance: :invariant, unchecked: false, default_type: nil)], type: Function.new( params: Function::Params.build(required: [AST::Types::Literal.new(value: index)]), return_type: AST::Types::Union.build(types: [elem_type, AST::Types::Var.new(name: :T)]), location: nil ), @@ -519,49 +520,54 @@ return_type: AST::Types::Var.new(name: :T), location: nil ), optional: false, self_type: nil - ), - method_decls: Set[] + ) ) - ] - } + fetch.method_types + ].map { Shape::MethodOverload.new(_1, []) } + } + fetch.overloads ) end first_entry = array_shape.methods[:first].yield_self do |first| Shape::Entry.new( + method_name: :first, private_method: false, - method_types: [ - MethodType.new( - type_params: [], - type: Function.new( - params: Function::Params.empty, - return_type: tuple.types[0] || AST::Builtin.nil_type, - location: nil + overloads: [ + Shape::MethodOverload.new( + MethodType.new( + type_params: [], + type: Function.new( + params: Function::Params.empty, + return_type: tuple.types[0] || AST::Builtin.nil_type, + location: nil + ), + block: nil ), - block: nil, - method_decls: Set[] + [] ) ] ) end last_entry = array_shape.methods[:last].yield_self do |last| Shape::Entry.new( + method_name: :last, private_method: false, - method_types: [ - MethodType.new( - type_params: [], - type: Function.new( - params: Function::Params.empty, - return_type: tuple.types.last || AST::Builtin.nil_type, - location: nil + overloads: [ + Shape::MethodOverload.new( + MethodType.new( + type_params: [], + type: Function.new( + params: Function::Params.empty, + return_type: tuple.types.last || AST::Builtin.nil_type, + location: nil + ), + block: nil ), - block: nil, - method_decls: Set[] + [] ) ] ) end @@ -574,92 +580,100 @@ shape end 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 + types: record.elements.each_key.map {|value| AST::Types::Literal.new(value: value) } ) - all_value_type = AST::Types::Union.build(types: record.elements.values, location: nil) + all_value_type = AST::Types::Union.build(types: record.elements.values) hash_type = AST::Builtin::Hash.instance_type(all_key_type, all_value_type) 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( + method_name: :[], private_method: false, - method_types: record.elements.map do |key_value, value_type| - key_type = AST::Types::Literal.new(value: key_value, location: nil) + overloads: record.elements.map do |key_value, value_type| + key_type = AST::Types::Literal.new(value: key_value) - MethodType.new( - type_params: [], - type: Function.new( - params: Function::Params.build(required: [key_type]), - return_type: value_type, - location: nil + if record.optional?(key_value) + value_type = AST::Builtin.optional(value_type) + end + + Shape::MethodOverload.new( + MethodType.new( + type_params: [], + type: Function.new( + params: Function::Params.build(required: [key_type]), + return_type: value_type, + location: nil + ), + block: nil ), - block: nil, - method_decls: Set[] + [] ) - end + aref.method_types + end + aref.overloads ) end shape.methods[:[]=] = hash_shape.methods[:[]=].yield_self do |update| update or raise Shape::Entry.new( + method_name: :[]=, 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( - params: Function::Params.build(required: [key_type, value_type]), - return_type: value_type, - location: nil), - block: nil, - method_decls: Set[] + overloads: record.elements.map do |key_value, value_type| + key_type = AST::Types::Literal.new(value: key_value) + Shape::MethodOverload.new( + MethodType.new( + type_params: [], + type: Function.new( + params: Function::Params.build(required: [key_type, value_type]), + return_type: value_type, + location: nil), + block: nil + ), + [] ) - end + update.method_types + end + update.overloads ) end shape.methods[:fetch] = hash_shape.methods[:fetch].yield_self do |update| update or raise Shape::Entry.new( + method_name: :fetch, private_method: false, - method_types: record.elements.flat_map {|key_value, value_type| - key_type = AST::Types::Literal.new(value: key_value, location: nil) + overloads: record.elements.flat_map {|key_value, value_type| + key_type = AST::Types::Literal.new(value: key_value) [ MethodType.new( type_params: [], type: Function.new( params: Function::Params.build(required: [key_type]), return_type: value_type, location: nil ), - block: nil, - method_decls: Set[] + block: nil ), MethodType.new( - type_params: [TypeParam.new(name: :T, upper_bound: nil, variance: :invariant, unchecked: false)], + type_params: [TypeParam.new(name: :T, upper_bound: nil, variance: :invariant, unchecked: false, default_type: nil)], type: Function.new( params: Function::Params.build(required: [key_type, AST::Types::Var.new(name: :T)]), return_type: AST::Types::Union.build(types: [value_type, AST::Types::Var.new(name: :T)]), location: nil ), - block: nil, - method_decls: Set[] + block: nil ), MethodType.new( - type_params: [TypeParam.new(name: :T, upper_bound: nil, variance: :invariant, unchecked: false)], + type_params: [TypeParam.new(name: :T, upper_bound: nil, variance: :invariant, unchecked: false, default_type: nil)], type: Function.new( params: Function::Params.build(required: [key_type]), return_type: AST::Types::Union.build(types: [value_type, AST::Types::Var.new(name: :T)]), location: nil ), @@ -669,29 +683,39 @@ return_type: AST::Types::Var.new(name: :T), location: nil ), optional: false, self_type: nil - ), - method_decls: Set[] + ) ) - ] - } + update.method_types + ].map { Shape::MethodOverload.new(_1, []) } + } + update.overloads ) end shape end 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( + overload = Shape::MethodOverload.new( + MethodType.new(type_params: [], type: proc.type, block: proc.block), + [] + ) + + shape.methods[:[]] = Shape::Entry.new( + method_name: :[], private_method: false, - method_types: [MethodType.new(type_params: [], type: proc.type, block: proc.block, method_decls: Set[])] + overloads: [overload] ) + shape.methods[:call] = Shape::Entry.new( + method_name: :call, + private_method: false, + overloads: [overload] + ) shape end def replace_primitive_method(method_name, method_def, method_type) @@ -705,11 +729,11 @@ when RBS::BuiltinNames::Object.name, RBS::BuiltinNames::Kernel.name if member.instance? return method_type.with( type: method_type.type.with( - return_type: AST::Types::Logic::ReceiverIsArg.new(location: method_type.type.return_type.location) + return_type: AST::Types::Logic::ReceiverIsArg.instance() ) ) end end @@ -719,11 +743,11 @@ AST::Builtin::NilClass.module_name, RBS::BuiltinNames::Kernel.name if member.instance? return method_type.with( type: method_type.type.with( - return_type: AST::Types::Logic::ReceiverIsNil.new(location: method_type.type.return_type.location) + return_type: AST::Types::Logic::ReceiverIsNil.instance() ) ) end end @@ -733,21 +757,21 @@ RBS::BuiltinNames::TrueClass.name, RBS::BuiltinNames::FalseClass.name, AST::Builtin::NilClass.module_name return method_type.with( type: method_type.type.with( - return_type: AST::Types::Logic::Not.new(location: method_type.type.return_type.location) + return_type: AST::Types::Logic::Not.instance() ) ) end when :=== case defined_in when RBS::BuiltinNames::Module.name return method_type.with( type: method_type.type.with( - return_type: AST::Types::Logic::ArgIsReceiver.new(location: method_type.type.return_type.location) + return_type: AST::Types::Logic::ArgIsReceiver.instance() ) ) when RBS::BuiltinNames::Object.name, RBS::BuiltinNames::Kernel.name, RBS::BuiltinNames::String.name, @@ -757,19 +781,19 @@ RBS::BuiltinNames::FalseClass.name, TypeName("::NilClass") # Value based type-case works on literal types which is available for String, Integer, Symbol, TrueClass, FalseClass, and NilClass return method_type.with( type: method_type.type.with( - return_type: AST::Types::Logic::ArgEqualsReceiver.new(location: method_type.type.return_type.location) + return_type: AST::Types::Logic::ArgEqualsReceiver.instance() ) ) end when :<, :<= case defined_in when RBS::BuiltinNames::Module.name return method_type.with( type: method_type.type.with( - return_type: AST::Types::Logic::ArgIsAncestor.new(location: method_type.type.return_type.location) + return_type: AST::Types::Logic::ArgIsAncestor.instance() ) ) end end end