From 32483269415070b16dbdb7233d53c600c6b7b30a Mon Sep 17 00:00:00 2001 From: Soutaro Matsumoto Date: Wed, 7 Aug 2024 09:28:29 +0900 Subject: [PATCH 1/5] Introduce `Shape::MethodOverload` Move `#method_decls` to `MethodOverload` from `MethodType` so that `Factory` can reuse `MethodType` objects. --- bin/stackprof_test.rb | 19 ++ bin/steep-check.rb | 13 + lib/steep.rb | 2 +- lib/steep/annotation_parser.rb | 2 +- lib/steep/ast/node/type_application.rb | 13 +- lib/steep/ast/types/factory.rb | 56 ++-- lib/steep/diagnostic/ruby.rb | 4 +- lib/steep/interface/builder.rb | 249 ++++++++++-------- lib/steep/interface/shape.rb | 74 +++++- lib/steep/located_value.rb | 20 ++ lib/steep/server/lsp_formatter.rb | 10 +- lib/steep/services/completion_provider.rb | 23 +- lib/steep/services/signature_help_provider.rb | 8 +- lib/steep/type_construction.rb | 60 +++-- sig/steep/ast/node/type_application.rbs | 4 +- sig/steep/ast/types/factory.rbs | 2 +- sig/steep/diagnostic/ruby.rbs | 2 +- sig/steep/interface/method_type.rbs | 2 +- sig/steep/interface/shape.rbs | 26 +- sig/steep/located_value.rbs | 15 ++ sig/steep/type_construction.rbs | 4 +- test/annotation_parsing_test.rb | 2 +- test/ast/node/type_application_test.rb | 6 +- test/test_helper.rb | 2 +- test/type_factory_test.rb | 24 +- test/validation_test.rb | 3 - 26 files changed, 410 insertions(+), 235 deletions(-) create mode 100644 bin/stackprof_test.rb create mode 100644 lib/steep/located_value.rb create mode 100644 sig/steep/located_value.rbs diff --git a/bin/stackprof_test.rb b/bin/stackprof_test.rb new file mode 100644 index 000000000..ee3020b07 --- /dev/null +++ b/bin/stackprof_test.rb @@ -0,0 +1,19 @@ +#!/usr/bin/env ruby + +require "stackprof" + +mode = (ENV["STEEP_STACKPROF_MODE"] || :cpu).to_sym +out = ENV["STEEP_STACKPROF_OUT"] || "tmp/stackprof-#{mode}-test.dump" +interval = ENV["STEEP_STACKPROF_INTERVAL"]&.to_i || 1000 + +STDERR.puts "Running profiler: mode => #{mode}, out => #{out}" +StackProf.run(mode: mode, out: out, raw: true, interval: interval) do + # 10.times do + # 1_000.times do + # Array.new(1_000_000) + # end + # sleep 0.1 + # end + + sleep 5 +end diff --git a/bin/steep-check.rb b/bin/steep-check.rb index cf8cf8639..8f6bf4313 100755 --- a/bin/steep-check.rb +++ b/bin/steep-check.rb @@ -229,8 +229,21 @@ def type_check_files(command_line_args, env) end when :none + + pp rbs_method_types: ObjectSpace.each_object(RBS::MethodType).count + GC.start(immediate_sweep: true, immediate_mark: true, full_mark: true) + + pp defs: ObjectSpace.each_object(RBS::AST::Members::MethodDefinition).count + pp aliases: ObjectSpace.each_object(RBS::AST::Members::Alias).count + pp attr_reader: ObjectSpace.each_object(RBS::AST::Members::AttrReader).count + pp attr_writer: ObjectSpace.each_object(RBS::AST::Members::AttrWriter).count + pp attr_accessor: ObjectSpace.each_object(RBS::AST::Members::AttrAccessor).count + Steep.measure("type check", level: :fatal) do + GC.disable typings = command.type_check_files(command_line_args, env) + + pp steep_method_types: ObjectSpace.each_object(Steep::Interface::MethodType).count, rbs_method_types: ObjectSpace.each_object(RBS::MethodType).count end end diff --git a/lib/steep.rb b/lib/steep.rb index 38fc693cc..83d9b350c 100644 --- a/lib/steep.rb +++ b/lib/steep.rb @@ -22,7 +22,7 @@ require "rbs" require "steep/path_helper" - +require "steep/located_value" require "steep/thread_waiter" require "steep/equatable" require "steep/method_name" diff --git a/lib/steep/annotation_parser.rb b/lib/steep/annotation_parser.rb index c3beb5cd0..042dfd1fe 100644 --- a/lib/steep/annotation_parser.rb +++ b/lib/steep/annotation_parser.rb @@ -91,7 +91,7 @@ def parse(src, location:) name = match[:name] or raise type = match[:type] or raise - method_type = factory.method_type(RBS::Parser.parse_method_type(type) || raise, method_decls: Set[]) + method_type = factory.method_type(RBS::Parser.parse_method_type(type) || raise) AST::Annotation::MethodType.new(name: name.to_sym, type: method_type, diff --git a/lib/steep/ast/node/type_application.rb b/lib/steep/ast/node/type_application.rb index a1c081e2f..64e0b2791 100644 --- a/lib/steep/ast/node/type_application.rb +++ b/lib/steep/ast/node/type_application.rb @@ -27,14 +27,15 @@ def source def types(context, subtyping, type_vars) resolver = RBS::Resolver::TypeNameResolver.new(subtyping.factory.env) - # @type var types: Array[Types::t] + # @type var types: Array[LocatedValue[Types::t]] types = [] loc = type_location while true - ty = RBS::Parser.parse_type(loc.buffer, range: loc.range, variables: type_vars) or break - ty = ty.map_type_name {|name| resolver.resolve(name, context: context) || name.absolute! } + rbs_ty = RBS::Parser.parse_type(loc.buffer, range: loc.range, variables: type_vars) or break + rbs_loc = rbs_ty.location or raise + ty = rbs_ty.map_type_name {|name| resolver.resolve(name, context: context) || name.absolute! } validator = Signature::Validator.new(checker: subtyping) validator.rescue_validation_errors do @@ -46,11 +47,11 @@ def types(context, subtyping, type_vars) end ty = subtyping.factory.type(ty) - types << ty + types << LocatedValue.new(value: ty, location: rbs_loc) - match = RBS::Location.new(loc.buffer, ty.location.end_pos, type_location.end_pos).source.match(/\A\s*,\s*/) or break + match = RBS::Location.new(loc.buffer, rbs_loc.end_pos, type_location.end_pos).source.match(/\A\s*,\s*/) or break offset = match.length - loc = RBS::Location.new(loc.buffer, ty.location.end_pos + offset, type_location.end_pos) + loc = RBS::Location.new(loc.buffer, rbs_loc.end_pos + offset, type_location.end_pos) end types diff --git a/lib/steep/ast/types/factory.rb b/lib/steep/ast/types/factory.rb index e4fcb144a..337514f72 100644 --- a/lib/steep/ast/types/factory.rb +++ b/lib/steep/ast/types/factory.rb @@ -37,76 +37,74 @@ def type_1_opt(type) end def type(type) - unless type.location - if ty = type_cache[type] - return ty - end + if ty = type_cache[type] + return ty end type_cache[type] = case type when RBS::Types::Bases::Any - Any.new(location: type.location) + Any.new(location: nil) when RBS::Types::Bases::Class - Class.new(location: type.location) + Class.new(location: nil) when RBS::Types::Bases::Instance - Instance.new(location: type.location) + Instance.new(location: nil) when RBS::Types::Bases::Self - Self.new(location: type.location) + Self.new(location: nil) when RBS::Types::Bases::Top - Top.new(location: type.location) + Top.new(location: nil) when RBS::Types::Bases::Bottom - Bot.new(location: type.location) + Bot.new(location: nil) when RBS::Types::Bases::Bool - Boolean.new(location: type.location) + Boolean.new(location: nil) when RBS::Types::Bases::Void - Void.new(location: type.location) + Void.new(location: nil) when RBS::Types::Bases::Nil - Nil.new(location: type.location) + Nil.new(location: nil) when RBS::Types::Variable - Var.new(name: type.name, location: type.location) + Var.new(name: type.name, location: nil) when RBS::Types::ClassSingleton type_name = type.name - Name::Singleton.new(name: type_name, location: type.location) + Name::Singleton.new(name: type_name, location: nil) when RBS::Types::ClassInstance type_name = type.name args = type.args.map {|arg| type(arg) } - Name::Instance.new(name: type_name, args: args, location: type.location) + Name::Instance.new(name: type_name, args: args, location: nil) when RBS::Types::Interface type_name = type.name args = type.args.map {|arg| type(arg) } - Name::Interface.new(name: type_name, args: args, location: type.location) + Name::Interface.new(name: type_name, args: args, location: nil) when RBS::Types::Alias type_name = type.name args = type.args.map {|arg| type(arg) } - Name::Alias.new(name: type_name, args: args, location: type.location) + Name::Alias.new(name: type_name, args: args, location: nil) when RBS::Types::Union - Union.build(types: type.types.map {|ty| type(ty) }, location: type.location) + Union.build(types: type.types.map {|ty| type(ty) }, location: nil) when RBS::Types::Intersection - Intersection.build(types: type.types.map {|ty| type(ty) }, location: type.location) + Intersection.build(types: type.types.map {|ty| type(ty) }, location: nil) when RBS::Types::Optional - Union.build(types: [type(type.type), Nil.new(location: nil)], location: type.location) + Union.build(types: [type(type.type), Nil.new(location: nil)], location: nil) when RBS::Types::Literal - Literal.new(value: type.literal, location: type.location) + Literal.new(value: type.literal, location: nil) when RBS::Types::Tuple - Tuple.new(types: type.types.map {|ty| type(ty) }, location: type.location) + Tuple.new(types: type.types.map {|ty| type(ty) }, location: nil) when RBS::Types::Record elements = type.fields.each.with_object({}) do |(key, value), hash| hash[key] = type(value) end - Record.new(elements: elements, location: type.location) + Record.new(elements: elements, location: nil) when RBS::Types::Proc func = Interface::Function.new( params: params(type.type), return_type: type(type.type.return_type), - location: type.location + location: nil ) block = if type.block Interface::Block.new( type: Interface::Function.new( params: params(type.block.type), return_type: type(type.block.type.return_type), - location: type.location + location: nil ), optional: !type.block.required, self_type: type_opt(type.block.self_type) @@ -269,8 +267,8 @@ def type_param_1(type_param) ).unchecked!(type_param.unchecked) end - def method_type(method_type, method_decls:) - mt = @method_type_cache[method_type] ||= + def method_type(method_type) + @method_type_cache[method_type] ||= Interface::MethodType.new( type_params: method_type.type_params.map {|param| type_param(param) }, type: Interface::Function.new( @@ -291,8 +289,6 @@ def method_type(method_type, method_decls:) end, method_decls: Set[] ) - - mt.with(method_decls: method_decls) end def method_type_1(method_type) diff --git a/lib/steep/diagnostic/ruby.rb b/lib/steep/diagnostic/ruby.rb index dce135b82..e7c9094dd 100644 --- a/lib/steep/diagnostic/ruby.rb +++ b/lib/steep/diagnostic/ruby.rb @@ -932,8 +932,8 @@ def header_line class TypeArgumentMismatchError < Base attr_reader :type_argument, :type_parameter, :result - def initialize(type_arg:, type_param:, result:) - super(node: nil, location: type_arg.location) + def initialize(type_arg:, type_param:, result:, location:) + super(node: nil, location: location) @type_argument = type_arg @type_parameter = type_param @result = result diff --git a/lib/steep/interface/builder.rb b/lib/steep/interface/builder.rb index 859332b33..5a7ace01e 100644 --- a/lib/steep/interface/builder.rb +++ b/lib/steep/interface/builder.rb @@ -277,15 +277,14 @@ def singleton_shape(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 @@ -308,15 +307,14 @@ def object_shape(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 @@ -334,51 +332,49 @@ def union_shape(shape_type, shapes) 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 - if types1 == types2 - decl_array1 = types1.map(&:method_decls) - decl_array2 = types2.map(&:method_decls) - - if decl_array1 == decl_array2 - next types1 - end + types1 = overloads1.map(&:method_type) + types2 = overloads2.map(&:method_type) - 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 types1 == types2 + defs1 = overloads1.flat_map(&:method_defs) + defs2 = overloads2.flat_map(&:method_defs) - if decls1 == decls2 - next types1 + if defs1 == defs2 + next overloads1 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 @@ -438,19 +434,23 @@ def tuple_shape(tuple) 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, + method_decls: Set[] ), - block: nil, - method_decls: Set[] + [] ) - } + aref.method_types + } + aref.overloads ) end @@ -458,19 +458,23 @@ def tuple_shape(tuple) 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, + method_decls: Set[] ), - block: nil, - method_decls: Set[] + [] ) - } + update.method_types + } + update.overloads ) end @@ -478,8 +482,9 @@ def tuple_shape(tuple) 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: [], @@ -524,24 +529,28 @@ def tuple_shape(tuple) ), 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, + method_decls: Set[] ), - block: nil, - method_decls: Set[] + [] ) ] ) @@ -549,17 +558,21 @@ def tuple_shape(tuple) 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, + method_decls: Set[] ), - block: nil, - method_decls: Set[] + [] ) ] ) @@ -589,21 +602,25 @@ def record_shape(record) 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| + overloads: 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]), - return_type: value_type, - location: nil + 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, + method_decls: Set[] ), - block: nil, - method_decls: Set[] + [] ) - end + aref.method_types + end + aref.overloads ) end @@ -611,19 +628,23 @@ def record_shape(record) update or raise Shape::Entry.new( + method_name: :[]=, private_method: false, - method_types: record.elements.map do |key_value, value_type| + overloads: 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[] + 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, + method_decls: Set[] + ), + [] ) - end + update.method_types + end + update.overloads ) end @@ -631,8 +652,9 @@ def record_shape(record) update or raise Shape::Entry.new( + method_name: :fetch, private_method: false, - method_types: record.elements.flat_map {|key_value, value_type| + overloads: record.elements.flat_map {|key_value, value_type| key_type = AST::Types::Literal.new(value: key_value, location: nil) [ @@ -674,8 +696,8 @@ def record_shape(record) ), method_decls: Set[] ) - ] - } + update.method_types + ].map { Shape::MethodOverload.new(_1, []) } + } + update.overloads ) end @@ -686,9 +708,20 @@ 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, method_decls: Set[]), + [] + ) + + shape.methods[:[]] = Shape::Entry.new( + method_name: :[], + private_method: false, + overloads: [overload] + ) + shape.methods[:call] = Shape::Entry.new( + method_name: :call, private_method: false, - method_types: [MethodType.new(type_params: [], type: proc.type, block: proc.block, method_decls: Set[])] + overloads: [overload] ) shape diff --git a/lib/steep/interface/shape.rb b/lib/steep/interface/shape.rb index 2c71174b2..c19077b12 100644 --- a/lib/steep/interface/shape.rb +++ b/lib/steep/interface/shape.rb @@ -1,28 +1,83 @@ module Steep module Interface class Shape + class MethodOverload + attr_reader :method_type + + attr_reader :method_defs + + def initialize(method_type, defs) + @method_type = method_type + @method_defs = defs.sort_by do |defn| + buf = +"" + + if loc = defn.type.location + buf << loc.buffer.name.to_s + buf << ":" + buf << loc.start_pos.to_s + end + + buf + end + @method_defs.uniq! + end + + def subst(s) + overload = MethodOverload.new(method_type.subst(s), []) + overload.method_defs.replace(method_defs) + overload + end + + def method_decls(name) + method_defs.map do |defn| + type_name = defn.implemented_in || defn.defined_in + + if name == :new && defn.member.is_a?(RBS::AST::Members::MethodDefinition) && defn.member.name == :initialize + method_name = SingletonMethodName.new(type_name: type_name, method_name: name) + else + method_name = + if defn.member.kind == :singleton + SingletonMethodName.new(type_name: defn.defined_in, method_name: name) + else + # Call the `self?` method an instance method, because the definition is done with instance method definition, not with singleton method + InstanceMethodName.new(type_name: defn.defined_in, method_name: name) + end + end + + TypeInference::MethodCall::MethodDecl.new(method_def: defn, method_name: method_name) + end + end + end + class Entry - def initialize(method_types: nil, private_method:, &block) - @method_types = method_types + attr_reader :method_name + + def initialize(overloads: nil, private_method:, method_name:, &block) + @overloads = overloads @generator = block @private_method = private_method + @method_name = method_name end def force - unless @method_types - @method_types = @generator&.call + unless @overloads + @overloads = @generator&.call @generator = nil end end - def method_types + def overloads force - @method_types or raise + @overloads or raise + end + + def method_types + overloads.map(&:method_type) end def has_method_type? force - @method_types ? true : false + @overloads ? true : false end def to_s @@ -72,8 +127,9 @@ def [](name) resolved_methods[name] ||= begin entry = methods[name] Entry.new( - method_types: entry.method_types.map do |method_type| - method_type.subst(subst) + method_name: name, + overloads: entry.overloads.map do |overload| + overload.subst(subst) end, private_method: entry.private_method? ) diff --git a/lib/steep/located_value.rb b/lib/steep/located_value.rb new file mode 100644 index 000000000..999a3ba5b --- /dev/null +++ b/lib/steep/located_value.rb @@ -0,0 +1,20 @@ +module Steep + class LocatedValue + attr_reader :value, :location + + def initialize(value:, location:) + @value = value + @location = location + end + + def ==(other) + other.is_a?(LocatedValue) && other.value == value + end + + alias eql? == + + def hash + value.hash # steep:ignore NoMethod + end + end +end diff --git a/lib/steep/server/lsp_formatter.rb b/lib/steep/server/lsp_formatter.rb index 2db2f6907..e1a68be70 100644 --- a/lib/steep/server/lsp_formatter.rb +++ b/lib/steep/server/lsp_formatter.rb @@ -36,7 +36,8 @@ def format_hover_content(content) ---- MD - method_types = call.method_decls.map(&:method_type) + method_decls = call.method_decls.sort_by {|decl| decl.method_name.to_s } + method_types = method_decls.map(&:method_type) if call.is_a?(TypeInference::MethodCall::Special) method_types = [ @@ -52,7 +53,8 @@ def format_hover_content(content) MD end when TypeInference::MethodCall::Error - method_types = call.method_decls.map {|decl| decl.method_type } + method_decls = call.method_decls.sort_by {|decl| decl.method_name.to_s } + method_types = method_decls.map {|decl| decl.method_type } header = <<~MD **🚨 No compatible method type found** @@ -61,8 +63,8 @@ def format_hover_content(content) MD end - method_names = call.method_decls.map {|decl| decl.method_name.relative } - docs = call.method_decls.map {|decl| [decl.method_name, decl.method_def.comment] }.to_h + method_names = method_decls.map {|decl| decl.method_name.relative } + docs = method_decls.map {|decl| [decl.method_name, decl.method_def.comment] }.to_h if header io.puts header diff --git a/lib/steep/services/completion_provider.rb b/lib/steep/services/completion_provider.rb index 624359b51..02dde7ccd 100644 --- a/lib/steep/services/completion_provider.rb +++ b/lib/steep/services/completion_provider.rb @@ -635,39 +635,40 @@ def method_items_for_receiver_type(type, include_private:, prefix:, position:, i case type when AST::Types::Name::Instance, AST::Types::Name::Interface, AST::Types::Name::Singleton # Simple method type - all_decls = Set.new(method_entry.method_types.flat_map {|method_type| method_type.method_decls.to_a }).sort_by {|decl| decl.method_name.to_s } + all_decls = Set.new(method_entry.overloads.flat_map {|overload| overload.method_decls(name) }).sort_by {|decl| decl.method_name.to_s } all_members = Set.new(all_decls.flat_map {|decl| decl.method_def.member }) all_members.each do |member| associated_decl = all_decls.find {|decl| decl.method_def.member == member } or next - method_types = method_entry.method_types.select {|method_type| method_type.method_decls.any? {|decl| decl.method_def.member == member }} + overloads = method_entry.overloads.select {|overload| overload.method_defs.any? {|defn| defn.member == member }} items << SimpleMethodNameItem.new( identifier: name, range: range, receiver_type: type, method_name: associated_decl.method_name, - method_types: method_types.map {|type| subtyping.factory.method_type_1(type) }, + method_types: overloads.map {|overload| subtyping.factory.method_type_1(overload.method_type) }, method_member: member ) end else - generated_method_types, defined_method_types = method_entry.method_types.partition {|method_type| method_type.method_decls.empty? } + generated_overloads, defined_overloads = + method_entry.overloads.partition {|overload| overload.method_defs.empty? } - unless defined_method_types.empty? + unless defined_overloads.empty? items << ComplexMethodNameItem.new( identifier: name, range: range, receiver_type: type, - method_types: defined_method_types.map {|type| subtyping.factory.method_type_1(type) }, - method_decls: defined_method_types.flat_map {|type| type.method_decls.to_a }.sort_by {|decl| decl.method_name.to_s } + method_types: defined_overloads.map { subtyping.factory.method_type_1(_1.method_type) }, + method_decls: defined_overloads.flat_map { _1.method_decls(name).to_a }.sort_by {|decl| decl.method_name.to_s } ) end - unless generated_method_types.empty? + unless generated_overloads.empty? items << GeneratedMethodNameItem.new( identifier: name, range: range, receiver_type: type, - method_types: generated_method_types.map {|type| subtyping.factory.method_type_1(type) } + method_types: generated_overloads.map { subtyping.factory.method_type_1(_1.method_type) } ) end end @@ -740,8 +741,8 @@ def keyword_argument_items_for_method(call_node:, send_node:, position:, prefix: if shape = subtyping.builder.shape(type, config) shape = shape.public_shape if private_send?(call_node) if method = shape.methods[call.method_name] - method.method_types.each.with_index do |method_type, i| - defn = method_type.method_decls.to_a[0]&.method_def + method.overloads.each.with_index do |overload, i| + defn = overload.method_decls(call.method_name).to_a[0]&.method_def if defn && defn.type.type range = range_for(position, prefix: prefix) kwargs = argument_nodes.find { |arg| arg.type == :kwargs }&.children || [] diff --git a/lib/steep/services/signature_help_provider.rb b/lib/steep/services/signature_help_provider.rb index cf55570cf..7ef3d4755 100644 --- a/lib/steep/services/signature_help_provider.rb +++ b/lib/steep/services/signature_help_provider.rb @@ -114,14 +114,14 @@ def signature_help_for(node, argument, last_argument, typing) shape = shape.public_shape if private_send?(node) if method = shape.methods[call.method_name] - method.method_types.each.with_index do |method_type, i| - defn = method_type.method_decls.to_a[0]&.method_def + method.overloads.each.with_index do |overload, i| + defn = overload.method_defs[0] active_parameter = active_parameter_for(defn&.type, argument, last_argument, node) - items << Item.new(subtyping.factory.method_type_1(method_type), defn&.comment, active_parameter) + items << Item.new(subtyping.factory.method_type_1(overload.method_type), defn&.comment, active_parameter) if call.is_a?(MethodCall::Typed) - if method_type.method_decls.intersect?(call.method_decls) + if call.method_decls.intersect?(overload.method_decls(call.method_name).to_set) index = i end end diff --git a/lib/steep/type_construction.rb b/lib/steep/type_construction.rb index c124cdb5a..593880b48 100644 --- a/lib/steep/type_construction.rb +++ b/lib/steep/type_construction.rb @@ -154,7 +154,7 @@ def for_new_method(method_name, node, args:, self_type:, definition:) definition_method_type = if definition definition.methods[method_name]&.yield_self do |method| method.method_types - .map {|method_type| checker.factory.method_type(method_type, method_decls: Set[]) } + .map {|method_type| checker.factory.method_type(method_type) } .select {|method_type| method_type.is_a?(Interface::MethodType) } .inject {|t1, t2| t1 + t2} end @@ -878,16 +878,11 @@ def synthesize(node, hint: nil, condition: false) if self_type && method_context!.method if super_def = method_context!.super_method super_method = Interface::Shape::Entry.new( + method_name: method_context!.name, private_method: true, - method_types: super_def.defs.map {|type_def| - decl = TypeInference::MethodCall::MethodDecl.new( - method_name: InstanceMethodName.new( - type_name: super_def.implemented_in || super_def.defined_in || raise, - method_name: method_context!.name || raise("method context must have a name") - ), - method_def: type_def - ) - checker.factory.method_type(type_def.type, method_decls: Set[decl]) + overloads: super_def.defs.map {|type_def| + type = checker.factory.method_type(type_def.type) + Interface::Shape::MethodOverload.new(type, [type_def]) } ) @@ -1511,7 +1506,7 @@ def synthesize(node, hint: nil, condition: false) constructor.synthesize(node.children[2]) if node.children[2] if constructor.module_context&.implement_name && !namespace_module?(node) - constructor.validate_method_definitions(node, constructor.module_context.implement_name) + constructor.validate_method_definitions(node, constructor.module_context.implement_name || raise) end end @@ -1550,7 +1545,7 @@ def synthesize(node, hint: nil, condition: false) constructor.synthesize(node.children[1]) if node.children[1] if constructor.module_context&.implement_name && !namespace_module?(node) - constructor.validate_method_definitions(node, constructor.module_context.implement_name) + constructor.validate_method_definitions(node, constructor.module_context.implement_name || raise) end end @@ -1683,7 +1678,7 @@ def synthesize(node, hint: nil, condition: false) if method_context && method_context.method if method_context.super_method types = method_context.super_method.method_types.map {|method_type| - checker.factory.method_type(method_type, method_decls: Set[]).type.return_type + checker.factory.method_type(method_type).type.return_type } add_typing(node, type: union_type(*types)) else @@ -3293,7 +3288,11 @@ def type_send_interface(node, interface:, receiver:, receiver_type:, method_name method_name: method_name, method_types: method.method_types ) - decls = method.method_types.each_with_object(Set[]) {|type, decls| decls.merge(type.method_decls) } + + decls = method.overloads.flat_map do |method_overload| + method_overload.method_decls(method_name) + end.to_set + call = TypeInference::MethodCall::Error.new( node: node, context: context.call_context, @@ -3497,8 +3496,9 @@ def expand_self(type) ] } - def try_special_method(node, receiver_type:, method_name:, method_type:, arguments:, block_params:, block_body:, hint:) - decls = method_type.method_decls + def try_special_method(node, receiver_type:, method_name:, method_overload:, arguments:, block_params:, block_body:, hint:) + method_type = method_overload.method_type + decls = method_overload.method_decls(method_name).to_set case when decl = decls.find {|decl| SPECIAL_METHOD_NAMES[:array_compact].include?(decl.method_name) } @@ -3574,8 +3574,8 @@ def type_method_call(node, method_name:, receiver_type:, method:, arguments:, bl # @type var fails: Array[[TypeInference::MethodCall::t, TypeConstruction]] fails = [] - method.method_types.each do |method_type| - Steep.logger.tagged method_type.to_s do + method.overloads.each do |overload| + Steep.logger.tagged overload.method_type.to_s do typing.new_child() do |child_typing| constr = self.with_new_typing(child_typing) @@ -3583,7 +3583,7 @@ def type_method_call(node, method_name:, receiver_type:, method:, arguments:, bl node, receiver_type: receiver_type, method_name: method_name, - method_type: method_type, + method_overload: overload, arguments: arguments, block_params: block_params, block_body: block_body, @@ -3592,7 +3592,7 @@ def type_method_call(node, method_name:, receiver_type:, method:, arguments:, bl node, receiver_type: receiver_type, method_name: method_name, - method_type: method_type, + method_overload: overload, arguments: arguments, block_params: block_params, block_body: block_body, @@ -3830,9 +3830,12 @@ def type_check_args(method_name, args, constraints, errors) constr end - def try_method_type(node, receiver_type:, method_name:, method_type:, arguments:, block_params:, block_body:, tapp:, hint:) + def try_method_type(node, receiver_type:, method_name:, method_overload:, arguments:, block_params:, block_body:, tapp:, hint:) constr = self + method_type = method_overload.method_type + decls = method_overload.method_decls(method_name).to_set + if tapp && type_args = tapp.types?(module_context.nesting, checker, []) type_arity = method_type.type_params.size type_param_names = method_type.type_params.map(&:name) @@ -3845,20 +3848,21 @@ def try_method_type(node, receiver_type:, method_name:, method_type:, arguments: type_args.each_with_index do |type, index| param = method_type.type_params[index] if param.upper_bound - if result = no_subtyping?(sub_type: type, super_type: param.upper_bound) + if result = no_subtyping?(sub_type: type.value, super_type: param.upper_bound) args_ << AST::Builtin.any_type constr.typing.add_error( Diagnostic::Ruby::TypeArgumentMismatchError.new( - type_arg: type, + type_arg: type.value, type_param: param, - result: result + result: result, + location: type.location ) ) else - args_ << type + args_ << type.value end else - args_ << type + args_ << type.value end end @@ -4276,7 +4280,7 @@ def try_method_type(node, receiver_type:, method_name:, method_type:, arguments: method_name: method_name, actual_method_type: method_type, return_type: return_type || method_type.type.return_type, - method_decls: method_type.method_decls + method_decls: decls ) else TypeInference::MethodCall::Error.new( @@ -4285,7 +4289,7 @@ def try_method_type(node, receiver_type:, method_name:, method_type:, arguments: receiver_type: receiver_type, method_name: method_name, return_type: return_type || method_type.type.return_type, - method_decls: method_type.method_decls, + method_decls: decls, errors: errors ) end diff --git a/sig/steep/ast/node/type_application.rbs b/sig/steep/ast/node/type_application.rbs index 0605a8d6b..36c83c5f0 100644 --- a/sig/steep/ast/node/type_application.rbs +++ b/sig/steep/ast/node/type_application.rbs @@ -12,9 +12,9 @@ module Steep def initialize: (RBS::Location[untyped, untyped]) -> void - def types: (RBS::Resolver::context, Subtyping::Check, Array[Symbol] type_vars) -> (Array[Types::t] | RBS::ParsingError | Enumerator[Diagnostic::Signature::Base, void] | nil) + def types: (RBS::Resolver::context, Subtyping::Check, Array[Symbol] type_vars) -> (Array[LocatedValue[Types::t]] | RBS::ParsingError | Enumerator[Diagnostic::Signature::Base, void] | nil) - def types?: (RBS::Resolver::context, Subtyping::Check, Array[Symbol] type_vars) -> Array[Types::t]? + def types?: (RBS::Resolver::context, Subtyping::Check, Array[Symbol] type_vars) -> Array[LocatedValue[Types::t]]? @type_str: String? def type_str: () -> String diff --git a/sig/steep/ast/types/factory.rbs b/sig/steep/ast/types/factory.rbs index 2804ce771..961cb4d92 100644 --- a/sig/steep/ast/types/factory.rbs +++ b/sig/steep/ast/types/factory.rbs @@ -38,7 +38,7 @@ module Steep @method_type_cache: Hash[RBS::MethodType, Interface::MethodType] - def method_type: (RBS::MethodType method_type, method_decls: Set[TypeInference::MethodCall::MethodDecl]) -> Interface::MethodType + def method_type: (RBS::MethodType method_type) -> Interface::MethodType def method_type_1: (Interface::MethodType method_type) -> RBS::MethodType diff --git a/sig/steep/diagnostic/ruby.rbs b/sig/steep/diagnostic/ruby.rbs index 476cc7606..af0dacdaf 100644 --- a/sig/steep/diagnostic/ruby.rbs +++ b/sig/steep/diagnostic/ruby.rbs @@ -604,7 +604,7 @@ module Steep def node: () -> nil - def initialize: (type_arg: AST::Types::t, type_param: Interface::TypeParam, result: Subtyping::Result::Base) -> void + def initialize: (type_arg: AST::Types::t, type_param: Interface::TypeParam, result: Subtyping::Result::Base, location: RBS::Location[untyped, untyped]) -> void def header_line: () -> String end diff --git a/sig/steep/interface/method_type.rbs b/sig/steep/interface/method_type.rbs index c70f55253..541ecbf4b 100644 --- a/sig/steep/interface/method_type.rbs +++ b/sig/steep/interface/method_type.rbs @@ -9,7 +9,7 @@ module Steep attr_reader block: Block? - attr_reader method_decls: Set[MethodDecl] + private attr_reader method_decls: Set[MethodDecl] @fvs: Set[Symbol] diff --git a/sig/steep/interface/shape.rbs b/sig/steep/interface/shape.rbs index 42b3b9c20..885487cff 100644 --- a/sig/steep/interface/shape.rbs +++ b/sig/steep/interface/shape.rbs @@ -1,15 +1,31 @@ +use Steep::TypeInference::MethodCall::MethodDecl + module Steep module Interface class Shape + class MethodOverload + attr_reader method_type: MethodType + + attr_reader method_defs: Array[RBS::Definition::Method::TypeDef] + + def initialize: (MethodType, Array[RBS::Definition::Method::TypeDef]) -> void + + def subst: (Substitution) -> MethodOverload + + def method_decls: (Symbol) -> Array[MethodDecl] + end + class Entry @private_method: bool - @method_types: Array[MethodType]? + @overloads: Array[MethodOverload]? - @generator: (^() -> Array[MethodType]?)? + @generator: (^() -> Array[MethodOverload]?)? - def initialize: (method_types: Array[MethodType], private_method: bool) -> void - | (private_method: bool) { () -> Array[MethodType]? } -> void + attr_reader method_name: Symbol + + def initialize: (method_name: Symbol, overloads: Array[MethodOverload], private_method: bool) -> void + | (method_name: Symbol, private_method: bool) { () -> Array[MethodOverload]? } -> void def has_method_type?: () -> bool @@ -19,6 +35,8 @@ module Steep def public_method?: () -> bool + def overloads: () -> Array[MethodOverload] + def method_types: () -> Array[MethodType] def force: () -> void diff --git a/sig/steep/located_value.rbs b/sig/steep/located_value.rbs new file mode 100644 index 000000000..7b316371c --- /dev/null +++ b/sig/steep/located_value.rbs @@ -0,0 +1,15 @@ +module Steep + class LocatedValue[T] + attr_reader value: T + + attr_reader location: RBS::Location[untyped, untyped] + + def initialize: (value: T, location: RBS::Location[untyped, untyped]) -> void + + def ==: (untyped) -> bool + + alias eql? == + + def hash: () -> Integer + end +end diff --git a/sig/steep/type_construction.rbs b/sig/steep/type_construction.rbs index 27b60ea8c..b4b17f00e 100644 --- a/sig/steep/type_construction.rbs +++ b/sig/steep/type_construction.rbs @@ -238,7 +238,7 @@ module Steep Parser::AST::Node node, receiver_type: AST::Types::t, method_name: Symbol, - method_type: Interface::MethodType, + method_overload: Interface::Shape::MethodOverload, arguments: Array[Parser::AST::Node], block_params: Parser::AST::Node?, block_body: Parser::AST::Node?, @@ -254,7 +254,7 @@ module Steep Parser::AST::Node node, receiver_type: AST::Types::t, method_name: Symbol, - method_type: Interface::MethodType, + method_overload: Interface::Shape::MethodOverload, arguments: Array[Parser::AST::Node], block_params: Parser::AST::Node?, block_body: Parser::AST::Node?, diff --git a/test/annotation_parsing_test.rb b/test/annotation_parsing_test.rb index a6a5aaf3b..404b12fb7 100644 --- a/test/annotation_parsing_test.rb +++ b/test/annotation_parsing_test.rb @@ -41,7 +41,7 @@ def test_method_annotation assert_instance_of Annotation::MethodType, annot assert_equal :foo, annot.name - assert_equal factory.method_type(RBS::Parser.parse_method_type("(Bar) -> Baz"), method_decls: Set[]), + assert_equal factory.method_type(RBS::Parser.parse_method_type("(Bar) -> Baz")), annot.type end end diff --git a/test/ast/node/type_application_test.rb b/test/ast/node/type_application_test.rb index 450f57237..7d8d71fab 100644 --- a/test/ast/node/type_application_test.rb +++ b/test/ast/node/type_application_test.rb @@ -24,7 +24,7 @@ class Bar assert_equal "Bar", app.type_str app.types([nil, TypeName("::Foo")], checker, []).tap do |types| assert_equal 1, types.size - assert_equal parse_type("::Foo::Bar"), types[0] + assert_equal parse_type("::Foo::Bar"), types[0].value assert_equal "Bar", types[0].location.source end end @@ -40,10 +40,10 @@ def test_sequence_type app.types(nil, checker, []).tap do |types| assert_equal 2, types.size - assert_equal parse_type("::String"), types[0] + assert_equal parse_type("::String"), types[0].value assert_equal "String", types[0].location.source - assert_equal parse_type("::Integer"), types[1] + assert_equal parse_type("::Integer"), types[1].value assert_equal "Integer", types[1].location.source end end diff --git a/test/test_helper.rb b/test/test_helper.rb index a25575239..1ce4cf3e3 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -533,7 +533,7 @@ def parse_ruby(string, factory: self.factory) def parse_method_type(string, factory: self.factory, variables: []) type = RBS::Parser.parse_method_type(string, variables: variables) - factory.method_type(type, method_decls: Set[]) + factory.method_type(type) end end diff --git a/test/type_factory_test.rb b/test/type_factory_test.rb index b689b1c91..30efb9cf2 100644 --- a/test/type_factory_test.rb +++ b/test/type_factory_test.rb @@ -11,7 +11,7 @@ def parse_method_type(str) def assert_overload_with(c, *types) types = types.map do |s| - factory.method_type(parse_method_type(s), self_type: Steep::AST::Types::Self.new, subst2: nil, method_decls: Set[]) + factory.method_type(parse_method_type(s), self_type: Steep::AST::Types::Self.new, subst2: nil) end assert_equal Set.new(types), Set.new(c.method_types), "Expected: { #{types.join(" | ")} }, Actual: #{c.to_s}" @@ -19,7 +19,7 @@ def assert_overload_with(c, *types) def assert_overload_including(c, *types) types = types.map do |s| - factory.method_type(parse_method_type(s), self_type: Steep::AST::Types::Self.new, subst2: nil, method_decls: Set[]) + factory.method_type(parse_method_type(s), self_type: Steep::AST::Types::Self.new, subst2: nil) end assert_operator Set.new(types), @@ -258,19 +258,19 @@ def test_method_type with_factory() do |factory| self_type = factory.type(parse_type("::Array[X]", variables: [:X])) - factory.method_type(parse_method_type("[A] (A) { (A, B) -> nil } -> void"), method_decls: Set[]).yield_self do |type| + factory.method_type(parse_method_type("[A] (A) { (A, B) -> nil } -> void")).yield_self do |type| assert_equal "[A] (A) { (A, B) -> nil } -> void", type.to_s end - factory.method_type(parse_method_type("[A] (A) -> void"), method_decls: Set[]).yield_self do |type| + factory.method_type(parse_method_type("[A] (A) -> void")).yield_self do |type| assert_equal "[A] (A) -> void", type.to_s end - factory.method_type(parse_method_type("[A] () ?{ () -> A } -> void"), method_decls: Set[]).yield_self do |type| + factory.method_type(parse_method_type("[A] () ?{ () -> A } -> void")).yield_self do |type| assert_equal "[A] () ?{ () -> A } -> void", type.to_s end - factory.method_type(parse_method_type("[X] (X) -> void"), method_decls: Set[]).yield_self do |type| + factory.method_type(parse_method_type("[X] (X) -> void")).yield_self do |type| assert_method_type( "[X] (X) -> void", type @@ -283,18 +283,18 @@ def test_bounded_method_type with_factory() do |factory| self_type = factory.type(parse_type("::Array[X]", variables: [:X])) - factory.method_type(parse_method_type("[A < Integer] (A) -> void"), method_decls: Set[]).yield_self do |type| + factory.method_type(parse_method_type("[A < Integer] (A) -> void")).yield_self do |type| assert_equal "[A < Integer] (A) -> void", type.to_s end - factory.method_type(parse_method_type("[X < Integer] () -> X"), method_decls: Set[]).yield_self do |type| + factory.method_type(parse_method_type("[X < Integer] () -> X")).yield_self do |type| assert_method_type( "[X < Integer] () -> X", type ) end - factory.method_type(parse_method_type("[X < Integer, Y < Array[X]] (Y) -> X"), method_decls: Set[]).yield_self do |type| + factory.method_type(parse_method_type("[X < Integer, Y < Array[X]] (Y) -> X")).yield_self do |type| assert_method_type( "[X < Integer, Y < Array[X]] (Y) -> X", type @@ -308,17 +308,17 @@ def test_method_type_1 self_type = factory.type(parse_type("::Array[X]", variables: [:X])) parse_method_type("[A] (A) { (A, B) -> nil } -> void").tap do |original| - type = factory.method_type_1(factory.method_type(original, method_decls: Set[])) + type = factory.method_type_1(factory.method_type(original)) assert_equal original, type end parse_method_type("[A] (A) -> void").tap do |original| - type = factory.method_type_1(factory.method_type(original, method_decls: Set[])) + type = factory.method_type_1(factory.method_type(original)) assert_equal original, type end parse_method_type("[A] () ?{ () -> A } -> void").tap do |original| - type = factory.method_type_1(factory.method_type(original, method_decls: Set[])) + type = factory.method_type_1(factory.method_type(original)) assert_equal original, type end end diff --git a/test/validation_test.rb b/test/validation_test.rb index b68948e09..6db4a1477 100644 --- a/test/validation_test.rb +++ b/test/validation_test.rb @@ -653,7 +653,6 @@ class Foo[X < Numeric] refute_predicate validator, :no_error? assert_any!(validator.each_error, size: 1) do |error| assert_instance_of Diagnostic::Signature::UnsatisfiableTypeApplication, error - assert_equal "::Foo[::String]", error.location.source end end @@ -667,7 +666,6 @@ class Foo[X < Numeric] refute_predicate validator, :no_error? assert_any!(validator.each_error, size: 1) do |error| assert_instance_of Diagnostic::Signature::UnsatisfiableTypeApplication, error - assert_equal "::_Bar[::String]", error.location.source end end @@ -681,7 +679,6 @@ class Foo[X < Numeric] refute_predicate validator, :no_error? assert_any!(validator.each_error, size: 1) do |error| assert_instance_of Diagnostic::Signature::UnsatisfiableTypeApplication, error - assert_equal "::baz[::BasicObject]", error.location.source end end end From 5945719316dcd8268e736cff827dde77702566a6 Mon Sep 17 00:00:00 2001 From: Soutaro Matsumoto Date: Wed, 7 Aug 2024 15:42:03 +0900 Subject: [PATCH 2/5] No transorm_values --- bin/steep-check.rb | 1 + lib/steep/interface/shape.rb | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/steep-check.rb b/bin/steep-check.rb index 8f6bf4313..472083b7b 100755 --- a/bin/steep-check.rb +++ b/bin/steep-check.rb @@ -244,6 +244,7 @@ def type_check_files(command_line_args, env) typings = command.type_check_files(command_line_args, env) pp steep_method_types: ObjectSpace.each_object(Steep::Interface::MethodType).count, rbs_method_types: ObjectSpace.each_object(RBS::MethodType).count + pp any: ObjectSpace.each_object(Steep::AST::Types::Any).count, void: ObjectSpace.each_object(Steep::AST::Types::Void).count, self: ObjectSpace.each_object(Steep::AST::Types::Self).count end end diff --git a/lib/steep/interface/shape.rb b/lib/steep/interface/shape.rb index c19077b12..d307a7529 100644 --- a/lib/steep/interface/shape.rb +++ b/lib/steep/interface/shape.rb @@ -105,7 +105,7 @@ class Methods def initialize(substs:, methods:) @substs = substs @methods = methods - @resolved_methods = methods.transform_values { nil } + @resolved_methods = {} end def key?(name) From 1547d615417839c6b851d8ef71b2edda094e01e5 Mon Sep 17 00:00:00 2001 From: Soutaro Matsumoto Date: Thu, 8 Aug 2024 15:24:21 +0900 Subject: [PATCH 3/5] Delete `MethodType#method_decls` --- lib/steep/ast/types/factory.rb | 3 +-- lib/steep/interface/builder.rb | 38 ++++++++++------------------- lib/steep/interface/method_type.rb | 28 ++++++++------------- sig/steep/interface/method_type.rbs | 6 ++--- 4 files changed, 26 insertions(+), 49 deletions(-) diff --git a/lib/steep/ast/types/factory.rb b/lib/steep/ast/types/factory.rb index 337514f72..7d17feef5 100644 --- a/lib/steep/ast/types/factory.rb +++ b/lib/steep/ast/types/factory.rb @@ -286,8 +286,7 @@ def method_type(method_type) ), self_type: type_opt(block.self_type) ) - end, - method_decls: Set[] + end ) end diff --git a/lib/steep/interface/builder.rb b/lib/steep/interface/builder.rb index 5a7ace01e..9a2f49ec8 100644 --- a/lib/steep/interface/builder.rb +++ b/lib/steep/interface/builder.rb @@ -445,8 +445,7 @@ def tuple_shape(tuple) return_type: elem_type, location: nil ), - block: nil, - method_decls: Set[] + block: nil ), [] ) @@ -469,8 +468,7 @@ def tuple_shape(tuple) return_type: elem_type, location: nil ), - block: nil, - method_decls: Set[] + block: nil ), [] ) @@ -493,8 +491,7 @@ def tuple_shape(tuple) 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)], @@ -508,8 +505,7 @@ def tuple_shape(tuple) 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)], @@ -526,8 +522,7 @@ def tuple_shape(tuple) ), optional: false, self_type: nil - ), - method_decls: Set[] + ) ) ].map { Shape::MethodOverload.new(_1, []) } } + fetch.overloads @@ -547,8 +542,7 @@ def tuple_shape(tuple) return_type: tuple.types[0] || AST::Builtin.nil_type, location: nil ), - block: nil, - method_decls: Set[] + block: nil ), [] ) @@ -569,8 +563,7 @@ def tuple_shape(tuple) return_type: tuple.types.last || AST::Builtin.nil_type, location: nil ), - block: nil, - method_decls: Set[] + block: nil ), [] ) @@ -615,8 +608,7 @@ def record_shape(record) return_type: value_type, location: nil ), - block: nil, - method_decls: Set[] + block: nil ), [] ) @@ -639,8 +631,7 @@ def record_shape(record) params: Function::Params.build(required: [key_type, value_type]), return_type: value_type, location: nil), - block: nil, - method_decls: Set[] + block: nil ), [] ) @@ -665,8 +656,7 @@ def record_shape(record) 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)], @@ -675,8 +665,7 @@ def record_shape(record) 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)], @@ -693,8 +682,7 @@ def record_shape(record) ), optional: false, self_type: nil - ), - method_decls: Set[] + ) ) ].map { Shape::MethodOverload.new(_1, []) } } + update.overloads @@ -709,7 +697,7 @@ def proc_shape(proc, proc_shape) shape.methods.merge!(proc_shape.methods) overload = Shape::MethodOverload.new( - MethodType.new(type_params: [], type: proc.type, block: proc.block, method_decls: Set[]), + MethodType.new(type_params: [], type: proc.type, block: proc.block), [] ) diff --git a/lib/steep/interface/method_type.rb b/lib/steep/interface/method_type.rb index 69f6ca769..95a2c4ad7 100644 --- a/lib/steep/interface/method_type.rb +++ b/lib/steep/interface/method_type.rb @@ -4,13 +4,11 @@ class MethodType attr_reader :type_params attr_reader :type attr_reader :block - attr_reader :method_decls - def initialize(type_params:, type:, block:, method_decls:) + def initialize(type_params:, type:, block:) @type_params = type_params @type = type @block = block - @method_decls = method_decls end def ==(other) @@ -52,7 +50,7 @@ def subst(s) if ty == type && bl == block self else - self.class.new(type_params: type_params, type: ty, block: bl, method_decls: method_decls) + self.class.new(type_params: type_params, type: ty, block: bl) end end @@ -72,15 +70,13 @@ def each_type(&block) def instantiate(s) self.class.new(type_params: [], type: type.subst(s), - block: block&.subst(s), - method_decls: method_decls) + block: block&.subst(s)) 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) self.class.new(type_params: type_params, type: type, - block: block, - method_decls: method_decls) + block: block) end def to_s @@ -95,8 +91,7 @@ def to_s 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) + block: self.block&.yield_self {|blk| blk.map_type(&block) }) end # Returns a new method type which can be used for the method implementation type of both `self` and `other`. @@ -125,8 +120,7 @@ def unify_overload(other) ), location: nil ), - block: block, - method_decls: method_decls + other.method_decls + block: block ) end @@ -280,8 +274,7 @@ def |(other) MethodType.new( type_params: [], type: Function.new(params: params, return_type: return_type, location: nil), - block: block, - method_decls: method_decls + other.method_decls + block: block ) end @@ -293,7 +286,7 @@ def &(other) else params = self.type.params || other.type.params end - + block = case when (b = self.block) && (ob = other.block) @@ -324,8 +317,7 @@ def &(other) MethodType.new( type_params: [], type: Function.new(params: params, return_type: return_type, location: nil), - block: block, - method_decls: method_decls + other.method_decls + block: block ) end end diff --git a/sig/steep/interface/method_type.rbs b/sig/steep/interface/method_type.rbs index 541ecbf4b..91501dd92 100644 --- a/sig/steep/interface/method_type.rbs +++ b/sig/steep/interface/method_type.rbs @@ -9,11 +9,9 @@ module Steep attr_reader block: Block? - private attr_reader method_decls: Set[MethodDecl] - @fvs: Set[Symbol] - def initialize: (type_params: Array[TypeParam], type: Function, block: Block?, method_decls: Set[MethodDecl]) -> void + def initialize: (type_params: Array[TypeParam], type: Function, block: Block?) -> void def ==: (untyped other) -> bool @@ -30,7 +28,7 @@ module Steep def instantiate: (Substitution s) -> MethodType - def with: (?type_params: Array[TypeParam], ?type: Function, ?block: Block?, ?method_decls: Set[MethodDecl]) -> MethodType + def with: (?type_params: Array[TypeParam], ?type: Function, ?block: Block?) -> MethodType def to_s: () -> ::String From b71a03522335075b4ec5a7816bd8946fc49ef15b Mon Sep 17 00:00:00 2001 From: Soutaro Matsumoto Date: Thu, 8 Aug 2024 15:58:04 +0900 Subject: [PATCH 4/5] Delete location from types --- lib/steep/ast/types/any.rb | 10 -- lib/steep/ast/types/boolean.rb | 22 ++-- lib/steep/ast/types/bot.rb | 10 -- lib/steep/ast/types/class.rb | 10 -- lib/steep/ast/types/factory.rb | 116 ++++++++++------------ lib/steep/ast/types/instance.rb | 8 +- lib/steep/ast/types/intersection.rb | 23 ++--- lib/steep/ast/types/literal.rb | 10 +- lib/steep/ast/types/logic.rb | 25 +---- lib/steep/ast/types/name.rb | 21 +--- lib/steep/ast/types/nil.rb | 13 +-- lib/steep/ast/types/proc.rb | 17 +--- lib/steep/ast/types/record.rb | 14 +-- lib/steep/ast/types/self.rb | 10 -- lib/steep/ast/types/top.rb | 10 -- lib/steep/ast/types/tuple.rb | 14 +-- lib/steep/ast/types/union.rb | 21 ++-- lib/steep/ast/types/var.rb | 17 +--- lib/steep/ast/types/void.rb | 10 -- lib/steep/diagnostic/ruby.rb | 4 +- lib/steep/interface/builder.rb | 25 +++-- lib/steep/services/completion_provider.rb | 2 +- lib/steep/services/hover_provider/ruby.rb | 2 +- lib/steep/signature/validator.rb | 22 ++-- lib/steep/subtyping/check.rb | 21 ++-- lib/steep/subtyping/constraints.rb | 8 +- lib/steep/type_construction.rb | 10 +- lib/steep/type_inference/method_params.rb | 2 +- sig/steep/ast/types/any.rbs | 6 -- sig/steep/ast/types/boolean.rbs | 6 -- sig/steep/ast/types/bot.rbs | 6 -- sig/steep/ast/types/class.rbs | 6 -- sig/steep/ast/types/factory.rbs | 2 +- sig/steep/ast/types/instance.rbs | 6 -- sig/steep/ast/types/intersection.rbs | 8 +- sig/steep/ast/types/literal.rbs | 6 +- sig/steep/ast/types/logic.rbs | 11 +- sig/steep/ast/types/name.rbs | 10 +- sig/steep/ast/types/nil.rbs | 6 -- sig/steep/ast/types/proc.rbs | 6 +- sig/steep/ast/types/record.rbs | 6 +- sig/steep/ast/types/self.rbs | 6 -- sig/steep/ast/types/top.rbs | 6 -- sig/steep/ast/types/tuple.rbs | 6 +- sig/steep/ast/types/union.rbs | 8 +- sig/steep/ast/types/var.rbs | 8 +- sig/steep/ast/types/void.rbs | 6 -- sig/steep/diagnostic/ruby.rbs | 2 +- test/test_helper.rb | 8 +- 49 files changed, 161 insertions(+), 451 deletions(-) diff --git a/lib/steep/ast/types/any.rb b/lib/steep/ast/types/any.rb index f9123b4e4..15bdee825 100644 --- a/lib/steep/ast/types/any.rb +++ b/lib/steep/ast/types/any.rb @@ -2,12 +2,6 @@ module Steep module AST module Types class Any - attr_reader :location - - def initialize(location: nil) - @location = location - end - def ==(other) other.is_a?(Any) end @@ -33,10 +27,6 @@ def to_s def level [1] end - - def with_location(new_location) - self.class.new(location: new_location) - end end end end diff --git a/lib/steep/ast/types/boolean.rb b/lib/steep/ast/types/boolean.rb index 70e218103..f8b54ad04 100644 --- a/lib/steep/ast/types/boolean.rb +++ b/lib/steep/ast/types/boolean.rb @@ -2,12 +2,6 @@ module Steep module AST module Types class Boolean - attr_reader :location - - def initialize(location: nil) - @location = location - end - def ==(other) other.is_a?(Boolean) end @@ -34,17 +28,13 @@ def level [0] end - def with_location(new_location) - self.class.new(location: new_location) - end - def back_type - Union.build(types: - [ - Builtin::TrueClass.instance_type, - Builtin::FalseClass.instance_type - ], - location: location) + Union.build( + types: [ + Builtin::TrueClass.instance_type, + Builtin::FalseClass.instance_type + ] + ) end end end diff --git a/lib/steep/ast/types/bot.rb b/lib/steep/ast/types/bot.rb index f79ab8ecc..657385598 100644 --- a/lib/steep/ast/types/bot.rb +++ b/lib/steep/ast/types/bot.rb @@ -2,12 +2,6 @@ module Steep module AST module Types class Bot - attr_reader :location - - def initialize(location: nil) - @location = location - end - def ==(other) other.is_a?(Bot) end @@ -33,10 +27,6 @@ def to_s def level [2] end - - def with_location(new_location) - self.class.new(location: new_location) - end end end end diff --git a/lib/steep/ast/types/class.rb b/lib/steep/ast/types/class.rb index 77fbcd595..43525e749 100644 --- a/lib/steep/ast/types/class.rb +++ b/lib/steep/ast/types/class.rb @@ -2,12 +2,6 @@ module Steep module AST module Types class Class - attr_reader :location - - def initialize(location: nil) - @location = location - end - def self.instance @instance ||= new() end @@ -45,10 +39,6 @@ def free_variables def level [0] end - - def with_location(new_location) - self.class.new(location: new_location) - end end end end diff --git a/lib/steep/ast/types/factory.rb b/lib/steep/ast/types/factory.rb index 7d17feef5..be46001e3 100644 --- a/lib/steep/ast/types/factory.rb +++ b/lib/steep/ast/types/factory.rb @@ -44,55 +44,55 @@ def type(type) type_cache[type] = case type when RBS::Types::Bases::Any - Any.new(location: nil) + Any.new() when RBS::Types::Bases::Class - Class.new(location: nil) + Class.new() when RBS::Types::Bases::Instance - Instance.new(location: nil) + Instance.new() when RBS::Types::Bases::Self - Self.new(location: nil) + Self.new() when RBS::Types::Bases::Top - Top.new(location: nil) + Top.new() when RBS::Types::Bases::Bottom - Bot.new(location: nil) + Bot.new() when RBS::Types::Bases::Bool - Boolean.new(location: nil) + Boolean.new() when RBS::Types::Bases::Void - Void.new(location: nil) + Void.new() when RBS::Types::Bases::Nil - Nil.new(location: nil) + Nil.new() when RBS::Types::Variable - Var.new(name: type.name, location: nil) + Var.new(name: type.name) when RBS::Types::ClassSingleton type_name = type.name - Name::Singleton.new(name: type_name, location: nil) + Name::Singleton.new(name: type_name) when RBS::Types::ClassInstance type_name = type.name args = type.args.map {|arg| type(arg) } - Name::Instance.new(name: type_name, args: args, location: nil) + Name::Instance.new(name: type_name, args: args) when RBS::Types::Interface type_name = type.name args = type.args.map {|arg| type(arg) } - Name::Interface.new(name: type_name, args: args, location: nil) + Name::Interface.new(name: type_name, args: args) when RBS::Types::Alias type_name = type.name args = type.args.map {|arg| type(arg) } - Name::Alias.new(name: type_name, args: args, location: nil) + Name::Alias.new(name: type_name, args: args) when RBS::Types::Union - Union.build(types: type.types.map {|ty| type(ty) }, location: nil) + Union.build(types: type.types.map {|ty| type(ty) }) when RBS::Types::Intersection - Intersection.build(types: type.types.map {|ty| type(ty) }, location: nil) + Intersection.build(types: type.types.map {|ty| type(ty) }) when RBS::Types::Optional - Union.build(types: [type(type.type), Nil.new(location: nil)], location: nil) + Union.build(types: [type(type.type), Nil.new()]) when RBS::Types::Literal - Literal.new(value: type.literal, location: nil) + Literal.new(value: type.literal) when RBS::Types::Tuple - Tuple.new(types: type.types.map {|ty| type(ty) }, location: nil) + Tuple.new(types: type.types.map {|ty| type(ty) }) when RBS::Types::Record elements = type.fields.each.with_object({}) do |(key, value), hash| hash[key] = type(value) end - Record.new(elements: elements, location: nil) + Record.new(elements: elements) when RBS::Types::Proc func = Interface::Function.new( params: params(type.type), @@ -124,67 +124,67 @@ def type(type) def type_1(type) case type when Any - RBS::Types::Bases::Any.new(location: type.location) + RBS::Types::Bases::Any.new(location: nil) when Class - RBS::Types::Bases::Class.new(location: type.location) + RBS::Types::Bases::Class.new(location: nil) when Instance - RBS::Types::Bases::Instance.new(location: type.location) + RBS::Types::Bases::Instance.new(location: nil) when Self - RBS::Types::Bases::Self.new(location: type.location) + RBS::Types::Bases::Self.new(location: nil) when Top - RBS::Types::Bases::Top.new(location: type.location) + RBS::Types::Bases::Top.new(location: nil) when Bot - RBS::Types::Bases::Bottom.new(location: type.location) + RBS::Types::Bases::Bottom.new(location: nil) when Boolean - RBS::Types::Bases::Bool.new(location: type.location) + RBS::Types::Bases::Bool.new(location: nil) when Void - RBS::Types::Bases::Void.new(location: type.location) + RBS::Types::Bases::Void.new(location: nil) when Nil - RBS::Types::Bases::Nil.new(location: type.location) + RBS::Types::Bases::Nil.new(location: nil) when Var - RBS::Types::Variable.new(name: type.name, location: type.location) + RBS::Types::Variable.new(name: type.name, location: nil) when Name::Singleton - RBS::Types::ClassSingleton.new(name: type.name, location: type.location) + RBS::Types::ClassSingleton.new(name: type.name, location: nil) when Name::Instance RBS::Types::ClassInstance.new( name: type.name, args: type.args.map {|arg| type_1(arg) }, - location: type.location + location: nil ) when Name::Interface RBS::Types::Interface.new( name: type.name, args: type.args.map {|arg| type_1(arg) }, - location: type.location + location: nil ) when Name::Alias RBS::Types::Alias.new( name: type.name, args: type.args.map {|arg| type_1(arg) }, - location: type.location + location: nil ) when Union RBS::Types::Union.new( types: type.types.map {|ty| type_1(ty) }, - location: type.location + location: nil ) when Intersection RBS::Types::Intersection.new( types: type.types.map {|ty| type_1(ty) }, - location: type.location + location: nil ) when Literal - RBS::Types::Literal.new(literal: type.value, location: type.location) + RBS::Types::Literal.new(literal: type.value, location: nil) when Tuple RBS::Types::Tuple.new( types: type.types.map {|ty| type_1(ty) }, - location: type.location + location: nil ) when Record fields = type.elements.each.with_object({}) do |(key, value), hash| hash[key] = type_1(value) end - RBS::Types::Record.new(fields: fields, location: type.location) + RBS::Types::Record.new(fields: fields, location: nil) when Proc block = if type.block RBS::Types::Block.new( @@ -197,10 +197,10 @@ def type_1(type) type: function_1(type.type), self_type: type_1_opt(type.self_type), block: block, - location: type.location + location: nil ) when Logic::Base - RBS::Types::Bases::Bool.new(location: type.location) + RBS::Types::Bases::Bool.new(location: nil) else raise "Unexpected type given: #{type} (#{type.class})" end @@ -332,10 +332,10 @@ def deep_expand_alias(type, recursive: Set.new) end when AST::Types::Union types = type.types.map {|ty| deep_expand_alias(ty, recursive: recursive) or return } - AST::Types::Union.build(types: types, location: type.location) + AST::Types::Union.build(types: types) when AST::Types::Intersection types = type.types.map {|ty| deep_expand_alias(ty, recursive: recursive) or return } - AST::Types::Intersection.build(types: types, location: type.location) + AST::Types::Intersection.build(types: types) else type end @@ -440,11 +440,11 @@ def absolute_type_name(type_name, context:) type_name_resolver.resolve(type_name, context: context) end - def instance_type(type_name, args: nil, location: nil) + def instance_type(type_name, args: nil) raise unless type_name.class? definition = definition_builder.build_singleton(type_name) - def_args = definition.type_params.map { Any.new(location: nil) } + def_args = definition.type_params.map { Any.new() } if args raise if def_args.size != args.size @@ -452,7 +452,7 @@ def instance_type(type_name, args: nil, location: nil) args = def_args end - AST::Types::Name::Instance.new(location: location, name: type_name, args: args) + AST::Types::Name::Instance.new(name: type_name, args: args) end def try_instance_type(type) @@ -480,13 +480,11 @@ def normalize_type(type) when AST::Types::Name::Instance AST::Types::Name::Instance.new( name: env.normalize_module_name(type.name), - args: type.args.map {|ty| normalize_type(ty) }, - location: type.location + args: type.args.map {|ty| normalize_type(ty) } ) when AST::Types::Name::Singleton AST::Types::Name::Singleton.new( - name: env.normalize_module_name(type.name), - location: type.location + name: env.normalize_module_name(type.name) ) when AST::Types::Any, AST::Types::Boolean, AST::Types::Bot, AST::Types::Nil, AST::Types::Top, AST::Types::Void, AST::Types::Literal, AST::Types::Class, AST::Types::Instance, @@ -494,37 +492,31 @@ def normalize_type(type) type when AST::Types::Intersection AST::Types::Intersection.build( - types: type.types.map {|type| normalize_type(type) }, - location: type.location + types: type.types.map {|type| normalize_type(type) } ) when AST::Types::Union AST::Types::Union.build( - types: type.types.map {|type| normalize_type(type) }, - location: type.location + types: type.types.map {|type| normalize_type(type) } ) when AST::Types::Record AST::Types::Record.new( - elements: type.elements.transform_values {|type| normalize_type(type) }, - location: type.location + elements: type.elements.transform_values {|type| normalize_type(type) } ) when AST::Types::Tuple AST::Types::Tuple.new( - types: type.types.map {|type| normalize_type(type) }, - location: type.location + types: type.types.map {|type| normalize_type(type) } ) when AST::Types::Proc type.map_type {|type| normalize_type(type) } when AST::Types::Name::Alias AST::Types::Name::Alias.new( name: type.name, - args: type.args.map {|ty| normalize_type(ty) }, - location: type.location + args: type.args.map {|ty| normalize_type(ty) } ) when AST::Types::Name::Interface AST::Types::Name::Interface.new( name: type.name, - args: type.args.map {|ty| normalize_type(ty) }, - location: type.location + args: type.args.map {|ty| normalize_type(ty) } ) end end diff --git a/lib/steep/ast/types/instance.rb b/lib/steep/ast/types/instance.rb index 228e9ce3a..3ad478de6 100644 --- a/lib/steep/ast/types/instance.rb +++ b/lib/steep/ast/types/instance.rb @@ -2,12 +2,6 @@ module Steep module AST module Types class Instance - attr_reader :location - - def initialize(location: nil) - @location = location - end - def self.instance @instance ||= new() end @@ -46,7 +40,7 @@ def level end def with_location(new_location) - self.class.new(location: new_location) + self.class.new() end end end diff --git a/lib/steep/ast/types/intersection.rb b/lib/steep/ast/types/intersection.rb index 3c601b885..155b89ad1 100644 --- a/lib/steep/ast/types/intersection.rb +++ b/lib/steep/ast/types/intersection.rb @@ -3,14 +3,12 @@ module AST module Types class Intersection attr_reader :types - attr_reader :location - def initialize(types:, location: nil) + def initialize(types:) @types = types - @location = location end - def self.build(types:, location: nil) + def self.build(types:) types.flat_map do |type| if type.is_a?(Intersection) type.types @@ -20,9 +18,9 @@ def self.build(types:, location: nil) end.map do |type| case type when AST::Types::Any - return AST::Types::Any.new(location: location) + return AST::Types::Any.new() when AST::Types::Bot - return AST::Types::Bot.new(location: location) + return AST::Types::Bot.new() when AST::Types::Top nil else @@ -33,11 +31,11 @@ def self.build(types:, location: nil) case dups.size when 0 - AST::Types::Top.new(location: location) + AST::Types::Top.new() when 1 tys.first || raise else - new(types: dups.to_a, location: location) + new(types: dups.to_a) end end end @@ -53,7 +51,7 @@ def hash alias eql? == def subst(s) - self.class.build(location: location, types: types.map {|ty| ty.subst(s) }) + self.class.build(types: types.map {|ty| ty.subst(s) }) end def to_s @@ -82,18 +80,13 @@ def each_child(&block) def map_type(&block) self.class.build( - types: each_child.map(&block), - location: location + types: each_child.map(&block) ) end def level [0] + level_of_children(types) end - - def with_location(new_location) - self.class.new(types: types, location: new_location) - end end end end diff --git a/lib/steep/ast/types/literal.rb b/lib/steep/ast/types/literal.rb index 2acf16843..d9257039e 100644 --- a/lib/steep/ast/types/literal.rb +++ b/lib/steep/ast/types/literal.rb @@ -2,11 +2,9 @@ module Steep module AST module Types class Literal - attr_reader :location attr_reader :value - def initialize(value:, location: nil) - @location = location + def initialize(value:) @value = value end @@ -37,10 +35,6 @@ def level [0] end - def with_location(new_location) - _ = self.class.new(value: value, location: new_location) - end - def back_type klass = case value when Integer @@ -57,7 +51,7 @@ def back_type raise "Unexpected literal type: #{(_ = value).inspect}" end - Name::Instance.new(name: klass.module_name, args: [], location: location) + Name::Instance.new(name: klass.module_name, args: []) end end end diff --git a/lib/steep/ast/types/logic.rb b/lib/steep/ast/types/logic.rb index 6d89c192c..101661b83 100644 --- a/lib/steep/ast/types/logic.rb +++ b/lib/steep/ast/types/logic.rb @@ -3,8 +3,6 @@ module AST module Types module Logic class Base - attr_reader :location - def subst(s) self end @@ -33,51 +31,30 @@ def level end class Not < Base - def initialize(location: nil) - @location = location - end end class ReceiverIsNil < Base - def initialize(location: nil) - @location = location - end end class ReceiverIsNotNil < Base - def initialize(location: nil) - @location = location - end end class ReceiverIsArg < Base - def initialize(location: nil) - @location = location - end end class ArgIsReceiver < Base - def initialize(location: nil) - @location = location - end end class ArgEqualsReceiver < Base - def initialize(location: nil) - @location = location - end end class ArgIsAncestor < Base - def initialize(location: nil) - @location = location - end end class Env < Base attr_reader :truthy, :falsy, :type - def initialize(truthy:, falsy:, type:, location: nil) + def initialize(truthy:, falsy:, type:) @truthy = truthy @falsy = falsy @type = type diff --git a/lib/steep/ast/types/name.rb b/lib/steep/ast/types/name.rb index 81e1db0d3..1d8996897 100644 --- a/lib/steep/ast/types/name.rb +++ b/lib/steep/ast/types/name.rb @@ -3,11 +3,9 @@ module AST module Types module Name class Base - attr_reader :location attr_reader :name - def initialize(name:, location: nil) - @location = location + def initialize(name:) @name = name end @@ -29,8 +27,8 @@ def map_type(&block) class Applying < Base attr_reader :args - def initialize(name:, args:, location: nil) - super(name: name, location: location) + def initialize(name:, args:) + super(name: name) @args = args end @@ -54,14 +52,9 @@ def to_s end end - def with_location(new_location) - _ = self.class.new(name: name, args: args, location: new_location) - end - def subst(s) if free_variables.intersect?(s.domain) _ = self.class.new( - location: location, name: name, args: args.map {|a| a.subst(s) } ) @@ -95,7 +88,7 @@ def level def map_type(&block) args = self.args.map(&block) - _ = self.class.new(name: self.name, args: self.args, location: self.location) + _ = self.class.new(name: self.name, args: self.args) end end @@ -115,16 +108,12 @@ def to_s "singleton(#{name.to_s})" end - def with_location(new_location) - self.class.new(name: name, location: new_location) - end - include Helper::NoChild end class Instance < Applying def to_module - Singleton.new(name: name, location: location) + Singleton.new(name: name) end end diff --git a/lib/steep/ast/types/nil.rb b/lib/steep/ast/types/nil.rb index bc2840667..83b689919 100644 --- a/lib/steep/ast/types/nil.rb +++ b/lib/steep/ast/types/nil.rb @@ -2,12 +2,6 @@ module Steep module AST module Types class Nil - attr_reader :location - - def initialize(location: nil) - @location = location - end - def ==(other) other.is_a?(Nil) end @@ -34,14 +28,9 @@ def level [0] end - def with_location(new_location) - self.class.new(location: new_location) - end - def back_type Name::Instance.new(name: Builtin::NilClass.module_name, - args: [], - location: location) + args: []) end end end diff --git a/lib/steep/ast/types/proc.rb b/lib/steep/ast/types/proc.rb index 0dece87b1..64f5e967a 100644 --- a/lib/steep/ast/types/proc.rb +++ b/lib/steep/ast/types/proc.rb @@ -2,16 +2,14 @@ module Steep module AST module Types class Proc - attr_reader :location attr_reader :type attr_reader :self_type attr_reader :block - def initialize(type:, block:, self_type:, location: type.location) + def initialize(type:, block:, self_type:) @type = type @block = block @self_type = self_type - @location = location end def ==(other) @@ -28,8 +26,7 @@ def subst(s) self.class.new( type: type.subst(s), block: block&.subst(s), - self_type: self_type&.subst(s), - location: location + self_type: self_type&.subst(s) ) end @@ -70,16 +67,11 @@ def level [0] + level_of_children(children) end - def with_location(new_location) - self.class.new(location: new_location, block: block, type: type, self_type: self_type) - end - def map_type(&block) self.class.new( type: type.map_type(&block), block: self.block&.map_type(&block), - self_type: self_type ? yield(self_type) : nil, - location: location + self_type: self_type ? yield(self_type) : nil ) end @@ -99,8 +91,7 @@ def one_arg? def back_type Name::Instance.new(name: Builtin::Proc.module_name, - args: [], - location: location) + args: []) end def block_required? diff --git a/lib/steep/ast/types/record.rb b/lib/steep/ast/types/record.rb index f4b0e2f83..91ce5051b 100644 --- a/lib/steep/ast/types/record.rb +++ b/lib/steep/ast/types/record.rb @@ -2,12 +2,10 @@ module Steep module AST module Types class Record - attr_reader :location attr_reader :elements - def initialize(elements:, location: nil) + def initialize(elements:) @elements = elements - @location = location end def ==(other) @@ -21,8 +19,7 @@ def hash alias eql? == def subst(s) - self.class.new(location: location, - elements: elements.transform_values {|type| type.subst(s) }) + self.class.new(elements: elements.transform_values {|type| type.subst(s) }) end def to_s @@ -52,18 +49,13 @@ def each_child(&block) def map_type(&block) self.class.new( - elements: elements.transform_values(&block), - location: location + elements: elements.transform_values(&block) ) end def level [0] + level_of_children(elements.values) end - - def with_location(new_location) - self.class.new(elements: elements, location: new_location) - end end end end diff --git a/lib/steep/ast/types/self.rb b/lib/steep/ast/types/self.rb index 7a990c606..ad54935f4 100644 --- a/lib/steep/ast/types/self.rb +++ b/lib/steep/ast/types/self.rb @@ -2,12 +2,6 @@ module Steep module AST module Types class Self - attr_reader :location - - def initialize(location: nil) - @location = location - end - def self.instance @instance ||= new() end @@ -45,10 +39,6 @@ def free_variables def level [0] end - - def with_location(new_location) - self.class.new(location: new_location) - end end end end diff --git a/lib/steep/ast/types/top.rb b/lib/steep/ast/types/top.rb index 46bec38b9..886e48f18 100644 --- a/lib/steep/ast/types/top.rb +++ b/lib/steep/ast/types/top.rb @@ -2,12 +2,6 @@ module Steep module AST module Types class Top - attr_reader :location - - def initialize(location: nil) - @location = location - end - def ==(other) other.is_a?(Top) end @@ -33,10 +27,6 @@ def to_s def level [2] end - - def with_location(new_location) - self.class.new(location: new_location) - end end end end diff --git a/lib/steep/ast/types/tuple.rb b/lib/steep/ast/types/tuple.rb index 97fbce1e7..ee0a302cc 100644 --- a/lib/steep/ast/types/tuple.rb +++ b/lib/steep/ast/types/tuple.rb @@ -3,11 +3,9 @@ module AST module Types class Tuple attr_reader :types - attr_reader :location - def initialize(types:, location: nil) + def initialize(types:) @types = types - @location = location end def ==(other) @@ -22,8 +20,7 @@ def hash alias eql? == def subst(s) - self.class.new(location: location, - types: types.map {|ty| ty.subst(s) }) + self.class.new(types: types.map {|ty| ty.subst(s) }) end def to_s @@ -47,10 +44,7 @@ def each_child(&block) end def map_type(&block) - Tuple.new( - types: types.map(&block), - location: location - ) + Tuple.new(types: types.map(&block)) end def level @@ -58,7 +52,7 @@ def level end def with_location(new_location) - self.class.new(types: types, location: new_location) + self.class.new(types: types) end end end diff --git a/lib/steep/ast/types/union.rb b/lib/steep/ast/types/union.rb index 2fb7f29cf..f03504769 100644 --- a/lib/steep/ast/types/union.rb +++ b/lib/steep/ast/types/union.rb @@ -3,14 +3,12 @@ module AST module Types class Union attr_reader :types - attr_reader :location - def initialize(types:, location: nil) + def initialize(types:) @types = types - @location = location end - def self.build(types:, location: nil) + def self.build(types:) return AST::Types::Bot.new if types.empty? if types.size == 1 return types.first || raise @@ -25,9 +23,9 @@ def self.build(types:, location: nil) end.map do |type| case type when AST::Types::Any - return AST::Types::Any.new(location: location) + return AST::Types::Any.new() when AST::Types::Top - return AST::Types::Top.new(location: location) + return AST::Types::Top.new() when AST::Types::Bot nil else @@ -40,7 +38,7 @@ def self.build(types:, location: nil) when 1 tys.first || raise else - new(types: tys, location: location) + new(types: tys) end end end @@ -57,7 +55,7 @@ def hash alias eql? == def subst(s) - self.class.build(location: location, types: types.map {|ty| ty.subst(s) }) + self.class.build(types: types.map {|ty| ty.subst(s) }) end def to_s @@ -81,10 +79,7 @@ def each_child(&block) end def map_type(&block) - Union.build( - types: types.map(&block), - location: location - ) + Union.build(types: types.map(&block)) end include Helper::ChildrenLevel @@ -94,7 +89,7 @@ def level end def with_location(new_location) - self.class.new(types: types, location: new_location) + self.class.new(types: types) end end end diff --git a/lib/steep/ast/types/var.rb b/lib/steep/ast/types/var.rb index 7c0cbefed..4b55efe28 100644 --- a/lib/steep/ast/types/var.rb +++ b/lib/steep/ast/types/var.rb @@ -3,11 +3,9 @@ module AST module Types class Var attr_reader :name - attr_reader :location - def initialize(name:, location: nil) + def initialize(name:) @name = name - @location = location end def ==(other) @@ -33,7 +31,7 @@ def self.fresh_name(name) end def self.fresh(name, location: nil) - new(name: fresh_name(name), location: location) + new(name: fresh_name(name)) end def to_s @@ -58,15 +56,8 @@ def level [0] end - def update(name: self.name, location: self.location) - self.class.new( - name: name, - location: location - ) - end - - def with_location(new_location) - update(location: new_location) + def update(name: self.name) + self.class.new(name: name) end end end diff --git a/lib/steep/ast/types/void.rb b/lib/steep/ast/types/void.rb index 887aa6d3e..5dd0967e5 100644 --- a/lib/steep/ast/types/void.rb +++ b/lib/steep/ast/types/void.rb @@ -2,12 +2,6 @@ module Steep module AST module Types class Void - attr_reader :location - - def initialize(location: nil) - @location = location - end - def ==(other) other.is_a?(Void) end @@ -33,10 +27,6 @@ def to_s def level [0] end - - def with_location(new_location) - self.class.new(location: new_location) - end end end end diff --git a/lib/steep/diagnostic/ruby.rb b/lib/steep/diagnostic/ruby.rb index e7c9094dd..f8b528451 100644 --- a/lib/steep/diagnostic/ruby.rb +++ b/lib/steep/diagnostic/ruby.rb @@ -904,8 +904,8 @@ def header_line class UnexpectedTypeArgument < Base attr_reader :type_arg, :method_type - def initialize(type_arg:, method_type:) - super(node: nil, location: type_arg.location) + def initialize(type_arg:, method_type:, location:) + super(node: nil, location: location) @type_arg = type_arg @method_type = method_type end diff --git a/lib/steep/interface/builder.rb b/lib/steep/interface/builder.rb index 9a2f49ec8..7d6a554b0 100644 --- a/lib/steep/interface/builder.rb +++ b/lib/steep/interface/builder.rb @@ -423,7 +423,7 @@ def subtyping 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 @@ -582,10 +582,9 @@ def tuple_shape(tuple) 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 @@ -598,7 +597,7 @@ def record_shape(record) method_name: :[], private_method: false, overloads: record.elements.map do |key_value, value_type| - key_type = AST::Types::Literal.new(value: key_value, location: nil) + key_type = AST::Types::Literal.new(value: key_value) Shape::MethodOverload.new( MethodType.new( @@ -623,7 +622,7 @@ def record_shape(record) method_name: :[]=, private_method: false, overloads: record.elements.map do |key_value, value_type| - key_type = AST::Types::Literal.new(value: key_value, location: nil) + key_type = AST::Types::Literal.new(value: key_value) Shape::MethodOverload.new( MethodType.new( type_params: [], @@ -646,7 +645,7 @@ def record_shape(record) method_name: :fetch, private_method: false, overloads: record.elements.flat_map {|key_value, value_type| - key_type = AST::Types::Literal.new(value: key_value, location: nil) + key_type = AST::Types::Literal.new(value: key_value) [ MethodType.new( @@ -728,7 +727,7 @@ def replace_primitive_method(method_name, method_def, method_type) 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.new() ) ) end @@ -742,7 +741,7 @@ def replace_primitive_method(method_name, method_def, method_type) 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.new() ) ) end @@ -756,7 +755,7 @@ def replace_primitive_method(method_name, method_def, method_type) 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.new() ) ) end @@ -766,7 +765,7 @@ def replace_primitive_method(method_name, method_def, method_type) 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.new() ) ) when RBS::BuiltinNames::Object.name, @@ -780,7 +779,7 @@ def replace_primitive_method(method_name, method_def, method_type) # 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.new() ) ) end @@ -789,7 +788,7 @@ def replace_primitive_method(method_name, method_def, method_type) 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.new() ) ) end diff --git a/lib/steep/services/completion_provider.rb b/lib/steep/services/completion_provider.rb index 02dde7ccd..5a82b6602 100644 --- a/lib/steep/services/completion_provider.rb +++ b/lib/steep/services/completion_provider.rb @@ -792,7 +792,7 @@ def disallowed_method?(name) def unwrap_optional(type) if type.is_a?(AST::Types::Union) && type.types.include?(AST::Builtin.nil_type) types = type.types.reject { |t| t == AST::Builtin.nil_type } - AST::Types::Union.new(types: types, location: type.location) + AST::Types::Union.new(types: types) else type end diff --git a/lib/steep/services/hover_provider/ruby.rb b/lib/steep/services/hover_provider/ruby.rb index bb0fb519f..cb62c1fcb 100644 --- a/lib/steep/services/hover_provider/ruby.rb +++ b/lib/steep/services/hover_provider/ruby.rb @@ -120,7 +120,7 @@ def content_for(target:, path:, line:, column:) when :lvar var_name = node.children[0] context = typing.cursor_context.context or raise - var_type = context.type_env[var_name] || AST::Types::Any.new(location: nil) + var_type = context.type_env[var_name] || AST::Types::Any.new() return VariableContent.new( node: node, diff --git a/lib/steep/signature/validator.rb b/lib/steep/signature/validator.rb index 354d0201e..01b2101b0 100644 --- a/lib/steep/signature/validator.rb +++ b/lib/steep/signature/validator.rb @@ -162,9 +162,9 @@ def ancestor_to_type(ancestor) case when ancestor.name.interface? - AST::Types::Name::Interface.new(name: ancestor.name, args: args, location: nil) + AST::Types::Name::Interface.new(name: ancestor.name, args: args) when ancestor.name.class? - AST::Types::Name::Instance.new(name: ancestor.name, args: args, location: nil) + AST::Types::Name::Instance.new(name: ancestor.name, args: args) else raise "#{ancestor.name}" end @@ -181,7 +181,7 @@ def mixin_constraints(definition, mixin_ancestors, immediate_self_types:) if immediate_self_types && !immediate_self_types.empty? # @type var sts: Array[AST::Types::t] sts = immediate_self_types.map {|st| ancestor_to_type(st) } - self_type = AST::Types::Intersection.build(types: sts.push(self_type), location: nil) + self_type = AST::Types::Intersection.build(types: sts.push(self_type)) end mixin_ancestors.each do |ancestor| @@ -255,11 +255,10 @@ def validate_one_class_decl(name, entry) rescue_validation_errors(name) do Steep.logger.debug { "Validating class definition `#{name}`..." } - class_type = AST::Types::Name::Singleton.new(name: name, location: nil) + class_type = AST::Types::Name::Singleton.new(name: name) instance_type = AST::Types::Name::Instance.new( name: name, - args: entry.type_params.map { AST::Types::Any.new(location: nil) }, - location: nil + args: entry.type_params.map { AST::Types::Any.new() } ) Steep.logger.tagged "#{name}" do @@ -270,8 +269,7 @@ def validate_one_class_decl(name, entry) self_type = AST::Types::Name::Instance.new( name: name, - args: entry.type_params.map { AST::Types::Var.new(name: _1.name) }, - location: nil + args: entry.type_params.map { AST::Types::Var.new(name: _1.name) } ) push_context(self_type: self_type, class_type: class_type, instance_type: instance_type) do @@ -487,8 +485,7 @@ def validate_one_interface(name) self_type = AST::Types::Name::Interface.new( name: name, - args: definition.type_params.map { AST::Types::Var.new(name: _1) }, - location: nil + args: definition.type_params.map { AST::Types::Var.new(name: _1) } ) push_context(self_type: self_type, class_type: nil, instance_type: nil) do @@ -561,11 +558,10 @@ def validate_one_global(name, entry) def validate_one_alias(name, entry = env.type_alias_decls[name]) *, inner_most_outer_module = entry.outer if inner_most_outer_module - class_type = AST::Types::Name::Singleton.new(name: inner_most_outer_module.name, location: nil) + class_type = AST::Types::Name::Singleton.new(name: inner_most_outer_module.name) instance_type = AST::Types::Name::Instance.new( name: inner_most_outer_module.name, - args: inner_most_outer_module.type_params.map { AST::Types::Any.new(location: nil) }, - location: nil + args: inner_most_outer_module.type_params.map { AST::Types::Any.new() }, ) end diff --git a/lib/steep/subtyping/check.rb b/lib/steep/subtyping/check.rb index 5dff60815..21e0a31f7 100644 --- a/lib/steep/subtyping/check.rb +++ b/lib/steep/subtyping/check.rb @@ -129,20 +129,17 @@ def instance_super_types(type_name, args:) if ancestor.name.class? AST::Types::Name::Instance.new( name: name, - args: args, - location: nil + args: args ) else AST::Types::Name::Interface.new( name: name, - args: args, - location: nil + args: args ) end when RBS::Definition::Ancestor::Singleton AST::Types::Name::Singleton.new( - name: name, - location: nil + name: name ) end end @@ -163,20 +160,17 @@ def singleton_super_types(type_name) if ancestor.name.class? AST::Types::Name::Instance.new( name: name, - args: args, - location: nil + args: args ) else AST::Types::Name::Interface.new( name: name, - args: args, - location: nil + args: args ) end when RBS::Definition::Ancestor::Singleton AST::Types::Name::Singleton.new( - name: name, - location: nil + name: name ) end end @@ -497,8 +491,7 @@ def check_type0(relation) Expand(relation) do tuple_element_type = AST::Types::Union.build( - types: relation.sub_type.types, - location: relation.sub_type.location + types: relation.sub_type.types ) check_type(Relation.new(sub_type: tuple_element_type, super_type: super_type.args[0])) diff --git a/lib/steep/subtyping/constraints.rb b/lib/steep/subtyping/constraints.rb index 4da9bfa36..dbbad2124 100644 --- a/lib/steep/subtyping/constraints.rb +++ b/lib/steep/subtyping/constraints.rb @@ -149,7 +149,7 @@ def eliminate_variable(type, to:) type.args.map do |ty| eliminate_variable(ty, to: AST::Types::Any.new) end.yield_self do |args| - type.class.new(name: type.name, args: args, location: type.location) + type.class.new(name: type.name, args: args) end when AST::Types::Union type.types.map do |ty| @@ -171,13 +171,11 @@ def eliminate_variable(type, to:) end when AST::Types::Tuple AST::Types::Tuple.new( - types: type.types.map {|ty| eliminate_variable(ty, to: AST::Builtin.any_type) }, - location: type.location + types: type.types.map {|ty| eliminate_variable(ty, to: AST::Builtin.any_type) } ) when AST::Types::Record AST::Types::Record.new( - elements: type.elements.transform_values {|ty| eliminate_variable(ty, to: AST::Builtin.any_type) }, - location: type.location + elements: type.elements.transform_values {|ty| eliminate_variable(ty, to: AST::Builtin.any_type) } ) when AST::Types::Proc type.map_type {|ty| eliminate_variable(ty, to: AST::Builtin.any_type) } diff --git a/lib/steep/type_construction.rb b/lib/steep/type_construction.rb index 593880b48..96b7babe4 100644 --- a/lib/steep/type_construction.rb +++ b/lib/steep/type_construction.rb @@ -2449,7 +2449,6 @@ def synthesize(node, hint: nil, condition: false) if block_type = method_context!.block_type type = AST::Types::Proc.new( type: block_type.type, - location: nil, block: nil, self_type: block_type.self_type ) @@ -3872,8 +3871,9 @@ def try_method_type(node, receiver_type:, method_name:, method_overload:, argume type_args.drop(type_arity).each do |type_arg| constr.typing.add_error( Diagnostic::Ruby::UnexpectedTypeArgument.new( - type_arg: type_arg, - method_type: method_type + type_arg: type_arg.value, + method_type: method_type, + location: type_arg.location ) ) end @@ -3883,7 +3883,7 @@ def try_method_type(node, receiver_type:, method_name:, method_overload:, argume constr.typing.add_error( Diagnostic::Ruby::InsufficientTypeArgument.new( node: tapp.node, - type_args: type_args, + type_args: type_args.map(&:value), method_type: method_type ) ) @@ -4765,7 +4765,7 @@ def test_literal_type(literal, hint) when AST::Types::Any nil else - literal_type = AST::Types::Literal.new(value: literal, location: nil) + literal_type = AST::Types::Literal.new(value: literal) if check_relation(sub_type: literal_type, super_type: hint).success? hint end diff --git a/lib/steep/type_inference/method_params.rb b/lib/steep/type_inference/method_params.rb index 253324d3a..ddb81f489 100644 --- a/lib/steep/type_inference/method_params.rb +++ b/lib/steep/type_inference/method_params.rb @@ -114,7 +114,7 @@ def var_type proc_type = AST::Types::Proc.new(type: type, block: nil, self_type: self_type) if optional? - AST::Types::Union.build(types: [proc_type, AST::Builtin.nil_type], location: proc_type.location) + AST::Types::Union.build(types: [proc_type, AST::Builtin.nil_type]) else proc_type end diff --git a/sig/steep/ast/types/any.rbs b/sig/steep/ast/types/any.rbs index a00ae3c5e..baa776261 100644 --- a/sig/steep/ast/types/any.rbs +++ b/sig/steep/ast/types/any.rbs @@ -2,10 +2,6 @@ module Steep module AST module Types class Any - attr_reader location: untyped - - def initialize: (?location: untyped?) -> void - def ==: (untyped other) -> bool def hash: () -> Integer @@ -21,8 +17,6 @@ module Steep include Helper::NoChild def level: () -> Array[Integer] - - def with_location: (untyped new_location) -> Any end end end diff --git a/sig/steep/ast/types/boolean.rbs b/sig/steep/ast/types/boolean.rbs index 151f3248f..d9cb87ba8 100644 --- a/sig/steep/ast/types/boolean.rbs +++ b/sig/steep/ast/types/boolean.rbs @@ -2,10 +2,6 @@ module Steep module AST module Types class Boolean - attr_reader location: untyped - - def initialize: (?location: untyped?) -> void - def ==: (untyped other) -> bool def hash: () -> Integer @@ -22,8 +18,6 @@ module Steep def level: () -> Array[Integer] - def with_location: (untyped new_location) -> Boolean - def back_type: () -> t end end diff --git a/sig/steep/ast/types/bot.rbs b/sig/steep/ast/types/bot.rbs index 6213cbc60..ecb4ba573 100644 --- a/sig/steep/ast/types/bot.rbs +++ b/sig/steep/ast/types/bot.rbs @@ -2,10 +2,6 @@ module Steep module AST module Types class Bot - attr_reader location: untyped - - def initialize: (?location: untyped?) -> void - def ==: (untyped other) -> bool def hash: () -> Integer @@ -21,8 +17,6 @@ module Steep include Helper::NoChild def level: () -> Array[Integer] - - def with_location: (untyped new_location) -> Bot end end end diff --git a/sig/steep/ast/types/class.rbs b/sig/steep/ast/types/class.rbs index ede6f89ff..103be44d7 100644 --- a/sig/steep/ast/types/class.rbs +++ b/sig/steep/ast/types/class.rbs @@ -2,10 +2,6 @@ module Steep module AST module Types class Class - attr_reader location: untyped - - def initialize: (?location: untyped?) -> void - def to_s: () -> String def ==: (untyped other) -> bool @@ -23,8 +19,6 @@ module Steep def level: () -> Array[Integer] - def with_location: (untyped new_location) -> Class - self.@instance: Class def self.instance: () -> Class end diff --git a/sig/steep/ast/types/factory.rbs b/sig/steep/ast/types/factory.rbs index 961cb4d92..42f9f6d8b 100644 --- a/sig/steep/ast/types/factory.rbs +++ b/sig/steep/ast/types/factory.rbs @@ -97,7 +97,7 @@ module Steep def absolute_type_name: (TypeName type_name, context: RBS::Resolver::context) -> TypeName? - def instance_type: (TypeName type_name, ?args: Array[t]?, ?location: untyped?) -> t + def instance_type: (TypeName type_name, ?args: Array[t]?) -> t def try_singleton_type: (t) -> t? diff --git a/sig/steep/ast/types/instance.rbs b/sig/steep/ast/types/instance.rbs index 9d232ce43..4c0934317 100644 --- a/sig/steep/ast/types/instance.rbs +++ b/sig/steep/ast/types/instance.rbs @@ -2,10 +2,6 @@ module Steep module AST module Types class Instance - attr_reader location: untyped - - def initialize: (?location: untyped?) -> void - def ==: (untyped other) -> bool def hash: () -> Integer @@ -23,8 +19,6 @@ module Steep def level: () -> Array[Integer] - def with_location: (untyped new_location) -> untyped - self.@instance: Instance def self.instance: () -> Instance end diff --git a/sig/steep/ast/types/intersection.rbs b/sig/steep/ast/types/intersection.rbs index 45cadfe44..aadd1e62b 100644 --- a/sig/steep/ast/types/intersection.rbs +++ b/sig/steep/ast/types/intersection.rbs @@ -4,11 +4,9 @@ module Steep class Intersection attr_reader types: Array[t] - attr_reader location: untyped + def initialize: (types: Array[t]) -> void - def initialize: (types: Array[t], ?location: untyped?) -> void - - def self.build: (types: Array[t], ?location: untyped?) -> t + def self.build: (types: Array[t]) -> t def ==: (untyped other) -> bool @@ -32,8 +30,6 @@ module Steep def map_type: () { (t) -> t } -> t def level: () -> Array[Integer] - - def with_location: (untyped new_location) -> Intersection end end end diff --git a/sig/steep/ast/types/literal.rbs b/sig/steep/ast/types/literal.rbs index 8c5c0bd7a..0f5e4cc5a 100644 --- a/sig/steep/ast/types/literal.rbs +++ b/sig/steep/ast/types/literal.rbs @@ -2,13 +2,11 @@ module Steep module AST module Types class Literal - attr_reader location: untyped - type value = Integer | String | Symbol | TrueClass | FalseClass attr_reader value: value - def initialize: (value: value, ?location: untyped?) -> void + def initialize: (value: value) -> void def ==: (untyped other) -> bool @@ -26,8 +24,6 @@ module Steep def level: () -> Array[Integer] - def with_location: (untyped new_location) -> Literal - def back_type: () -> AST::Types::Name::Instance end end diff --git a/sig/steep/ast/types/logic.rbs b/sig/steep/ast/types/logic.rbs index 7bbef5b8c..20e23eff7 100644 --- a/sig/steep/ast/types/logic.rbs +++ b/sig/steep/ast/types/logic.rbs @@ -3,8 +3,6 @@ module Steep module Types module Logic class Base - attr_reader location: untyped - def subst: (Interface::Substitution s) -> self include Helper::NoFreeVariables @@ -24,37 +22,30 @@ module Steep # A type for `!` (not) operator results. class Not < Base - def initialize: (?location: untyped?) -> void end # A type for `foo.nil?` call results. class ReceiverIsNil < Base - def initialize: (?location: untyped?) -> void end # class ReceiverIsNotNil < Base - def initialize: (?location: untyped?) -> void end # A type for `receiver.is_a?(C)` call results. class ReceiverIsArg < Base - def initialize: (?location: untyped?) -> void end # A type for `Class#===` call results. class ArgIsReceiver < Base - def initialize: (?location: untyped?) -> void end # A type for `Object#===` call results. class ArgEqualsReceiver < Base - def initialize: (?location: untyped?) -> void end # A type for `Class#<` or `Class#<=` call results. class ArgIsAncestor < Base - def initialize: (?location: untyped?) -> void end # A type with truthy/falsy type environment. @@ -65,7 +56,7 @@ module Steep attr_reader type: t - def initialize: (truthy: TypeInference::TypeEnv, falsy: TypeInference::TypeEnv, type: t, ?location: untyped) -> void + def initialize: (truthy: TypeInference::TypeEnv, falsy: TypeInference::TypeEnv, type: t) -> void def ==: (untyped other) -> bool diff --git a/sig/steep/ast/types/name.rbs b/sig/steep/ast/types/name.rbs index bdcda8132..e06cf22cc 100644 --- a/sig/steep/ast/types/name.rbs +++ b/sig/steep/ast/types/name.rbs @@ -5,11 +5,9 @@ module Steep # module Name class Base - attr_reader location: untyped - attr_reader name: RBS::TypeName - def initialize: (name: RBS::TypeName, ?location: untyped?) -> void + def initialize: (name: RBS::TypeName) -> void include Helper::NoFreeVariables @@ -23,7 +21,7 @@ module Steep class Applying < Base attr_reader args: Array[t] - def initialize: (name: RBS::TypeName, args: Array[t], ?location: untyped?) -> void + def initialize: (name: RBS::TypeName, args: Array[t]) -> void def ==: (untyped other) -> bool @@ -34,8 +32,6 @@ module Steep def to_s: () -> ::String - def with_location: (untyped new_location) -> self - def subst: (Steep::Interface::Substitution s) -> self @fvs: Set[variable] @@ -61,8 +57,6 @@ module Steep def to_s: () -> ::String - def with_location: (untyped new_location) -> Singleton - include Helper::NoChild end diff --git a/sig/steep/ast/types/nil.rbs b/sig/steep/ast/types/nil.rbs index da0f023f5..aadcffbdb 100644 --- a/sig/steep/ast/types/nil.rbs +++ b/sig/steep/ast/types/nil.rbs @@ -2,10 +2,6 @@ module Steep module AST module Types class Nil - attr_reader location: untyped - - def initialize: (?location: untyped?) -> void - def ==: (untyped other) -> bool def hash: () -> Integer @@ -22,8 +18,6 @@ module Steep def level: () -> Array[Integer] - def with_location: (untyped new_location) -> Nil - def back_type: () -> Name::Instance end end diff --git a/sig/steep/ast/types/proc.rbs b/sig/steep/ast/types/proc.rbs index 1f2f64151..9367ef9af 100644 --- a/sig/steep/ast/types/proc.rbs +++ b/sig/steep/ast/types/proc.rbs @@ -2,15 +2,13 @@ module Steep module AST module Types class Proc - attr_reader location: untyped - attr_reader type: Interface::Function attr_reader self_type: AST::Types::t? attr_reader block: Interface::Block? - def initialize: (type: Interface::Function, self_type: AST::Types::t?, block: Interface::Block?, ?location: untyped) -> void + def initialize: (type: Interface::Function, self_type: AST::Types::t?, block: Interface::Block?) -> void def ==: (untyped other) -> bool @@ -29,8 +27,6 @@ module Steep def level: () -> Array[Integer] - def with_location: (untyped new_location) -> Proc - def map_type: () { (AST::Types::t) -> AST::Types::t } -> Proc # Returns true if the proc requires exactly one argument diff --git a/sig/steep/ast/types/record.rbs b/sig/steep/ast/types/record.rbs index a2292e0ac..77b83f2ee 100644 --- a/sig/steep/ast/types/record.rbs +++ b/sig/steep/ast/types/record.rbs @@ -4,11 +4,9 @@ module Steep class Record type key = Symbol | String | Integer - attr_reader location: untyped - attr_reader elements: Hash[key, t] - def initialize: (elements: Hash[key, t], ?location: untyped) -> void + def initialize: (elements: Hash[key, t]) -> void def ==: (untyped other) -> bool @@ -31,8 +29,6 @@ module Steep def map_type: () { (t) -> t } -> Record def level: () -> Array[Integer] - - def with_location: (untyped new_location) -> Record end end end diff --git a/sig/steep/ast/types/self.rbs b/sig/steep/ast/types/self.rbs index 2ea932707..a2d707dec 100644 --- a/sig/steep/ast/types/self.rbs +++ b/sig/steep/ast/types/self.rbs @@ -2,10 +2,6 @@ module Steep module AST module Types class Self - attr_reader location: untyped - - def initialize: (?location: untyped?) -> void - def ==: (untyped other) -> bool def hash: () -> Integer @@ -23,8 +19,6 @@ module Steep def level: () -> Array[Integer] - def with_location: (untyped new_location) -> Self - self.@instance: Self def self.instance: () -> Self end diff --git a/sig/steep/ast/types/top.rbs b/sig/steep/ast/types/top.rbs index fc5790108..dad875c3e 100644 --- a/sig/steep/ast/types/top.rbs +++ b/sig/steep/ast/types/top.rbs @@ -2,10 +2,6 @@ module Steep module AST module Types class Top - attr_reader location: untyped - - def initialize: (?location: untyped?) -> void - def ==: (untyped other) -> bool def hash: () -> Integer @@ -21,8 +17,6 @@ module Steep include Helper::NoChild def level: () -> Array[Integer] - - def with_location: (untyped new_location) -> Top end end end diff --git a/sig/steep/ast/types/tuple.rbs b/sig/steep/ast/types/tuple.rbs index 3d5500874..f727d0590 100644 --- a/sig/steep/ast/types/tuple.rbs +++ b/sig/steep/ast/types/tuple.rbs @@ -4,9 +4,7 @@ module Steep class Tuple attr_reader types: Array[t] - attr_reader location: untyped - - def initialize: (types: Array[t], ?location: untyped) -> void + def initialize: (types: Array[t]) -> void def ==: (untyped other) -> bool @@ -29,8 +27,6 @@ module Steep def map_type: () { (t) -> t } -> Tuple def level: () -> Array[Integer] - - def with_location: (untyped new_location) -> Tuple end end end diff --git a/sig/steep/ast/types/union.rbs b/sig/steep/ast/types/union.rbs index b09d415a1..ff627e705 100644 --- a/sig/steep/ast/types/union.rbs +++ b/sig/steep/ast/types/union.rbs @@ -4,11 +4,9 @@ module Steep class Union attr_reader types: Array[t] - attr_reader location: untyped + def initialize: (types: Array[t]) -> void - def initialize: (types: Array[t], ?location: untyped) -> void - - def self.build: (types: Array[t], ?location: untyped) -> t + def self.build: (types: Array[t]) -> t def ==: (untyped other) -> bool @@ -32,8 +30,6 @@ module Steep include Helper::ChildrenLevel def level: () -> Array[Integer] - - def with_location: (untyped new_location) -> Union end end end diff --git a/sig/steep/ast/types/var.rbs b/sig/steep/ast/types/var.rbs index 14b097ff6..5027f2c66 100644 --- a/sig/steep/ast/types/var.rbs +++ b/sig/steep/ast/types/var.rbs @@ -5,9 +5,7 @@ module Steep class Var attr_reader name: Symbol - attr_reader location: untyped - - def initialize: (name: Symbol, ?location: untyped?) -> void + def initialize: (name: Symbol) -> void def ==: (untyped other) -> bool @@ -33,9 +31,7 @@ module Steep def level: () -> Array[Integer] - def update: (?name: Symbol, ?location: untyped) -> Var - - def with_location: (untyped new_location) -> Var + def update: (?name: Symbol) -> Var end end end diff --git a/sig/steep/ast/types/void.rbs b/sig/steep/ast/types/void.rbs index 63c9130ba..c7422312e 100644 --- a/sig/steep/ast/types/void.rbs +++ b/sig/steep/ast/types/void.rbs @@ -2,10 +2,6 @@ module Steep module AST module Types class Void - attr_reader location: untyped - - def initialize: (?location: untyped?) -> void - def ==: (untyped other) -> bool def hash: () -> Integer @@ -21,8 +17,6 @@ module Steep include Helper::NoChild def level: () -> Array[Integer] - - def with_location: (untyped new_location) -> Void end end end diff --git a/sig/steep/diagnostic/ruby.rbs b/sig/steep/diagnostic/ruby.rbs index af0dacdaf..8206d7704 100644 --- a/sig/steep/diagnostic/ruby.rbs +++ b/sig/steep/diagnostic/ruby.rbs @@ -578,7 +578,7 @@ module Steep def node: () -> nil - def initialize: (type_arg: AST::Types::t, method_type: Interface::MethodType) -> void + def initialize: (type_arg: AST::Types::t, method_type: Interface::MethodType, location: RBS::Location[untyped, untyped]) -> void def header_line: () -> String end diff --git a/test/test_helper.rb b/test/test_helper.rb index 1ce4cf3e3..2fd45150f 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -24,14 +24,14 @@ Rainbow.enabled = false module Steep::AST::Types::Name - def self.new_singleton(name:, location: nil) + def self.new_singleton(name:) name = TypeName(name.to_s) unless name.is_a?(RBS::TypeName) - Steep::AST::Types::Name::Singleton.new(name: name, location: location) + Steep::AST::Types::Name::Singleton.new(name: name) end - def self.new_instance(location: nil, name:, args: []) + def self.new_instance(name:, args: []) name = TypeName(name.to_s) unless name.is_a?(RBS::TypeName) - Steep::AST::Types::Name::Instance.new(location: location, name: name, args: args) + Steep::AST::Types::Name::Instance.new(name: name, args: args) end end From 32db7bd7fd78e2f7f62f926a3a0b58a7d9c36dbd Mon Sep 17 00:00:00 2001 From: Soutaro Matsumoto Date: Thu, 8 Aug 2024 17:04:04 +0900 Subject: [PATCH 5/5] Use shared instance --- lib/steep.rb | 1 + lib/steep/ast/builtin.rb | 10 ++++----- lib/steep/ast/types/any.rb | 2 ++ lib/steep/ast/types/boolean.rb | 2 ++ lib/steep/ast/types/bot.rb | 2 ++ lib/steep/ast/types/class.rb | 4 +--- lib/steep/ast/types/factory.rb | 22 +++++++++---------- lib/steep/ast/types/instance.rb | 8 +------ lib/steep/ast/types/intersection.rb | 6 ++--- lib/steep/ast/types/logic.rb | 2 ++ lib/steep/ast/types/nil.rb | 2 ++ lib/steep/ast/types/self.rb | 4 +--- lib/steep/ast/types/shared_instance.rb | 11 ++++++++++ lib/steep/ast/types/top.rb | 2 ++ lib/steep/ast/types/union.rb | 8 +++---- lib/steep/ast/types/void.rb | 2 ++ lib/steep/interface/builder.rb | 12 +++++----- lib/steep/interface/method_type.rb | 4 ++-- lib/steep/services/hover_provider/ruby.rb | 2 +- lib/steep/signature/validator.rb | 4 ++-- lib/steep/subtyping/constraints.rb | 16 +++++++------- lib/steep/type_construction.rb | 22 +++++++++---------- lib/steep/type_inference/block_params.rb | 12 +++++----- .../type_inference/logic_type_interpreter.rb | 14 ++++++------ lib/steep/type_inference/method_call.rb | 6 ++--- sig/steep/ast/types/any.rbs | 2 ++ sig/steep/ast/types/boolean.rbs | 2 ++ sig/steep/ast/types/bot.rbs | 2 ++ sig/steep/ast/types/class.rbs | 5 ++--- sig/steep/ast/types/instance.rbs | 5 ++--- sig/steep/ast/types/logic.rbs | 4 ++++ sig/steep/ast/types/nil.rbs | 2 ++ sig/steep/ast/types/self.rbs | 5 ++--- sig/steep/ast/types/shared_instance.rbs | 13 +++++++++++ sig/steep/ast/types/top.rbs | 2 ++ sig/steep/ast/types/void.rbs | 2 ++ 36 files changed, 133 insertions(+), 91 deletions(-) create mode 100644 lib/steep/ast/types/shared_instance.rb create mode 100644 sig/steep/ast/types/shared_instance.rbs diff --git a/lib/steep.rb b/lib/steep.rb index 83d9b350c..4710cbc1f 100644 --- a/lib/steep.rb +++ b/lib/steep.rb @@ -27,6 +27,7 @@ require "steep/equatable" require "steep/method_name" require "steep/node_helper" +require "steep/ast/types/shared_instance" require "steep/ast/types/helper" require "steep/ast/types/any" require "steep/ast/types/instance" diff --git a/lib/steep/ast/builtin.rb b/lib/steep/ast/builtin.rb index aa4628322..77f62adb9 100644 --- a/lib/steep/ast/builtin.rb +++ b/lib/steep/ast/builtin.rb @@ -67,23 +67,23 @@ def module_type?(type) Proc = Type.new("::Proc") def self.nil_type - AST::Types::Nil.new + AST::Types::Nil.instance end def self.any_type - AST::Types::Any.new + AST::Types::Any.instance end def self.bool_type - AST::Types::Boolean.new + AST::Types::Boolean.instance end def self.bottom_type - AST::Types::Bot.new + AST::Types::Bot.instance end def self.top_type - AST::Types::Top.new + AST::Types::Top.instance end def self.optional(type) diff --git a/lib/steep/ast/types/any.rb b/lib/steep/ast/types/any.rb index 15bdee825..16d447f48 100644 --- a/lib/steep/ast/types/any.rb +++ b/lib/steep/ast/types/any.rb @@ -2,6 +2,8 @@ module Steep module AST module Types class Any + extend SharedInstance + def ==(other) other.is_a?(Any) end diff --git a/lib/steep/ast/types/boolean.rb b/lib/steep/ast/types/boolean.rb index f8b54ad04..77d269716 100644 --- a/lib/steep/ast/types/boolean.rb +++ b/lib/steep/ast/types/boolean.rb @@ -2,6 +2,8 @@ module Steep module AST module Types class Boolean + extend SharedInstance + def ==(other) other.is_a?(Boolean) end diff --git a/lib/steep/ast/types/bot.rb b/lib/steep/ast/types/bot.rb index 657385598..d31057ce6 100644 --- a/lib/steep/ast/types/bot.rb +++ b/lib/steep/ast/types/bot.rb @@ -2,6 +2,8 @@ module Steep module AST module Types class Bot + extend SharedInstance + def ==(other) other.is_a?(Bot) end diff --git a/lib/steep/ast/types/class.rb b/lib/steep/ast/types/class.rb index 43525e749..39a80ae6e 100644 --- a/lib/steep/ast/types/class.rb +++ b/lib/steep/ast/types/class.rb @@ -2,9 +2,7 @@ module Steep module AST module Types class Class - def self.instance - @instance ||= new() - end + extend SharedInstance def to_s "class" diff --git a/lib/steep/ast/types/factory.rb b/lib/steep/ast/types/factory.rb index be46001e3..263328086 100644 --- a/lib/steep/ast/types/factory.rb +++ b/lib/steep/ast/types/factory.rb @@ -44,23 +44,23 @@ def type(type) type_cache[type] = case type when RBS::Types::Bases::Any - Any.new() + Any.instance when RBS::Types::Bases::Class - Class.new() + Class.instance when RBS::Types::Bases::Instance - Instance.new() + Instance.instance when RBS::Types::Bases::Self - Self.new() + Self.instance when RBS::Types::Bases::Top - Top.new() + Top.instance when RBS::Types::Bases::Bottom - Bot.new() + Bot.instance when RBS::Types::Bases::Bool - Boolean.new() + Boolean.instance when RBS::Types::Bases::Void - Void.new() + Void.instance when RBS::Types::Bases::Nil - Nil.new() + Nil.instance when RBS::Types::Variable Var.new(name: type.name) when RBS::Types::ClassSingleton @@ -83,7 +83,7 @@ def type(type) when RBS::Types::Intersection Intersection.build(types: type.types.map {|ty| type(ty) }) when RBS::Types::Optional - Union.build(types: [type(type.type), Nil.new()]) + Union.build(types: [type(type.type), Nil.instance()]) when RBS::Types::Literal Literal.new(value: type.literal) when RBS::Types::Tuple @@ -444,7 +444,7 @@ def instance_type(type_name, args: nil) raise unless type_name.class? definition = definition_builder.build_singleton(type_name) - def_args = definition.type_params.map { Any.new() } + def_args = definition.type_params.map { Any.instance } if args raise if def_args.size != args.size diff --git a/lib/steep/ast/types/instance.rb b/lib/steep/ast/types/instance.rb index 3ad478de6..ed085900b 100644 --- a/lib/steep/ast/types/instance.rb +++ b/lib/steep/ast/types/instance.rb @@ -2,9 +2,7 @@ module Steep module AST module Types class Instance - def self.instance - @instance ||= new() - end + extend SharedInstance def ==(other) other.is_a?(Instance) @@ -38,10 +36,6 @@ def to_s def level [0] end - - def with_location(new_location) - self.class.new() - end end end end diff --git a/lib/steep/ast/types/intersection.rb b/lib/steep/ast/types/intersection.rb index 155b89ad1..ee4f1edc0 100644 --- a/lib/steep/ast/types/intersection.rb +++ b/lib/steep/ast/types/intersection.rb @@ -18,9 +18,9 @@ def self.build(types:) end.map do |type| case type when AST::Types::Any - return AST::Types::Any.new() + return AST::Types::Any.instance() when AST::Types::Bot - return AST::Types::Bot.new() + return AST::Types::Bot.instance when AST::Types::Top nil else @@ -31,7 +31,7 @@ def self.build(types:) case dups.size when 0 - AST::Types::Top.new() + AST::Types::Top.instance when 1 tys.first || raise else diff --git a/lib/steep/ast/types/logic.rb b/lib/steep/ast/types/logic.rb index 101661b83..6a9408379 100644 --- a/lib/steep/ast/types/logic.rb +++ b/lib/steep/ast/types/logic.rb @@ -3,6 +3,8 @@ module AST module Types module Logic class Base + extend SharedInstance + def subst(s) self end diff --git a/lib/steep/ast/types/nil.rb b/lib/steep/ast/types/nil.rb index 83b689919..24134490e 100644 --- a/lib/steep/ast/types/nil.rb +++ b/lib/steep/ast/types/nil.rb @@ -2,6 +2,8 @@ module Steep module AST module Types class Nil + extend SharedInstance + def ==(other) other.is_a?(Nil) end diff --git a/lib/steep/ast/types/self.rb b/lib/steep/ast/types/self.rb index ad54935f4..59e7cabe4 100644 --- a/lib/steep/ast/types/self.rb +++ b/lib/steep/ast/types/self.rb @@ -2,9 +2,7 @@ module Steep module AST module Types class Self - def self.instance - @instance ||= new() - end + extend SharedInstance def ==(other) other.is_a?(Self) diff --git a/lib/steep/ast/types/shared_instance.rb b/lib/steep/ast/types/shared_instance.rb new file mode 100644 index 000000000..2d3c03c55 --- /dev/null +++ b/lib/steep/ast/types/shared_instance.rb @@ -0,0 +1,11 @@ +module Steep + module AST + module Types + module SharedInstance + def instance + @instance ||= new + end + end + end + end +end diff --git a/lib/steep/ast/types/top.rb b/lib/steep/ast/types/top.rb index 886e48f18..1c69414fe 100644 --- a/lib/steep/ast/types/top.rb +++ b/lib/steep/ast/types/top.rb @@ -2,6 +2,8 @@ module Steep module AST module Types class Top + extend SharedInstance + def ==(other) other.is_a?(Top) end diff --git a/lib/steep/ast/types/union.rb b/lib/steep/ast/types/union.rb index f03504769..175bdd2cf 100644 --- a/lib/steep/ast/types/union.rb +++ b/lib/steep/ast/types/union.rb @@ -9,7 +9,7 @@ def initialize(types:) end def self.build(types:) - return AST::Types::Bot.new if types.empty? + return AST::Types::Bot.instance if types.empty? if types.size == 1 return types.first || raise end @@ -23,9 +23,9 @@ def self.build(types:) end.map do |type| case type when AST::Types::Any - return AST::Types::Any.new() + return AST::Types::Any.instance() when AST::Types::Top - return AST::Types::Top.new() + return AST::Types::Top.instance when AST::Types::Bot nil else @@ -34,7 +34,7 @@ def self.build(types:) end.compact.uniq.yield_self do |tys| case tys.size when 0 - AST::Types::Bot.new + AST::Types::Bot.instance when 1 tys.first || raise else diff --git a/lib/steep/ast/types/void.rb b/lib/steep/ast/types/void.rb index 5dd0967e5..21cc54b5d 100644 --- a/lib/steep/ast/types/void.rb +++ b/lib/steep/ast/types/void.rb @@ -2,6 +2,8 @@ module Steep module AST module Types class Void + extend SharedInstance + def ==(other) other.is_a?(Void) end diff --git a/lib/steep/interface/builder.rb b/lib/steep/interface/builder.rb index 7d6a554b0..97869fa7e 100644 --- a/lib/steep/interface/builder.rb +++ b/lib/steep/interface/builder.rb @@ -727,7 +727,7 @@ def replace_primitive_method(method_name, method_def, method_type) if member.instance? return method_type.with( type: method_type.type.with( - return_type: AST::Types::Logic::ReceiverIsArg.new() + return_type: AST::Types::Logic::ReceiverIsArg.instance() ) ) end @@ -741,7 +741,7 @@ def replace_primitive_method(method_name, method_def, method_type) if member.instance? return method_type.with( type: method_type.type.with( - return_type: AST::Types::Logic::ReceiverIsNil.new() + return_type: AST::Types::Logic::ReceiverIsNil.instance() ) ) end @@ -755,7 +755,7 @@ def replace_primitive_method(method_name, method_def, method_type) AST::Builtin::NilClass.module_name return method_type.with( type: method_type.type.with( - return_type: AST::Types::Logic::Not.new() + return_type: AST::Types::Logic::Not.instance() ) ) end @@ -765,7 +765,7 @@ def replace_primitive_method(method_name, method_def, method_type) when RBS::BuiltinNames::Module.name return method_type.with( type: method_type.type.with( - return_type: AST::Types::Logic::ArgIsReceiver.new() + return_type: AST::Types::Logic::ArgIsReceiver.instance() ) ) when RBS::BuiltinNames::Object.name, @@ -779,7 +779,7 @@ def replace_primitive_method(method_name, method_def, method_type) # 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() + return_type: AST::Types::Logic::ArgEqualsReceiver.instance() ) ) end @@ -788,7 +788,7 @@ def replace_primitive_method(method_name, method_def, method_type) when RBS::BuiltinNames::Module.name return method_type.with( type: method_type.type.with( - return_type: AST::Types::Logic::ArgIsAncestor.new() + return_type: AST::Types::Logic::ArgIsAncestor.instance() ) ) end diff --git a/lib/steep/interface/method_type.rb b/lib/steep/interface/method_type.rb index 95a2c4ad7..81e127c78 100644 --- a/lib/steep/interface/method_type.rb +++ b/lib/steep/interface/method_type.rb @@ -239,7 +239,7 @@ def |(other) when (self_self = b.self_type) && (other_self = ob.self_type) AST::Types::Union.build(types: [self_self, other_self]) when b.self_type || ob.self_type - AST::Types::Bot.new() + AST::Types::Bot.instance else nil end @@ -295,7 +295,7 @@ def &(other) when (self_self = b.self_type) && (other_self = ob.self_type) AST::Types::Intersection.build(types: [self_self, other_self]) when b.self_type || ob.self_type - AST::Types::Top.new() + AST::Types::Top.instance else nil end diff --git a/lib/steep/services/hover_provider/ruby.rb b/lib/steep/services/hover_provider/ruby.rb index cb62c1fcb..61183665d 100644 --- a/lib/steep/services/hover_provider/ruby.rb +++ b/lib/steep/services/hover_provider/ruby.rb @@ -120,7 +120,7 @@ def content_for(target:, path:, line:, column:) when :lvar var_name = node.children[0] context = typing.cursor_context.context or raise - var_type = context.type_env[var_name] || AST::Types::Any.new() + var_type = context.type_env[var_name] || AST::Types::Any.instance() return VariableContent.new( node: node, diff --git a/lib/steep/signature/validator.rb b/lib/steep/signature/validator.rb index 01b2101b0..07df36765 100644 --- a/lib/steep/signature/validator.rb +++ b/lib/steep/signature/validator.rb @@ -258,7 +258,7 @@ def validate_one_class_decl(name, entry) class_type = AST::Types::Name::Singleton.new(name: name) instance_type = AST::Types::Name::Instance.new( name: name, - args: entry.type_params.map { AST::Types::Any.new() } + args: entry.type_params.map { AST::Types::Any.instance() } ) Steep.logger.tagged "#{name}" do @@ -561,7 +561,7 @@ def validate_one_alias(name, entry = env.type_alias_decls[name]) class_type = AST::Types::Name::Singleton.new(name: inner_most_outer_module.name) instance_type = AST::Types::Name::Instance.new( name: inner_most_outer_module.name, - args: inner_most_outer_module.type_params.map { AST::Types::Any.new() }, + args: inner_most_outer_module.type_params.map { AST::Types::Any.instance() }, ) end diff --git a/lib/steep/subtyping/constraints.rb b/lib/steep/subtyping/constraints.rb index dbbad2124..8388d03a2 100644 --- a/lib/steep/subtyping/constraints.rb +++ b/lib/steep/subtyping/constraints.rb @@ -113,13 +113,13 @@ def add(var, sub_type: nil, super_type: nil, skip: false) end if super_type && !super_type.is_a?(AST::Types::Top) - type = eliminate_variable(super_type, to: AST::Types::Top.new) + type = eliminate_variable(super_type, to: AST::Types::Top.instance) supers << type skips << type if skip end if sub_type && !sub_type.is_a?(AST::Types::Bot) - type = eliminate_variable(sub_type, to: AST::Types::Bot.new) + type = eliminate_variable(sub_type, to: AST::Types::Bot.instance) subs << type skips << type if skip end @@ -147,19 +147,19 @@ def eliminate_variable(type, to:) case type when AST::Types::Name::Instance, AST::Types::Name::Alias, AST::Types::Name::Interface type.args.map do |ty| - eliminate_variable(ty, to: AST::Types::Any.new) + eliminate_variable(ty, to: AST::Types::Any.instance) end.yield_self do |args| type.class.new(name: type.name, args: args) end when AST::Types::Union type.types.map do |ty| - eliminate_variable(ty, to: AST::Types::Any.new) + eliminate_variable(ty, to: AST::Types::Any.instance) end.yield_self do |types| AST::Types::Union.build(types: types) end when AST::Types::Intersection type.types.map do |ty| - eliminate_variable(ty, to: AST::Types::Any.new) + eliminate_variable(ty, to: AST::Types::Any.instance) end.yield_self do |types| AST::Types::Intersection.build(types: types) end @@ -211,7 +211,7 @@ def upper_bound(var, skip: false) case upper_bound.size when 0 - AST::Types::Top.new + AST::Types::Top.instance when 1 upper_bound.first || raise else @@ -224,7 +224,7 @@ def lower_bound(var, skip: false) case lower_bound.size when 0 - AST::Types::Bot.new + AST::Types::Bot.instance when 1 lower_bound.first || raise else @@ -291,7 +291,7 @@ def solution(checker, variance: nil, variables:, self_type: nil, instance_type: end else vars << var - types << AST::Types::Any.new + types << AST::Types::Any.instance end end end diff --git a/lib/steep/type_construction.rb b/lib/steep/type_construction.rb index 96b7babe4..eafb4f474 100644 --- a/lib/steep/type_construction.rb +++ b/lib/steep/type_construction.rb @@ -1421,7 +1421,7 @@ def synthesize(node, hint: nil, condition: false) when condition add_typing(node, type: ty) else - add_typing(node, type: AST::Types::Boolean.new) + add_typing(node, type: AST::Types::Boolean.instance) end when :hash, :kwargs @@ -1583,10 +1583,10 @@ def synthesize(node, hint: nil, condition: false) end when :self - add_typing node, type: AST::Types::Self.new + add_typing node, type: AST::Types::Self.instance when :cbase - add_typing node, type: AST::Types::Void.new + add_typing node, type: AST::Types::Void.instance when :const yield_self do @@ -1776,8 +1776,8 @@ def synthesize(node, hint: nil, condition: false) type = union_type(left_falsy.type, right_type) unless type.is_a?(AST::Types::Any) - if check_relation(sub_type: type, super_type: AST::Types::Boolean.new).success? - type = AST::Types::Boolean.new + if check_relation(sub_type: type, super_type: AST::Types::Boolean.instance).success? + type = AST::Types::Boolean.instance end end end @@ -1834,8 +1834,8 @@ def synthesize(node, hint: nil, condition: false) type = union_type(left_truthy.type, right_type) unless type.is_a?(AST::Types::Any) - if check_relation(sub_type: type, super_type: AST::Types::Boolean.new).success? - type = AST::Types::Boolean.new + if check_relation(sub_type: type, super_type: AST::Types::Boolean.instance).success? + type = AST::Types::Boolean.instance end end end @@ -2113,7 +2113,7 @@ def synthesize(node, hint: nil, condition: false) end resbody_pairs.select! do |pair| - no_subtyping?(sub_type: pair.type, super_type: AST::Types::Bot.new) + no_subtyping?(sub_type: pair.type, super_type: AST::Types::Bot.instance) end resbody_types = resbody_pairs.map(&:type) @@ -2406,7 +2406,7 @@ def synthesize(node, hint: nil, condition: false) param_type = hint.type.params.required[0] case param_type when AST::Types::Any - type = AST::Types::Any.new + type = AST::Types::Any.instance else if method = calculate_interface(param_type, private: true)&.methods&.[](value_node.children[0]) return_types = method.method_types.filter_map do |method_type| @@ -4548,7 +4548,7 @@ def union_type_unify(*types) types = types.reject {|t| t.is_a?(AST::Types::Bot) } if types.empty? - AST::Types::Bot.new + AST::Types::Bot.instance else types.inject do |type1, type2| next type2 if type1.is_a?(AST::Types::Any) @@ -4718,7 +4718,7 @@ def type_any_rec(node, only_children: false) end def unwrap(type) - checker.factory.unwrap_optional(type) || AST::Types::Bot.new + checker.factory.unwrap_optional(type) || AST::Types::Bot.instance end def deep_expand_alias(type) diff --git a/lib/steep/type_inference/block_params.rb b/lib/steep/type_inference/block_params.rb index d9f4f6ba7..fa46970bf 100644 --- a/lib/steep/type_inference/block_params.rb +++ b/lib/steep/type_inference/block_params.rb @@ -174,7 +174,7 @@ def params_type(hint: nil) def params_type0(hint:) # @type var leadings: Array[AST::Types::t] # @type var optionals: Array[AST::Types::t] - + if hint case when leading_params.size == hint.required.size @@ -223,8 +223,8 @@ def params_type0(hint:) end end else - leadings = leading_params.map {|param| param.type || AST::Types::Any.new } - optionals = optional_params.map {|param| param.type || AST::Types::Any.new } + leadings = leading_params.map {|param| param.type || AST::Types::Any.instance } + optionals = optional_params.map {|param| param.type || AST::Types::Any.instance } if rest_param if rest_type = rest_param.type @@ -232,7 +232,7 @@ def params_type0(hint:) rest = array.args.first or raise end end - rest ||= AST::Types::Any.new + rest ||= AST::Types::Any.instance end end @@ -282,7 +282,7 @@ def zip(params_type, block, factory:) if ty zip << [param, ty] else - zip << [param, AST::Types::Nil.new] + zip << [param, AST::Types::Nil.instance] end end @@ -291,7 +291,7 @@ def zip(params_type, block, factory:) union = AST::Types::Union.build(types: types) zip << [rest_param, AST::Builtin::Array.instance_type(union)] else - zip << [rest_param, AST::Types::Nil.new] + zip << [rest_param, AST::Types::Nil.instance] end end end diff --git a/lib/steep/type_inference/logic_type_interpreter.rb b/lib/steep/type_inference/logic_type_interpreter.rb index 621bc4d1b..5f0a45665 100644 --- a/lib/steep/type_inference/logic_type_interpreter.rb +++ b/lib/steep/type_inference/logic_type_interpreter.rb @@ -36,22 +36,22 @@ def guess_type_from_method(node) method = node.children[1] case method when :is_a?, :kind_of?, :instance_of? - AST::Types::Logic::ReceiverIsArg.new + AST::Types::Logic::ReceiverIsArg.instance when :nil? - AST::Types::Logic::ReceiverIsNil.new + AST::Types::Logic::ReceiverIsNil.instance when :! - AST::Types::Logic::Not.new + AST::Types::Logic::Not.instance when :=== - AST::Types::Logic::ArgIsReceiver.new + AST::Types::Logic::ArgIsReceiver.instance end end end TRUE = AST::Types::Literal.new(value: true) FALSE = AST::Types::Literal.new(value: false) - BOOL = AST::Types::Boolean.new - BOT = AST::Types::Bot.new - UNTYPED = AST::Types::Any.new + BOOL = AST::Types::Boolean.instance + BOT = AST::Types::Bot.instance + UNTYPED = AST::Types::Any.instance def eval(env:, node:) evaluate_node(env: env, node: node) diff --git a/lib/steep/type_inference/method_call.rb b/lib/steep/type_inference/method_call.rb index 85722d8f3..dabcfc253 100644 --- a/lib/steep/type_inference/method_call.rb +++ b/lib/steep/type_inference/method_call.rb @@ -165,7 +165,7 @@ class Special < Typed 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) + super(node: node, context: context, method_name: method_name, receiver_type: AST::Types::Any.instance, return_type: AST::Types::Any.instance) end end @@ -173,7 +173,7 @@ 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) + super(node: node, context: context, method_name: method_name, receiver_type: receiver_type, return_type: AST::Types::Any.instance) @error = error end end @@ -182,7 +182,7 @@ 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) + def initialize(node:, context:, method_name:, receiver_type:, errors:, method_decls: Set[], return_type: AST::Types::Any.instance) super(node: node, context: context, method_name: method_name, receiver_type: receiver_type, return_type: return_type) @method_decls = method_decls @errors = errors diff --git a/sig/steep/ast/types/any.rbs b/sig/steep/ast/types/any.rbs index baa776261..1994d9e4a 100644 --- a/sig/steep/ast/types/any.rbs +++ b/sig/steep/ast/types/any.rbs @@ -2,6 +2,8 @@ module Steep module AST module Types class Any + extend SharedInstance[Any] + def ==: (untyped other) -> bool def hash: () -> Integer diff --git a/sig/steep/ast/types/boolean.rbs b/sig/steep/ast/types/boolean.rbs index d9cb87ba8..8ac445f31 100644 --- a/sig/steep/ast/types/boolean.rbs +++ b/sig/steep/ast/types/boolean.rbs @@ -2,6 +2,8 @@ module Steep module AST module Types class Boolean + extend SharedInstance[Boolean] + def ==: (untyped other) -> bool def hash: () -> Integer diff --git a/sig/steep/ast/types/bot.rbs b/sig/steep/ast/types/bot.rbs index ecb4ba573..466c37813 100644 --- a/sig/steep/ast/types/bot.rbs +++ b/sig/steep/ast/types/bot.rbs @@ -2,6 +2,8 @@ module Steep module AST module Types class Bot + extend SharedInstance[Bot] + def ==: (untyped other) -> bool def hash: () -> Integer diff --git a/sig/steep/ast/types/class.rbs b/sig/steep/ast/types/class.rbs index 103be44d7..bb4a432f3 100644 --- a/sig/steep/ast/types/class.rbs +++ b/sig/steep/ast/types/class.rbs @@ -2,6 +2,8 @@ module Steep module AST module Types class Class + extend SharedInstance[Class] + def to_s: () -> String def ==: (untyped other) -> bool @@ -18,9 +20,6 @@ module Steep include Helper::NoChild def level: () -> Array[Integer] - - self.@instance: Class - def self.instance: () -> Class end end end diff --git a/sig/steep/ast/types/instance.rbs b/sig/steep/ast/types/instance.rbs index 4c0934317..fb53fa48c 100644 --- a/sig/steep/ast/types/instance.rbs +++ b/sig/steep/ast/types/instance.rbs @@ -2,6 +2,8 @@ module Steep module AST module Types class Instance + extend SharedInstance[Instance] + def ==: (untyped other) -> bool def hash: () -> Integer @@ -18,9 +20,6 @@ module Steep def to_s: () -> String def level: () -> Array[Integer] - - self.@instance: Instance - def self.instance: () -> Instance end end end diff --git a/sig/steep/ast/types/logic.rbs b/sig/steep/ast/types/logic.rbs index 20e23eff7..6570a4d70 100644 --- a/sig/steep/ast/types/logic.rbs +++ b/sig/steep/ast/types/logic.rbs @@ -3,6 +3,8 @@ module Steep module Types module Logic class Base + extend SharedInstance[instance] + def subst: (Interface::Substitution s) -> self include Helper::NoFreeVariables @@ -56,6 +58,8 @@ module Steep attr_reader type: t + def self.new: (truthy: TypeInference::TypeEnv, falsy: TypeInference::TypeEnv, type: t) -> Env + def initialize: (truthy: TypeInference::TypeEnv, falsy: TypeInference::TypeEnv, type: t) -> void def ==: (untyped other) -> bool diff --git a/sig/steep/ast/types/nil.rbs b/sig/steep/ast/types/nil.rbs index aadcffbdb..5335d0bef 100644 --- a/sig/steep/ast/types/nil.rbs +++ b/sig/steep/ast/types/nil.rbs @@ -2,6 +2,8 @@ module Steep module AST module Types class Nil + extend SharedInstance[Nil] + def ==: (untyped other) -> bool def hash: () -> Integer diff --git a/sig/steep/ast/types/self.rbs b/sig/steep/ast/types/self.rbs index a2d707dec..3205c7eed 100644 --- a/sig/steep/ast/types/self.rbs +++ b/sig/steep/ast/types/self.rbs @@ -2,6 +2,8 @@ module Steep module AST module Types class Self + extend SharedInstance[Self] + def ==: (untyped other) -> bool def hash: () -> Integer @@ -18,9 +20,6 @@ module Steep def free_variables: () -> Set[variable] def level: () -> Array[Integer] - - self.@instance: Self - def self.instance: () -> Self end end end diff --git a/sig/steep/ast/types/shared_instance.rbs b/sig/steep/ast/types/shared_instance.rbs new file mode 100644 index 000000000..c44f85876 --- /dev/null +++ b/sig/steep/ast/types/shared_instance.rbs @@ -0,0 +1,13 @@ +module Steep + module AST + module Types + module SharedInstance[T] + private def new: () -> T + + def instance: () -> T + + @instance: T + end + end + end +end diff --git a/sig/steep/ast/types/top.rbs b/sig/steep/ast/types/top.rbs index dad875c3e..9aaaf6d01 100644 --- a/sig/steep/ast/types/top.rbs +++ b/sig/steep/ast/types/top.rbs @@ -2,6 +2,8 @@ module Steep module AST module Types class Top + extend SharedInstance[Top] + def ==: (untyped other) -> bool def hash: () -> Integer diff --git a/sig/steep/ast/types/void.rbs b/sig/steep/ast/types/void.rbs index c7422312e..2b2ac98f0 100644 --- a/sig/steep/ast/types/void.rbs +++ b/sig/steep/ast/types/void.rbs @@ -2,6 +2,8 @@ module Steep module AST module Types class Void + extend SharedInstance[Void] + def ==: (untyped other) -> bool def hash: () -> Integer