lib/rbs/definition_builder.rb in rbs-2.8.4 vs lib/rbs/definition_builder.rb in rbs-3.0.0.dev.1

- old
+ new

@@ -30,247 +30,181 @@ NoTypeFoundError.check!(ns.to_type_name, env: env, location: location) end end end + def define_interface(definition, type_name, subst) + included_interfaces = ancestor_builder.one_interface_ancestors(type_name).included_interfaces or raise + interface_methods = interface_methods(included_interfaces) + + methods = method_builder.build_interface(type_name) + + import_methods(definition, type_name, methods, interface_methods, subst) + end + def build_interface(type_name) try_cache(type_name, cache: interface_cache) do entry = env.interface_decls[type_name] or raise "Unknown name for build_interface: #{type_name}" declaration = entry.decl ensure_namespace!(type_name.namespace, location: declaration.location) - self_type = Types::Interface.new( - name: type_name, - args: Types::Variable.build(declaration.type_params.each.map(&:name)), - location: nil - ) + type_params = declaration.type_params.each.map(&:name) + type_args = Types::Variable.build(type_params) + self_type = Types::Interface.new(name: type_name, args: type_args, location: nil) + subst = Substitution.build(type_params, type_args) + ancestors = ancestor_builder.interface_ancestors(type_name) Definition.new(type_name: type_name, entry: entry, self_type: self_type, ancestors: ancestors).tap do |definition| - included_interfaces = ancestor_builder.one_interface_ancestors(type_name).included_interfaces or raise - included_interfaces.each do |mod| - defn = build_interface(mod.name) - subst = Substitution.build(defn.type_params, mod.args) - - defn.methods.each do |name, method| - definition.methods[name] = method.sub(subst) - end - end - methods = method_builder.build_interface(type_name) one_ancestors = ancestor_builder.one_interface_ancestors(type_name) validate_type_params(definition, methods: methods, ancestors: one_ancestors) - methods.each do |defn| - method = case original = defn.original - when AST::Members::MethodDefinition - defs = original.types.map do |method_type| - Definition::Method::TypeDef.new( - type: method_type, - member: original, - defined_in: type_name, - implemented_in: nil - ) - end + define_interface(definition, type_name, subst) + end + end + end - Definition::Method.new( - super_method: nil, - defs: defs, - accessibility: :public, - alias_of: nil - ) - when AST::Members::Alias - unless definition.methods.key?(original.old_name) - raise UnknownMethodAliasError.new( - type_name: type_name, - original_name: original.old_name, - aliased_name: original.new_name, - location: original.location - ) - end + def tapp_subst(name, args) + params = + case + when name.interface? + entry = env.interface_decls[name] or raise "Unknown interface name: #{name}" + entry.decl.type_params + when name.alias? + entry = env.alias_decls[name] or raise "Unknown alias name: #{name}" + entry.decl.type_params + when name.class? + entry = env.class_decls[name] or raise "Unknown module name: #{name}" + entry.type_params + else + raise + end - original_method = definition.methods[original.old_name] - Definition::Method.new( - super_method: nil, - defs: original_method.defs.map do |defn| - defn.update(implemented_in: nil, defined_in: type_name) - end, - accessibility: :public, - alias_of: original_method - ) - when nil - unless definition.methods.key?(defn.name) - raise InvalidOverloadMethodError.new( - type_name: type_name, - method_name: defn.name, - kind: :instance, - members: defn.overloads - ) - end + Substitution.build(params.map(&:name), args) + end - definition.methods[defn.name] + def define_instance(definition, type_name, subst) + one_ancestors = ancestor_builder.one_instance_ancestors(type_name) + methods = method_builder.build_instance(type_name) - when AST::Members::AttrReader, AST::Members::AttrWriter, AST::Members::AttrAccessor - raise + one_ancestors.each_included_module do |mod| + mod.args.each do |arg| + validate_type_presence(arg) + end - end + define_instance(definition, mod.name, subst + tapp_subst(mod.name, mod.args)) + end - defn.overloads.each do |overload| - overload_defs = overload.types.map do |method_type| - Definition::Method::TypeDef.new( - type: method_type, - member: overload, - defined_in: type_name, - implemented_in: nil + interface_methods = interface_methods(one_ancestors.each_included_interface.to_a) + import_methods(definition, type_name, methods, interface_methods, subst) + + one_ancestors.each_prepended_module do |mod| + mod.args.each do |arg| + validate_type_presence(arg) + end + + define_instance(definition, mod.name, subst + tapp_subst(mod.name, mod.args)) + end + + entry = env.class_decls[type_name] or raise "Unknown name for build_instance: #{type_name}" + args = entry.type_params.map {|param| Types::Variable.new(name: param.name, location: param.location) } + + entry.decls.each do |d| + subst_ = subst + Substitution.build(d.decl.type_params.each.map(&:name), args) + + d.decl.members.each do |member| + case member + when AST::Members::AttrReader, AST::Members::AttrAccessor, AST::Members::AttrWriter + if member.kind == :instance + ivar_name = case member.ivar_name + when false + nil + else + member.ivar_name || :"@#{member.name}" + end + + if ivar_name + insert_variable( + type_name, + definition.instance_variables, + name: ivar_name, + type: member.type.sub(subst_) ) end - - method.defs.unshift(*overload_defs) end - definition.methods[defn.name] = method + when AST::Members::InstanceVariable + insert_variable( + type_name, + definition.instance_variables, + name: member.name, + type: member.type.sub(subst_) + ) + + when AST::Members::ClassVariable + insert_variable(type_name, definition.class_variables, name: member.name, type: member.type) end end end end - def build_instance(type_name, no_self_types: false) - try_cache(type_name, cache: instance_cache, key: [type_name, no_self_types]) do + def build_instance(type_name) + try_cache(type_name, cache: instance_cache) do entry = env.class_decls[type_name] or raise "Unknown name for build_instance: #{type_name}" ensure_namespace!(type_name.namespace, location: entry.decls[0].decl.location) - case entry - when Environment::ClassEntry, Environment::ModuleEntry - ancestors = ancestor_builder.instance_ancestors(type_name) - args = entry.type_params.map {|param| Types::Variable.new(name: param.name, location: param.location) } - self_type = Types::ClassInstance.new(name: type_name, args: args, location: nil) + ancestors = ancestor_builder.instance_ancestors(type_name) + args = entry.type_params.map {|param| Types::Variable.new(name: param.name, location: param.location) } + self_type = Types::ClassInstance.new(name: type_name, args: args, location: nil) - Definition.new(type_name: type_name, entry: entry, self_type: self_type, ancestors: ancestors).tap do |definition| - one_ancestors = ancestor_builder.one_instance_ancestors(type_name) - methods = method_builder.build_instance(type_name) + Definition.new(type_name: type_name, entry: entry, self_type: self_type, ancestors: ancestors).tap do |definition| + one_ancestors = ancestor_builder.one_instance_ancestors(type_name) + methods = method_builder.build_instance(type_name) - validate_type_params definition, methods: methods, ancestors: one_ancestors + validate_type_params definition, methods: methods, ancestors: one_ancestors + if entry.is_a?(Environment::ClassEntry) if super_class = one_ancestors.super_class - case super_class - when Definition::Ancestor::Instance - build_instance(super_class.name).yield_self do |defn| - merge_definition(src: defn, - dest: definition, - subst: Substitution.build(defn.type_params, super_class.args), - keep_super: true) - end - else - raise - end - end + super_class.is_a?(Definition::Ancestor::Instance) or raise - if self_types = one_ancestors.self_types - unless no_self_types - self_types.each do |ans| - defn = if ans.name.interface? - build_interface(ans.name) - else - build_instance(ans.name) - end + build_instance(super_class.name).tap do |defn| + unless super_class.args.empty? + super_class.args.each do |arg| + validate_type_presence(arg) + end - # Successor interface method overwrites. - merge_definition( - src: defn, - dest: definition, - subst: Substitution.build(defn.type_params, ans.args), - keep_super: true - ) + subst = tapp_subst(super_class.name, super_class.args) + defn = defn.sub(subst) end - else - methods_with_self = build_instance(type_name, no_self_types: false).methods + + definition.methods.merge!(defn.methods) + definition.instance_variables.merge!(defn.instance_variables) + definition.class_variables.merge!(defn.class_variables) end end + end - one_ancestors.each_included_module do |mod| - defn = build_instance(mod.name, no_self_types: true) - merge_definition(src: defn, - dest: definition, - subst: Substitution.build(defn.type_params, mod.args)) - end - - interface_methods = {} - - one_ancestors.each_included_interface do |mod| - defn = build_interface(mod.name) - subst = Substitution.build(defn.type_params, mod.args) - - defn.methods.each do |name, method| - if interface_methods.key?(name) - include_member = mod.source - - raise unless include_member.is_a?(AST::Members::Include) - - raise DuplicatedInterfaceMethodDefinitionError.new( - type: self_type, - method_name: name, - member: include_member - ) + if entry.is_a?(Environment::ModuleEntry) + if self_types = one_ancestors.self_types + self_types.each do |ans| + ans.args.each do |arg| + validate_type_presence(arg) end - merge_method(type_name, interface_methods, name, method, subst, implemented_in: type_name) - end - end - - if entry.is_a?(Environment::ModuleEntry) - define_methods_module_instance( - definition, - methods: methods, - interface_methods: interface_methods, - module_self_methods: methods_with_self - ) - else - define_methods_instance(definition, methods: methods, interface_methods: interface_methods) - end - - entry.decls.each do |d| - subst = Substitution.build(d.decl.type_params.each.map(&:name), args) - - d.decl.members.each do |member| - case member - when AST::Members::AttrReader, AST::Members::AttrAccessor, AST::Members::AttrWriter - if member.kind == :instance - ivar_name = case member.ivar_name - when false - nil - else - member.ivar_name || :"@#{member.name}" - end - - if ivar_name - insert_variable(type_name, - definition.instance_variables, - name: ivar_name, - type: member.type.sub(subst)) - end - end - - when AST::Members::InstanceVariable - insert_variable(type_name, - definition.instance_variables, - name: member.name, - type: member.type.sub(subst)) - - when AST::Members::ClassVariable - insert_variable(type_name, definition.class_variables, name: member.name, type: member.type) + subst = tapp_subst(ans.name, ans.args) + if ans.name.interface? + define_interface(definition, ans.name, subst) + else + define_instance(definition, ans.name, subst) end end end - - one_ancestors.each_prepended_module do |mod| - defn = build_instance(mod.name, no_self_types: true) - merge_definition(src: defn, - dest: definition, - subst: Substitution.build(defn.type_params, mod.args)) - end end + + define_instance(definition, type_name, Substitution.new) end end end # Builds a definition for singleton without .new method. @@ -278,95 +212,66 @@ def build_singleton0(type_name) try_cache type_name, cache: singleton0_cache do entry = env.class_decls[type_name] or raise "Unknown name for build_singleton0: #{type_name}" ensure_namespace!(type_name.namespace, location: entry.decls[0].decl.location) - case entry - when Environment::ClassEntry, Environment::ModuleEntry - ancestors = ancestor_builder.singleton_ancestors(type_name) - self_type = Types::ClassSingleton.new(name: type_name, location: nil) + ancestors = ancestor_builder.singleton_ancestors(type_name) + self_type = Types::ClassSingleton.new(name: type_name, location: nil) - Definition.new(type_name: type_name, entry: entry, self_type: self_type, ancestors: ancestors).tap do |definition| - one_ancestors = ancestor_builder.one_singleton_ancestors(type_name) + Definition.new(type_name: type_name, entry: entry, self_type: self_type, ancestors: ancestors).tap do |definition| + one_ancestors = ancestor_builder.one_singleton_ancestors(type_name) - if super_class = one_ancestors.super_class - case super_class - when Definition::Ancestor::Instance - defn = build_instance(super_class.name) - merge_definition(src: defn, - dest: definition, - subst: Substitution.build(defn.type_params, super_class.args), - keep_super: true) - when Definition::Ancestor::Singleton - defn = build_singleton0(super_class.name) - merge_definition(src: defn, dest: definition, subst: Substitution.new, keep_super: true) - end + if super_class = one_ancestors.super_class + case super_class + when Definition::Ancestor::Instance + defn = build_instance(super_class.name) + when Definition::Ancestor::Singleton + defn = build_singleton0(super_class.name) end - one_ancestors.each_extended_module do |mod| - mod.args.each do |arg| - validate_type_presence(arg) - end + definition.methods.merge!(defn.methods) + definition.instance_variables.merge!(defn.instance_variables) + definition.class_variables.merge!(defn.class_variables) + end - mod_defn = build_instance(mod.name, no_self_types: true) - merge_definition(src: mod_defn, - dest: definition, - subst: Substitution.build(mod_defn.type_params, mod.args)) + one_ancestors = ancestor_builder.one_singleton_ancestors(type_name) + methods = method_builder.build_singleton(type_name) + + one_ancestors.each_extended_module do |mod| + mod.args.each do |arg| + validate_type_presence(arg) end - interface_methods = {} - one_ancestors.each_extended_interface do |mod| - mod.args.each do |arg| - validate_type_presence(arg) - end + subst = tapp_subst(mod.name, mod.args) + define_instance(definition, mod.name, subst) + end - mod_defn = build_interface(mod.name) - subst = Substitution.build(mod_defn.type_params, mod.args) + interface_methods = interface_methods(one_ancestors.each_extended_interface.to_a) + import_methods(definition, type_name, methods, interface_methods, Substitution.new) - mod_defn.methods.each do |name, method| - if interface_methods.key?(name) - src_member = mod.source + entry.decls.each do |d| + d.decl.members.each do |member| + case member + when AST::Members::AttrReader, AST::Members::AttrAccessor, AST::Members::AttrWriter + if member.kind == :singleton + ivar_name = case member.ivar_name + when false + nil + else + member.ivar_name || :"@#{member.name}" + end - raise unless src_member.is_a?(AST::Members::Extend) - - raise DuplicatedInterfaceMethodDefinitionError.new( - type: self_type, - method_name: name, - member: src_member - ) + if ivar_name + insert_variable(type_name, definition.instance_variables, name: ivar_name, type: member.type) + end end - merge_method(type_name, interface_methods, name, method, subst, implemented_in: type_name) - end - end + when AST::Members::ClassInstanceVariable + insert_variable(type_name, definition.instance_variables, name: member.name, type: member.type) - methods = method_builder.build_singleton(type_name) - define_methods_singleton(definition, methods: methods, interface_methods: interface_methods) - - entry.decls.each do |d| - d.decl.members.each do |member| - case member - when AST::Members::AttrReader, AST::Members::AttrAccessor, AST::Members::AttrWriter - if member.kind == :singleton - ivar_name = case member.ivar_name - when false - nil - else - member.ivar_name || :"@#{member.name}" - end - - if ivar_name - insert_variable(type_name, definition.instance_variables, name: ivar_name, type: member.type) - end - end - - when AST::Members::ClassInstanceVariable - insert_variable(type_name, definition.instance_variables, name: member.name, type: member.type) - - when AST::Members::ClassVariable - insert_variable(type_name, definition.class_variables, name: member.name, type: member.type) - end + when AST::Members::ClassVariable + insert_variable(type_name, definition.class_variables, name: member.name, type: member.type) end end end end end @@ -375,116 +280,133 @@ def build_singleton(type_name) try_cache type_name, cache: singleton_cache do entry = env.class_decls[type_name] or raise "Unknown name for build_singleton: #{type_name}" ensure_namespace!(type_name.namespace, location: entry.decls[0].decl.location) - case entry - when Environment::ClassEntry, Environment::ModuleEntry - ancestors = ancestor_builder.singleton_ancestors(type_name) - self_type = Types::ClassSingleton.new(name: type_name, location: nil) + ancestors = ancestor_builder.singleton_ancestors(type_name) + self_type = Types::ClassSingleton.new(name: type_name, location: nil) - Definition.new(type_name: type_name, entry: entry, self_type: self_type, ancestors: ancestors).tap do |definition| - def0 = build_singleton0(type_name) - subst = Substitution.new + Definition.new(type_name: type_name, entry: entry, self_type: self_type, ancestors: ancestors).tap do |definition| + definition0 = build_singleton0(type_name) + definition.methods.merge!(definition0.methods) + definition.instance_variables.merge!(definition0.instance_variables) + definition.class_variables.merge!(definition0.class_variables) - merge_definition(src: def0, dest: definition, subst: subst, keep_super: true) + if entry.is_a?(Environment::ClassEntry) + new_method = definition.methods[:new] - if entry.is_a?(Environment::ClassEntry) - new_method = definition.methods[:new] - if new_method.defs.all? {|d| d.defined_in == BuiltinNames::Class.name } - alias_methods = definition.methods.each.with_object([]) do |entry, array| - # @type var method: Definition::Method? - name, method = entry - while method - if method.alias_of == new_method - array << name - break - end - method = method.alias_of + if new_method.defs.all? {|d| d.defined_in == BuiltinNames::Class.name } + # The method is _untyped new_. + + alias_methods = definition.methods.each.with_object([]) do |entry, array| + # @type var method: Definition::Method? + name, method = entry + while method + if method.alias_of == new_method + array << name + break end + method = method.alias_of end + end - # The method is _untyped new_. + instance = build_instance(type_name) + initialize = instance.methods[:initialize] - instance = build_instance(type_name) - initialize = instance.methods[:initialize] + if initialize + class_params = entry.type_params - if initialize - class_params = entry.type_params + # Inject a virtual _typed new_. + initialize_defs = initialize.defs + typed_new = Definition::Method.new( + super_method: new_method, + defs: initialize_defs.map do |initialize_def| + method_type = initialize_def.type - # Inject a virtual _typed new_. - initialize_defs = initialize.defs - typed_new = Definition::Method.new( - super_method: new_method, - defs: initialize_defs.map do |initialize_def| - method_type = initialize_def.type + class_type_param_vars = Set.new(class_params.map(&:name)) + method_type_param_vars = Set.new(method_type.type_params.map(&:name)) - class_type_param_vars = Set.new(class_params.map(&:name)) - method_type_param_vars = Set.new(method_type.type_params.map(&:name)) - - if class_type_param_vars.intersect?(method_type_param_vars) - new_method_param_names = method_type.type_params.map do |method_param| - if class_type_param_vars.include?(method_param.name) - Types::Variable.fresh(method_param.name).name - else - method_param.name - end + if class_type_param_vars.intersect?(method_type_param_vars) + new_method_param_names = method_type.type_params.map do |method_param| + if class_type_param_vars.include?(method_param.name) + Types::Variable.fresh(method_param.name).name + else + method_param.name end + end - sub = Substitution.build( - method_type.type_params.map(&:name), - Types::Variable.build(new_method_param_names) - ) + sub = Substitution.build( + method_type.type_params.map(&:name), + Types::Variable.build(new_method_param_names) + ) - method_params = class_params + AST::TypeParam.rename(method_type.type_params, new_names: new_method_param_names) - method_type = method_type - .update(type_params: []) - .sub(sub) - .update(type_params: method_params) - else - method_type = method_type - .update(type_params: class_params + method_type.type_params) - end + method_params = class_params + AST::TypeParam.rename(method_type.type_params, new_names: new_method_param_names) + method_type = method_type + .update(type_params: []) + .sub(sub) + .update(type_params: method_params) + else + method_type = method_type + .update(type_params: class_params + method_type.type_params) + end - method_type = method_type.update( - type: method_type.type.with_return_type( - Types::ClassInstance.new( - name: type_name, - args: entry.type_params.map {|param| Types::Variable.new(name: param.name, location: param.location) }, - location: nil - ) + method_type = method_type.update( + type: method_type.type.with_return_type( + Types::ClassInstance.new( + name: type_name, + args: entry.type_params.map {|param| Types::Variable.new(name: param.name, location: param.location) }, + location: nil ) ) + ) - Definition::Method::TypeDef.new( - type: method_type, - member: initialize_def.member, - defined_in: initialize_def.defined_in, - implemented_in: initialize_def.implemented_in - ) - end, - accessibility: :public, - annotations: [], - alias_of: nil - ) + Definition::Method::TypeDef.new( + type: method_type, + member: initialize_def.member, + defined_in: initialize_def.defined_in, + implemented_in: initialize_def.implemented_in + ) + end, + accessibility: :public, + alias_of: nil + ) - definition.methods[:new] = typed_new + definition.methods[:new] = typed_new - alias_methods.each do |alias_name| - definition.methods[alias_name] = definition.methods[alias_name].update( - alias_of: typed_new, - defs: typed_new.defs - ) - end + alias_methods.each do |alias_name| + definition.methods[alias_name] = definition.methods[alias_name].update( + alias_of: typed_new, + defs: typed_new.defs + ) end end end end end end end + def interface_methods(interface_ancestors) + interface_methods = {} #: interface_methods + + interface_ancestors.each do |mod| + source = + case mod.source + when AST::Members::Include, AST::Members::Extend + mod.source + else + raise "Interface mixin must be include/extend: #{mod.source.inspect}" + end + + methods = method_builder.build_interface(mod.name) + + interface_methods[mod] = [methods, source] + end + + interface_methods + end + def validate_params_with(type_params, result:) type_params.each do |param| unless param.unchecked? unless result.compatible?(param.name, with_annotation: param.variance) yield param @@ -537,11 +459,11 @@ methods.each do |defn| next if defn.name == :initialize method_types = case original = defn.original when AST::Members::MethodDefinition - original.types + original.overloads.map(&:method_type) when AST::Members::AttrWriter, AST::Members::AttrReader, AST::Members::AttrAccessor if defn.name.to_s.end_with?("=") [ MethodType.new( type_params: [], @@ -595,273 +517,229 @@ type: type, declared_in: type_name ) end - def define_methods_instance(definition, methods:, interface_methods:) - define_methods( - definition, - methods: methods, - interface_methods: interface_methods, - methods_with_self: nil, - super_interface_method: false - ) - end + def import_methods(definition, module_name, module_methods, interfaces_methods, subst) + new_methods = {} #: Hash[Symbol, Definition::Method] + interface_method_duplicates = Set[] #: Set[Symbol] - def define_methods_module_instance(definition, methods:, interface_methods:, module_self_methods:) - define_methods(definition, methods: methods, interface_methods: interface_methods, methods_with_self: module_self_methods, super_interface_method: true) - end + interfaces_methods.each do |interface, (methods, member)| + unless interface.args.empty? + methods.type.is_a?(Types::Interface) or raise + params = methods.type.args.map do |arg| + arg.is_a?(Types::Variable) or raise + arg.name + end - def define_methods_singleton(definition, methods:, interface_methods:) - define_methods( - definition, - methods: methods, - interface_methods: interface_methods, - methods_with_self: nil, - super_interface_method: false - ) - end + interface.args.each do |arg| + validate_type_presence(arg) + end - def define_methods(definition, methods:, interface_methods:, methods_with_self:, super_interface_method:) - methods.each do |method_def| - method_name = method_def.name - original = method_def.original + subst_ = subst + Substitution.build(params, interface.args) + else + subst_ = subst + end - if original.is_a?(AST::Members::Alias) - existing_method = interface_methods[method_name] || definition.methods[method_name] - original_method = - interface_methods[original.old_name] || - methods_with_self&.[](original.old_name) || - definition.methods[original.old_name] + methods.each do |method| + if interface_method_duplicates.include?(method.name) + member.is_a?(AST::Members::Include) || member.is_a?(AST::Members::Extend) or raise - unless original_method - raise UnknownMethodAliasError.new( - type_name: definition.type_name, - original_name: original.old_name, - aliased_name: original.new_name, - location: original.location + raise DuplicatedInterfaceMethodDefinitionError.new( + type: definition.self_type, + method_name: method.name, + member: member ) end - method = Definition::Method.new( - super_method: existing_method, - defs: original_method.defs.map do |defn| - defn.update(defined_in: definition.type_name, implemented_in: definition.type_name) - end, - accessibility: original_method.accessibility, - alias_of: original_method + interface_method_duplicates << method.name + define_method( + new_methods, + definition, + method, + subst_, + defined_in: interface.name, + implemented_in: module_name ) - else - if interface_methods.key?(method_name) - interface_method = interface_methods[method_name] + end + end - if original = method_def.original - raise DuplicatedMethodDefinitionError.new( - type: definition.self_type, - method_name: method_name, - members: [original] - ) - end + module_methods.each do |method| + define_method( + new_methods, + definition, + method, + subst, + defined_in: module_name, + implemented_in: module_name.interface? ? nil : module_name + ) + end - definition.methods[method_name] = interface_method - end + definition.methods.merge!(new_methods) + end - existing_method = definition.methods[method_name] + def define_method(methods, definition, method, subst, defined_in:, implemented_in: defined_in) + existing_method = methods[method.name] || definition.methods[method.name] - case original - when AST::Members::MethodDefinition - defs = original.types.map do |method_type| - Definition::Method::TypeDef.new( - type: method_type, - member: original, - defined_in: definition.type_name, - implemented_in: definition.type_name - ) - end + case original = method.original + when AST::Members::Alias + original_method = methods[original.old_name] || definition.methods[original.old_name] - # @type var accessibility: RBS::Definition::accessibility - accessibility = if method_name == :initialize - :private - else - method_def.accessibility - end + unless original_method + raise UnknownMethodAliasError.new( + type_name: definition.type_name, + original_name: original.old_name, + aliased_name: original.new_name, + location: original.location + ) + end - method = Definition::Method.new( - super_method: existing_method, - defs: defs, - accessibility: accessibility, - alias_of: nil - ) + method_definition = Definition::Method.new( + super_method: existing_method, + defs: original_method.defs.map do |defn| + defn.update(defined_in: defined_in, implemented_in: implemented_in) + end, + accessibility: original_method.accessibility, + alias_of: original_method + ) + when AST::Members::MethodDefinition + if duplicated_method = methods[method.name] + raise DuplicatedMethodDefinitionError.new( + type: definition.self_type, + method_name: method.name, + members: [original, *duplicated_method.members] + ) + end - when AST::Members::AttrReader, AST::Members::AttrWriter, AST::Members::AttrAccessor - method_type = if method_name.to_s.end_with?("=") - # setter - MethodType.new( - type_params: [], - type: Types::Function.empty(original.type).update( - required_positionals: [ - Types::Function::Param.new(type: original.type, name: original.name) - ] - ), - block: nil, - location: nil - ) - else - # getter - MethodType.new( - type_params: [], - type: Types::Function.empty(original.type), - block: nil, - location: nil - ) - end - defs = [ - Definition::Method::TypeDef.new( - type: method_type, - member: original, - defined_in: definition.type_name, - implemented_in: definition.type_name - ) - ] + defs = original.overloads.map do |overload| + Definition::Method::TypeDef.new( + type: subst.empty? ? overload.method_type : overload.method_type.sub(subst), + member: original, + defined_in: defined_in, + implemented_in: implemented_in + ) + end - method = Definition::Method.new( - super_method: existing_method, - defs: defs, - accessibility: method_def.accessibility, - alias_of: nil - ) + # @type var accessibility: RBS::Definition::accessibility + accessibility = if method.name == :initialize + :private + else + method.accessibility + end - when nil - unless definition.methods.key?(method_name) - raise InvalidOverloadMethodError.new( - type_name: definition.type_name, - method_name: method_name, - kind: :instance, - members: method_def.overloads - ) - end + # Skip setting up `super_method` if `implemented_in` is `nil`, that means the type doesn't have implementation. + # This typically happens if the type is an interface. + if implemented_in + super_method = existing_method + end - if !super_interface_method && existing_method.defs.any? {|defn| defn.defined_in.interface? } - super_method = existing_method.super_method - else - super_method = existing_method - end + method_definition = Definition::Method.new( + super_method: super_method, + defs: defs, + accessibility: accessibility, + alias_of: nil + ) + when AST::Members::AttrReader, AST::Members::AttrWriter, AST::Members::AttrAccessor + if duplicated_method = methods[method.name] + raise DuplicatedMethodDefinitionError.new( + type: definition.self_type, + method_name: method.name, + members: [*duplicated_method.members, original] + ) + end - method = Definition::Method.new( - super_method: super_method, - defs: existing_method.defs.map do |defn| - defn.update(implemented_in: definition.type_name) - end, - accessibility: existing_method.accessibility, - alias_of: existing_method.alias_of + attr_type = original.type.sub(subst) + method_type = + if method.name.to_s.end_with?("=") + # setter + MethodType.new( + type_params: [], + type: Types::Function.empty(attr_type).update( + required_positionals: [ + Types::Function::Param.new(type: attr_type, name: original.name) + ] + ), + block: nil, + location: nil ) + else + # getter + MethodType.new( + type_params: [], + type: Types::Function.empty(attr_type), + block: nil, + location: nil + ) end + + if implemented_in + super_method = existing_method end - method_def.overloads.each do |overload| - type_defs = overload.types.map do |method_type| + method_definition = Definition::Method.new( + super_method: super_method, + defs: [ Definition::Method::TypeDef.new( type: method_type, - member: overload, + member: original, defined_in: definition.type_name, implemented_in: definition.type_name ) - end + ], + accessibility: method.accessibility, + alias_of: nil + ) + when nil + # Overloading method definition only - method.defs.unshift(*type_defs) + case + when methods.key?(method.name) + # The method is defined in an interface + super_method = methods[method.name].super_method + when definition.methods.key?(method.name) + # The method is defined in the super class + super_method = existing_method + else + # Cannot find any non-overloading method + raise InvalidOverloadMethodError.new( + type_name: definition.type_name, + method_name: method.name, + kind: :instance, + members: method.overloads + ) end - definition.methods[method_name] = method + method_definition = Definition::Method.new( + super_method: super_method, + defs: existing_method.defs.map do |defn| + defn.update(implemented_in: definition.type_name) + end, + accessibility: existing_method.accessibility, + alias_of: existing_method.alias_of + ) end - interface_methods.each do |name, method| - unless methods.methods.key?(name) - merge_method(definition.type_name, definition.methods, name, method, Substitution.new) + method.overloads.each do |overloading_def| + overloading_def.overloads.reverse_each do |overload| + type_def = Definition::Method::TypeDef.new( + type: subst.empty? ? overload.method_type : overload.method_type.sub(subst), + member: overloading_def, + defined_in: definition.type_name, + implemented_in: definition.type_name + ) + + method_definition.defs.unshift(type_def) end end - end - def merge_definition(src:, dest:, subst:, implemented_in: :keep, keep_super: false) - src.methods.each do |name, method| - merge_method(dest.type_name, dest.methods, name, method, subst, implemented_in: implemented_in, keep_super: keep_super) - end - - src.instance_variables.each do |name, variable| - merge_variable(dest.instance_variables, name, variable, subst, keep_super: keep_super) - end - - src.class_variables.each do |name, variable| - merge_variable(dest.class_variables, name, variable, subst, keep_super: keep_super) - end + methods[method.name] = method_definition end - def merge_variable(variables, name, variable, sub, keep_super: false) - super_variable = variables[name] - - variables[name] = Definition::Variable.new( - parent_variable: keep_super ? variable.parent_variable : super_variable, - type: sub.empty? ? variable.type : variable.type.sub(sub), - declared_in: variable.declared_in - ) + def try_cache(type_name, cache:) + cache[type_name] ||= yield end - def merge_method(type_name, methods, name, method, sub, implemented_in: :keep, keep_super: false) - if sub.empty? && implemented_in == :keep && keep_super - methods[name] = method - else - if sub.empty? && implemented_in == :keep - defs = method.defs - else - defs = method.defs.map do |defn| - defn.update( - type: sub.empty? ? defn.type : defn.type.sub(sub), - implemented_in: case implemented_in - when :keep - defn.implemented_in - when nil - nil - else - implemented_in - end - ) - end - - defs = method.defs.map do |defn| - defn.update( - type: sub.empty? ? defn.type : defn.type.sub(sub), - implemented_in: case implemented_in - when :keep - defn.implemented_in - when nil - nil - else - implemented_in - end - ) - end - end - - super_method = methods[name] - - methods[name] = Definition::Method.new( - super_method: keep_super ? method.super_method : super_method, - accessibility: method.accessibility, - defs: defs, - alias_of: method.alias_of - ) - end - end - - def try_cache(type_name, cache:, key: nil) - # @type var cc: Hash[untyped, Definition | nil] - # @type var key: untyped - key ||= type_name - cc = _ = cache - - cc[key] ||= yield - end - def expand_alias(type_name) expand_alias2(type_name, []) end def expand_alias1(type_name) @@ -901,11 +779,10 @@ builder.singleton_cache.merge!(singleton_cache) builder.singleton0_cache.merge!(singleton0_cache) builder.interface_cache.merge!(interface_cache) except.each do |name| - builder.instance_cache.delete([name, true]) - builder.instance_cache.delete([name, false]) + builder.instance_cache.delete(name) builder.singleton_cache.delete(name) builder.singleton0_cache.delete(name) builder.interface_cache.delete(name) end end