lib/rbs/definition_builder.rb in rbs-0.20.1 vs lib/rbs/definition_builder.rb in rbs-1.0.0.pre

- old
+ new

@@ -1,446 +1,322 @@ module RBS class DefinitionBuilder attr_reader :env attr_reader :type_name_resolver + attr_reader :ancestor_builder + attr_reader :method_builder attr_reader :instance_cache attr_reader :singleton_cache + attr_reader :singleton0_cache attr_reader :interface_cache - attr_reader :one_instance_cache - attr_reader :one_singleton_cache - - attr_reader :instance_ancestors_cache - attr_reader :singleton_ancestor_cache - - attr_reader :one_instance_ancestors_cache - attr_reader :one_singleton_ancestors_cache - - class OneAncestors - attr_reader :type_name - attr_reader :params - attr_reader :super_class - attr_reader :self_types - attr_reader :included_modules - attr_reader :prepended_modules - attr_reader :extended_modules - - def initialize(type_name:, params:, super_class:, self_types:, included_modules:, prepended_modules:, extended_modules:) - @type_name = type_name - @params = params - @super_class = super_class - @self_types = self_types - @included_modules = included_modules - @prepended_modules = prepended_modules - @extended_modules = extended_modules - end - - def each_ancestor(&block) - if block - if s = super_class - yield s - end - - self_types&.each(&block) - included_modules&.each(&block) - prepended_modules&.each(&block) - extended_modules&.each(&block) - else - enum_for :each_ancestor - end - end - - def self.class_instance(type_name:, params:, super_class:) - new( - type_name: type_name, - params: params, - super_class: super_class, - self_types: nil, - included_modules: [], - prepended_modules: [], - extended_modules: nil - ) - end - - def self.singleton(type_name:, super_class:) - new( - type_name: type_name, - params: nil, - super_class: super_class, - self_types: nil, - included_modules: nil, - prepended_modules: nil, - extended_modules: [] - ) - end - - def self.module_instance(type_name:, params:) - new( - type_name: type_name, - params: params, - self_types: [], - included_modules: [], - prepended_modules: [], - super_class: nil, - extended_modules: nil - ) - end - end - def initialize(env:) @env = env @type_name_resolver = TypeNameResolver.from_env(env) + @ancestor_builder = AncestorBuilder.new(env: env) + @method_builder = MethodBuilder.new(env: env) @instance_cache = {} @singleton_cache = {} + @singleton0_cache = {} @interface_cache = {} - - @one_instance_cache = {} - @one_singleton_cache = {} - - @instance_ancestors_cache = {} - @singleton_ancestor_cache = {} - - @one_instance_ancestors_cache = {} - @one_singleton_ancestors_cache = {} end - def validate_super_class!(type_name, entry) - with_super_classes = entry.decls.select {|d| d.decl.super_class } - - return if with_super_classes.size <= 1 - - super_types = with_super_classes.map do |d| - super_class = d.decl.super_class or raise - Types::ClassInstance.new(name: super_class.name, args: super_class.args, location: nil) + def ensure_namespace!(namespace, location:) + namespace.ascend do |ns| + unless ns.empty? + NoTypeFoundError.check!(ns.to_type_name, env: env, location: location) + end end - - super_types.uniq! - - return if super_types.size == 1 - - raise SuperclassMismatchError.new(name: type_name, super_classes: super_types, entry: entry) end - def one_instance_ancestors(type_name) - as = one_instance_ancestors_cache[type_name] and return as + 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) - entry = env.class_decls[type_name] or raise "Unknown name for one_instance_ancestors: #{type_name}" - params = entry.type_params.each.map(&:name) + self_type = Types::Interface.new( + name: type_name, + args: Types::Variable.build(declaration.type_params.each.map(&:name)), + location: nil + ) - case entry - when Environment::ClassEntry - validate_super_class!(type_name, entry) - primary = entry.primary - super_class = primary.decl.super_class + ancestors = ancestor_builder.interface_ancestors(type_name) + Definition.new(type_name: type_name, entry: entry, self_type: self_type, ancestors: ancestors).tap do |definition| + ancestor_builder.one_interface_ancestors(type_name).included_interfaces.each do |mod| + defn = build_interface(mod.name) + subst = Substitution.build(defn.type_params, mod.args) - if type_name != BuiltinNames::BasicObject.name - if super_class - super_name = super_class.name - super_args = super_class.args - else - super_name = BuiltinNames::Object.name - super_args = [] + defn.methods.each do |name, method| + definition.methods[name] = method.sub(subst) + end end - NoSuperclassFoundError.check!(super_name, env: env, location: primary.decl.location) + methods = method_builder.build_interface(type_name) + methods.each do |defn| + method = case defn.original + when AST::Members::MethodDefinition + defs = defn.original.types.map do |method_type| + Definition::Method::TypeDef.new( + type: method_type, + member: defn.original, + defined_in: type_name, + implemented_in: nil + ) + end - ancestors = OneAncestors.class_instance( - type_name: type_name, - params: params, - super_class: Definition::Ancestor::Instance.new(name: super_name, args: super_args) - ) - else - ancestors = OneAncestors.class_instance( - type_name: type_name, - params: params, - super_class: nil - ) - end - when Environment::ModuleEntry - ancestors = OneAncestors.module_instance(type_name: type_name, params: params) + Definition::Method.new( + super_method: nil, + defs: defs, + accessibility: :public, + alias_of: nil + ) + when AST::Members::Alias + unless definition.methods.key?(defn.original.old_name) + raise UnknownMethodAliasError.new( + original_name: defn.original.old_name, + aliased_name: defn.original.new_name, + location: defn.original.location + ) + end - entry.self_types.each do |module_self| - NoSelfTypeFoundError.check!(module_self, env: env) + original_method = definition.methods[defn.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 - self_types = ancestors.self_types or raise - self_types.push Definition::Ancestor::Instance.new(name: module_self.name, args: module_self.args) - end - end + definition.methods[defn.name] + end - mixin_ancestors(entry, - included_modules: ancestors.included_modules, - prepended_modules: ancestors.prepended_modules, - extended_modules: nil) + defn.overloads.each do |overload| + defs = overload.types.map do |method_type| + Definition::Method::TypeDef.new( + type: method_type, + member: overload, + defined_in: type_name, + implemented_in: nil + ) + end - one_instance_ancestors_cache[type_name] = ancestors - end + method.defs.unshift(*defs) + end - def one_singleton_ancestors(type_name) - as = one_singleton_ancestors_cache[type_name] and return as - - entry = env.class_decls[type_name] or raise "Unknown name for one_singleton_ancestors: #{type_name}" - - case entry - when Environment::ClassEntry - validate_super_class!(type_name, entry) - primary = entry.primary - super_class = primary.decl.super_class - - if type_name != BuiltinNames::BasicObject.name - if super_class - super_name = super_class.name - else - super_name = BuiltinNames::Object.name + definition.methods[defn.name] = method end - - NoSuperclassFoundError.check!(super_name, env: env, location: primary.decl.location) - - ancestors = OneAncestors.singleton( - type_name: type_name, - super_class: Definition::Ancestor::Singleton.new(name: super_name) - ) - else - ancestors = OneAncestors.singleton( - type_name: type_name, - super_class: Definition::Ancestor::Instance.new(name: BuiltinNames::Class.name, args: []) - ) end - when Environment::ModuleEntry - ancestors = OneAncestors.singleton( - type_name: type_name, - super_class: Definition::Ancestor::Instance.new(name: BuiltinNames::Module.name, args: []) - ) end - - mixin_ancestors(entry, - included_modules: nil, - prepended_modules: nil, - extended_modules: ancestors.extended_modules) - - one_singleton_ancestors_cache[type_name] = ancestors end - def mixin_ancestors(entry, included_modules:, extended_modules:, prepended_modules:) - entry.decls.each do |d| - decl = d.decl + 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) - align_params = Substitution.build( - decl.type_params.each.map(&:name), - Types::Variable.build(entry.type_params.each.map(&:name)) - ) + case entry + when Environment::ClassEntry, Environment::ModuleEntry + ancestors = ancestor_builder.instance_ancestors(type_name) + self_type = Types::ClassInstance.new(name: type_name, + args: Types::Variable.build(entry.type_params.each.map(&:name)), + location: nil) - decl.each_mixin do |member| - case member - when AST::Members::Include - if included_modules - NoMixinFoundError.check!(member.name, env: env, member: member) + 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) - module_name = member.name - module_args = member.args.map {|type| type.sub(align_params) } + validate_type_params definition, methods: methods, ancestors: one_ancestors - included_modules << Definition::Ancestor::Instance.new(name: module_name, args: module_args) + if super_class = one_ancestors.super_class + defn = build_instance(super_class.name) + merge_definition(src: defn, + dest: definition, + subst: Substitution.build(defn.type_params, super_class.args), + keep_super: true) end - when AST::Members::Prepend - if prepended_modules - NoMixinFoundError.check!(member.name, env: env, member: member) + if one_ancestors.self_types + one_ancestors.self_types.each do |ans| + defn = if ans.name.interface? + build_interface(ans.name) + else + build_instance(ans.name) + end - module_name = member.name - module_args = member.args.map {|type| type.sub(align_params) } - - prepended_modules << Definition::Ancestor::Instance.new(name: module_name, args: module_args) + # Successor interface method overwrites. + merge_definition(src: defn, + dest: definition, + subst: Substitution.build(defn.type_params, ans.args), + keep_super: true) + end end - when AST::Members::Extend - if extended_modules - NoMixinFoundError.check!(member.name, env: env, member: member) - - module_name = member.name - module_args = member.args - - extended_modules << Definition::Ancestor::Instance.new(name: module_name, args: module_args) + one_ancestors.included_modules.each do |mod| + defn = build_instance(mod.name) + merge_definition(src: defn, + dest: definition, + subst: Substitution.build(defn.type_params, mod.args)) end - end - end - end - end - def instance_ancestors(type_name, building_ancestors: []) - as = instance_ancestors_cache[type_name] and return as + interface_methods = {} - entry = env.class_decls[type_name] or raise "Unknown name for instance_ancestors: #{type_name}" - params = entry.type_params.each.map(&:name) - args = Types::Variable.build(params) - self_ancestor = Definition::Ancestor::Instance.new(name: type_name, args: args) + one_ancestors.included_interfaces.each do |mod| + defn = build_interface(mod.name) + subst = Substitution.build(defn.type_params, mod.args) - RecursiveAncestorError.check!(self_ancestor, - ancestors: building_ancestors, - location: entry.primary.decl.location) - building_ancestors.push self_ancestor + defn.methods.each do |name, method| + if interface_methods.key?(name) + raise DuplicatedInterfaceMethodDefinitionError.new( + type: self_type, + method_name: name, + member: mod.source + ) + end - one_ancestors = one_instance_ancestors(type_name) + merge_method(type_name, interface_methods, name, method, subst, implemented_in: type_name) + end + end - ancestors = [] + define_methods(definition, + interface_methods: interface_methods, + methods: methods, + super_interface_method: entry.is_a?(Environment::ModuleEntry)) - case entry - when Environment::ClassEntry - if super_class = one_ancestors.super_class - # @type var super_class: Definition::Ancestor::Instance - super_name = super_class.name - super_args = super_class.args + 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 == :instance + ivar_name = case member.ivar_name + when false + nil + else + member.ivar_name || :"@#{member.name}" + end - super_ancestors = instance_ancestors(super_name, building_ancestors: building_ancestors) - ancestors.unshift(*super_ancestors.apply(super_args, location: entry.primary.decl.location)) - end - end + if ivar_name + insert_variable(type_name, definition.instance_variables, name: ivar_name, type: member.type) + end + end - if included_modules = one_ancestors.included_modules - included_modules.each do |mod| - if mod.name.class? - name = mod.name - arg_types = mod.args - mod_ancestors = instance_ancestors(name, building_ancestors: building_ancestors) - ancestors.unshift(*mod_ancestors.apply(arg_types, location: entry.primary.decl.location)) - end - end - end + when AST::Members::InstanceVariable + insert_variable(type_name, definition.instance_variables, name: member.name, type: member.type) - ancestors.unshift(self_ancestor) + when AST::Members::ClassVariable + insert_variable(type_name, definition.class_variables, name: member.name, type: member.type) + end + end + end - if prepended_modules = one_ancestors.prepended_modules - prepended_modules.each do |mod| - if mod.name.class? - name = mod.name - arg_types = mod.args - mod_ancestors = instance_ancestors(name, building_ancestors: building_ancestors) - ancestors.unshift(*mod_ancestors.apply(arg_types, location: entry.primary.decl.location)) + one_ancestors.prepended_modules.each do |mod| + defn = build_instance(mod.name) + merge_definition(src: defn, + dest: definition, + subst: Substitution.build(defn.type_params, mod.args)) + end end end end - - building_ancestors.pop - - instance_ancestors_cache[type_name] = Definition::InstanceAncestors.new( - type_name: type_name, - params: params, - ancestors: ancestors - ) end - def singleton_ancestors(type_name, building_ancestors: []) - as = singleton_ancestor_cache[type_name] and return as + # Builds a definition for singleton without .new method. + # + 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) - entry = env.class_decls[type_name] or raise "Unknown name for singleton_ancestors: #{type_name}" - self_ancestor = Definition::Ancestor::Singleton.new(name: type_name) + case entry + when Environment::ClassEntry, Environment::ModuleEntry + ancestors = ancestor_builder.singleton_ancestors(type_name) + self_type = Types::ClassSingleton.new(name: type_name, location: nil) - RecursiveAncestorError.check!(self_ancestor, - ancestors: building_ancestors, - location: entry.primary.decl.location) - building_ancestors.push self_ancestor + 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) - one_ancestors = 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 + end - ancestors = [] + one_ancestors.extended_modules.each do |mod| + defn = build_instance(mod.name) + merge_definition(src: defn, + dest: definition, + subst: Substitution.build(defn.type_params, mod.args)) + end - case super_class = one_ancestors.super_class - when Definition::Ancestor::Instance - super_name = super_class.name - super_args = super_class.args + interface_methods = {} + one_ancestors.extended_interfaces.each do |mod| + defn = build_interface(mod.name) + subst = Substitution.build(defn.type_params, mod.args) - super_ancestors = instance_ancestors(super_name, building_ancestors: building_ancestors) - ancestors.unshift(*super_ancestors.apply(super_args, location: entry.primary.decl.location)) + defn.methods.each do |name, method| + if interface_methods.key?(name) + raise DuplicatedInterfaceMethodDefinitionError.new( + type: self_type, + method_name: name, + member: mod.source + ) + end - when Definition::Ancestor::Singleton - super_name = super_class.name + merge_method(type_name, interface_methods, name, method, subst, implemented_in: type_name) + end + end - super_ancestors = singleton_ancestors(super_name, building_ancestors: []) - ancestors.unshift(*super_ancestors.ancestors) - end + methods = method_builder.build_singleton(type_name) + define_methods(definition, interface_methods: interface_methods, methods: methods, super_interface_method: false) - extended_modules = one_ancestors.extended_modules or raise - extended_modules.each do |mod| - if mod.name.class? - name = mod.name - args = mod.args - mod_ancestors = instance_ancestors(name, building_ancestors: building_ancestors) - ancestors.unshift(*mod_ancestors.apply(args, location: entry.primary.decl.location)) - end - end + 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 - ancestors.unshift(self_ancestor) + if ivar_name + insert_variable(type_name, definition.instance_variables, name: ivar_name, type: member.type) + end + end - building_ancestors.pop + when AST::Members::ClassInstanceVariable + insert_variable(type_name, definition.instance_variables, name: member.name, type: member.type) - singleton_ancestor_cache[type_name] = Definition::SingletonAncestors.new( - type_name: type_name, - ancestors: ancestors - ) - end - - def each_member_with_accessibility(members, accessibility: :public) - members.each do |member| - case member - when AST::Members::Public - accessibility = :public - when AST::Members::Private - accessibility = :private - else - yield member, accessibility - end - end - end - - def ensure_namespace!(namespace, location:) - namespace.ascend do |ns| - unless ns.empty? - NoTypeFoundError.check!(ns.to_type_name, env: env, location: location) - end - end - end - - 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 = instance_ancestors(type_name) - self_type = Types::ClassInstance.new(name: type_name, - args: Types::Variable.build(entry.type_params.each.map(&:name)), - location: nil) - - definition_pairs = ancestors.ancestors.map do |ancestor| - # @type block: [Definition::Ancestor::t, Definition] - case ancestor - when Definition::Ancestor::Instance - [ancestor, build_one_instance(ancestor.name)] - when Definition::Ancestor::Singleton - [ancestor, build_one_singleton(ancestor.name)] + when AST::Members::ClassVariable + insert_variable(type_name, definition.class_variables, name: member.name, type: member.type) + end + end end end - - case entry - when Environment::ModuleEntry - entry.self_types.each do |module_self| - ancestor = Definition::Ancestor::Instance.new(name: module_self.name, args: module_self.args) - definition_pairs.push( - [ - ancestor, - if module_self.name.interface? - build_interface(module_self.name) - else - build_instance(module_self.name) - end - ] - ) - end - end - - merge_definitions(type_name, definition_pairs, entry: entry, self_type: self_type, ancestors: ancestors) end end end def build_singleton(type_name) @@ -448,284 +324,88 @@ 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 = singleton_ancestors(type_name) + ancestors = ancestor_builder.singleton_ancestors(type_name) self_type = Types::ClassSingleton.new(name: type_name, location: nil) instance_type = Types::ClassInstance.new( name: type_name, - args: Types::Variable.build(entry.type_params.each.map(&:name)), + args: entry.type_params.each.map { Types::Bases::Any.new(location: nil) }, location: nil ) - definition_pairs = ancestors.ancestors.map do |ancestor| - # @type block: [Definition::Ancestor::t, Definition] - case ancestor - when Definition::Ancestor::Instance - [ancestor, build_one_instance(ancestor.name)] - when Definition::Ancestor::Singleton - definition = build_one_singleton(ancestor.name) - definition = definition.sub(Substitution.build([], [], instance_type: instance_type)) - definition = definition.map_method_type do |method_type| - s = Substitution.build( - method_type.free_variables.to_a, - method_type.free_variables.map { Types::Bases::Any.new(location: nil) } - ) - method_type.sub(s) - end + Definition.new(type_name: type_name, entry: entry, self_type: self_type, ancestors: ancestors).tap do |definition| + def0 = build_singleton0(type_name) + subst = Substitution.build([], [], instance_type: instance_type) - [ - ancestor, - definition - ] - end - end + merge_definition(src: def0, dest: definition, subst: subst, keep_super: true) - merge_definitions(type_name, definition_pairs, entry: entry, self_type: self_type, ancestors: ancestors) - end - end - end + if entry.is_a?(Environment::ClassEntry) + new_method = definition.methods[:new] + if new_method.defs.all? {|d| d.defined_in == BuiltinNames::Class.name } + # The method is _untyped new_. - def method_definition_members(type_name, entry, kind:) - # @type var interface_methods: Hash[Symbol, [Definition::Method, AST::Members::t]] - interface_methods = {} - # @type var methods: Hash[Symbol, Array[[AST::Members::MethodDefinition, Definition::accessibility]]] - methods = {} + instance = build_instance(type_name) + initialize = instance.methods[:initialize] - entry.decls.each do |d| - each_member_with_accessibility(d.decl.members) do |member, accessibility| - case member - when AST::Members::MethodDefinition - case kind - when :singleton - next unless member.singleton? - when :instance - next unless member.instance? - end + if initialize + class_params = entry.type_params.each.map(&:name) - methods[member.name] ||= [] - methods[member.name] << [ - member.update(types: member.types), - accessibility - ] - when AST::Members::Include, AST::Members::Extend - if member.name.interface? - if (kind == :instance && member.is_a?(AST::Members::Include)) || (kind == :singleton && member.is_a?(AST::Members::Extend)) - NoMixinFoundError.check!(member.name, env: env, member: member) + # Inject a virtual _typed new_. + initialize_defs = initialize.defs + definition.methods[:new] = Definition::Method.new( + super_method: new_method, + defs: initialize_defs.map do |initialize_def| + method_type = initialize_def.type - interface_name = member.name - interface_args = member.args + class_type_param_vars = Set.new(class_params) + method_type_param_vars = Set.new(method_type.type_params) - interface_definition = build_interface(interface_name) + if class_type_param_vars.intersect?(method_type_param_vars) + renamed_method_params = method_type.type_params.map do |name| + if class_type_param_vars.include?(name) + Types::Variable.fresh(name).name + else + name + end + end + method_params = class_params + renamed_method_params - InvalidTypeApplicationError.check!( - type_name: interface_name, - args: interface_args, - params: interface_definition.type_params_decl, - location: member.location - ) + sub = Substitution.build(method_type.type_params, Types::Variable.build(renamed_method_params)) + else + method_params = class_params + method_type.type_params + sub = Substitution.build([], []) + end - sub = Substitution.build(interface_definition.type_params, interface_args) + method_type = method_type.map_type {|ty| ty.sub(sub) } + method_type = method_type.update( + type_params: method_params, + type: method_type.type.with_return_type( + Types::ClassInstance.new( + name: type_name, + args: Types::Variable.build(entry.type_params.each.map(&:name)), + location: nil + ) + ) + ) - interface_definition.methods.each do |name, method| - interface_methods[name] = [method.sub(sub), member] - end - end - end - end - end - end - - # @type var result: Hash[Symbol, member_detail] - result = {} - - interface_methods.each do |name, pair| - method_definition, _ = pair - # @type var detail: member_detail - detail = [:public, method_definition, nil, []] - result[name] = detail - end - - methods.each do |method_name, array| - if result[method_name] - unless array.all? {|pair| pair[0].overload? } - raise MethodDefinitionConflictWithInterfaceMixinError.new( - type_name: type_name, - method_name: method_name, - kind: :instance, - mixin_member: interface_methods[method_name][1], - entries: array.map(&:first) - ) - end - - unless array.all? {|pair| pair[1] == :public } - raise InconsistentMethodVisibilityError.new( - type_name: type_name, - method_name: method_name, - kind: :instance, - member_pairs: array - ) - end - - result[method_name][3].push(*array.map(&:first)) - else - case - when array.size == 1 && !array[0][0].overload? - member, visibility = array[0] - result[method_name] = [visibility, nil, member, []] - - else - visibilities = array.group_by {|pair| pair[1] } - - if visibilities.size > 1 - raise InconsistentMethodVisibilityError.new( - type_name: type_name, - method_name: method_name, - kind: :instance, - member_pairs: array - ) - end - - overloads, primary = array.map(&:first).partition(&:overload?) - result[method_name] = [array[0][1], nil, primary[0], overloads] - end - end - end - - result - end - - def build_one_instance(type_name) - try_cache(type_name, cache: one_instance_cache) do - entry = env.class_decls[type_name] - - param_names = entry.type_params.each.map(&:name) - self_type = Types::ClassInstance.new(name: type_name, - args: Types::Variable.build(param_names), - location: nil) - ancestors = Definition::InstanceAncestors.new( - type_name: type_name, - params: param_names, - ancestors: [Definition::Ancestor::Instance.new(name: type_name, args: self_type.args)] - ) - - Definition.new(type_name: type_name, entry: entry, self_type: self_type, ancestors: ancestors).tap do |definition| - method_definition_members(type_name, entry, kind: :instance).each do |method_name, array| - visibility, method_def, primary_member, overload_members = array - - members = if primary_member - [primary_member, *overload_members] - else - overload_members - end - - m = if method_def - Definition::Method.new( - super_method: nil, - accessibility: visibility, - defs: method_def.defs.map {|defn| defn.update(implemented_in: type_name) }, + 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 ) - else - Definition::Method.new( - super_method: nil, - accessibility: visibility, - defs: [], - alias_of: nil - ) end - - definition.methods[method_name] = members.inject(m) do |original, member| - defs = member.types.map do |method_type| - Definition::Method::TypeDef.new( - type: method_type, - member: member, - implemented_in: type_name, - defined_in: type_name - ) end - - Definition::Method.new( - super_method: nil, - defs: defs + original.defs, - accessibility: original.accessibility, - alias_of: nil - ) end end - - entry.decls.each do |d| - each_member_with_accessibility(d.decl.members) do |member, accessibility| - case member - when AST::Members::AttrReader, AST::Members::AttrAccessor, AST::Members::AttrWriter - if member.kind == :instance - build_attribute( - type_name: type_name, - definition: definition, - member: member, - accessibility: accessibility - ) - end - - when AST::Members::InstanceVariable - definition.instance_variables[member.name] = Definition::Variable.new( - parent_variable: nil, - type: member.type, - declared_in: type_name - ) - - when AST::Members::ClassVariable - definition.class_variables[member.name] = Definition::Variable.new( - parent_variable: nil, - type: member.type, - declared_in: type_name - ) - - end - end - end - - entry.decls.each do |d| - d.decl.members.each do |member| - case member - when AST::Members::Alias - if member.instance? - UnknownMethodAliasError.check!( - methods: definition.methods, - original_name: member.old_name, - aliased_name: member.new_name, - location: member.location - ) - - DuplicatedMethodDefinitionError.check!( - decl: d.decl, - methods: definition.methods, - name: member.new_name, - location: member.location - ) - - original_method = definition.methods[member.old_name] - - definition.methods[member.new_name] = Definition::Method.new( - super_method: original_method.super_method, - defs: original_method.defs, - accessibility: original_method.accessibility, - alias_of: original_method, - annotations: original_method.annotations - ) - end - end - end - end - - entry.decls.each do |d| - validate_parameter_variance( - decl: d.decl, - methods: definition.methods - ) - end end end end def validate_params_with(type_params, result:) @@ -736,353 +416,306 @@ end end end end - def validate_parameter_variance(decl:, methods:) - type_params = decl.type_params + def validate_type_params(definition, ancestors:, methods:) + type_params = definition.type_params_decl calculator = VarianceCalculator.new(builder: self) param_names = type_params.each.map(&:name) - errors = [] + ancestors.each_ancestor do |ancestor| + case ancestor + when Definition::Ancestor::Instance + result = calculator.in_inherit(name: ancestor.name, args: ancestor.args, variables: param_names) + validate_params_with(type_params, result: result) do |param| + location = case source = ancestor.source + when nil + definition.entry.primary.decl.location + when :super + definition.entry.primary.decl.super_class.location + else + source.location + end - case decl - when AST::Declarations::Class - if super_class = decl.super_class - result = calculator.in_inherit(name: super_class.name, args: super_class.args, variables: param_names) - - validate_params_with type_params, result: result do |param| - errors.push InvalidVarianceAnnotationError::InheritanceError.new( - param: param + raise InvalidVarianceAnnotationError.new( + type_name: definition.type_name, + param: param, + location: location ) end end end - # @type var result: VarianceCalculator::Result + methods.each do |defn| + next if defn.name == :initialize - decl.members.each do |member| - case member - when AST::Members::Include - if member.name.class? - result = calculator.in_inherit(name: member.name, args: member.args, variables: param_names) + method_types = case original = defn.original + when AST::Members::MethodDefinition + original.types + when AST::Members::AttrWriter, AST::Members::AttrReader, AST::Members::AttrAccessor + if defn.name.to_s.end_with?("=") + [ + 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: original.location + ) + ] + else + [ + MethodType.new( + type_params: [], + type: Types::Function.empty(original.type), + block: nil, + location: original.location + ) + ] + end + when AST::Members::Alias + nil + when nil + nil + else + raise + end - validate_params_with type_params, result: result do |param| - errors.push InvalidVarianceAnnotationError::MixinError.new( - include_member: member, - param: param - ) - end - end - end - end - - methods.each do |name, method| - method.method_types.each do |method_type| - unless name == :initialize + if method_types + method_types.each do |method_type| result = calculator.in_method_type(method_type: method_type, variables: param_names) - - validate_params_with type_params, result: result do |param| - errors.push InvalidVarianceAnnotationError::MethodTypeError.new( - method_name: name, - method_type: method_type, - param: param + validate_params_with(type_params, result: result) do |param| + raise InvalidVarianceAnnotationError.new( + type_name: definition.type_name, + param: param, + location: method_type.location ) end end end end + end - unless errors.empty? - raise InvalidVarianceAnnotationError.new(decl: decl, errors: errors) - end + def insert_variable(type_name, variables, name:, type:) + variables[name] = Definition::Variable.new( + parent_variable: variables[name], + type: type, + declared_in: type_name + ) end - def build_one_singleton(type_name) - try_cache(type_name, cache: one_singleton_cache) do - entry = env.class_decls[type_name] + def define_methods(definition, interface_methods:, methods:, super_interface_method:) + methods.each do |method_def| + method_name = method_def.name + original = method_def.original - self_type = Types::ClassSingleton.new(name: type_name, location: nil) - ancestors = Definition::SingletonAncestors.new( - type_name: type_name, - ancestors: [Definition::Ancestor::Singleton.new(name: type_name)] - ) + if original.is_a?(AST::Members::Alias) + existing_method = interface_methods[method_name] || definition.methods[method_name] + original_method = interface_methods[original.old_name] || definition.methods[original.old_name] - Definition.new(type_name: type_name, entry: entry, self_type: self_type, ancestors: ancestors).tap do |definition| - method_definition_members(type_name, entry, kind: :singleton).each do |method_name, array| - visibility, method_def, primary_member, overload_members = array + unless original_method + raise UnknownMethodAliasError.new( + original_name: original.old_name, + aliased_name: original.new_name, + location: original.location + ) + end - members = if primary_member - [primary_member, *overload_members] - else - overload_members - 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: method_def.accessibility, + alias_of: original_method + ) + else + if interface_methods.key?(method_name) + interface_method = interface_methods[method_name] - m = Definition::Method.new( - super_method: nil, - defs: method_def&.yield_self do |method_def| - method_def.defs.map {|defn| defn.update(implemented_in: type_name) } - end || [], - accessibility: visibility, - alias_of: nil - ) - definition.methods[method_name] = members.inject(m) do |original, new| - defs = new.types.map do |type| - Definition::Method::TypeDef.new( - type: type, - member: new, - defined_in: type_name, - implemented_in: type_name - ) - end - Definition::Method.new( - super_method: nil, - defs: defs + original.defs, - accessibility: original.accessibility, - alias_of: nil + if method_def.original + raise DuplicatedMethodDefinitionError.new( + type: definition.self_type, + method_name: method_name, + members: [method_def.original] ) end + + definition.methods[method_name] = interface_method end - entry.decls.each do |d| - d.decl.members.each do |member| - case member - when AST::Members::Alias - if member.singleton? - UnknownMethodAliasError.check!( - methods: definition.methods, - original_name: member.old_name, - aliased_name: member.new_name, - location: member.location - ) + existing_method = definition.methods[method_name] - DuplicatedMethodDefinitionError.check!( - decl: d.decl, - methods: definition.methods, - name: member.new_name, - location: member.location - ) - - original_method = definition.methods[member.old_name] - definition.methods[member.new_name] = Definition::Method.new( - super_method: original_method.super_method, - defs: original_method.defs, - accessibility: original_method.accessibility, - alias_of: original_method, - annotations: original_method.annotations - ) - end - end + 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 - end - unless definition.methods.key?(:new) - instance = build_instance(type_name) - initialize = instance.methods[:initialize] + accessibility = if method_name == :initialize + :private + else + method_def.accessibility + end - if initialize - class_params = entry.type_params.each.map(&:name) + method = Definition::Method.new( + super_method: existing_method, + defs: defs, + accessibility: accessibility, + alias_of: nil + ) - initialize_defs = initialize.defs - definition.methods[:new] = Definition::Method.new( - super_method: nil, - defs: initialize_defs.map do |initialize_def| - method_type = initialize_def.type + 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 + ) + ] - class_type_param_vars = Set.new(class_params) - method_type_param_vars = Set.new(method_type.type_params) + method = Definition::Method.new( + super_method: existing_method, + defs: defs, + accessibility: method_def.accessibility, + alias_of: nil + ) - if class_type_param_vars.intersect?(method_type_param_vars) - renamed_method_params = method_type.type_params.map do |name| - if class_type_param_vars.include?(name) - Types::Variable.fresh(name).name - else - name - end - end - method_params = class_params + renamed_method_params - - sub = Substitution.build(method_type.type_params, Types::Variable.build(renamed_method_params)) - else - method_params = class_params + method_type.type_params - sub = Substitution.build([], []) - end - - method_type = method_type.map_type {|ty| ty.sub(sub) } - method_type = method_type.update( - type_params: method_params, - type: method_type.type.with_return_type(Types::Bases::Instance.new(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: [AST::Annotation.new(location: nil, string: "rbs:test:target")], - alias_of: nil + 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 - end - entry.decls.each do |d| - each_member_with_accessibility(d.decl.members) do |member, accessibility| - case member - when AST::Members::AttrReader, AST::Members::AttrAccessor, AST::Members::AttrWriter - if member.kind == :singleton - build_attribute(type_name: type_name, - definition: definition, - member: member, - accessibility: accessibility) - end - - when AST::Members::ClassInstanceVariable - definition.instance_variables[member.name] = Definition::Variable.new( - parent_variable: nil, - type: member.type, - declared_in: type_name - ) - - when AST::Members::ClassVariable - definition.class_variables[member.name] = Definition::Variable.new( - parent_variable: nil, - type: member.type, - declared_in: type_name - ) - 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::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 end - end - end - def build_attribute(type_name:, definition:, member:, accessibility:) - name = member.name - type = member.type - - ivar_name = case member.ivar_name - when false - nil - else - member.ivar_name || :"@#{member.name}" - end - - if member.is_a?(AST::Members::AttrReader) || member.is_a?(AST::Members::AttrAccessor) - definition.methods[name] = Definition::Method.new( - super_method: nil, - defs: [ + method_def.overloads.each do |overload| + defs = overload.types.map do |method_type| Definition::Method::TypeDef.new( - type: MethodType.new( - type_params: [], - type: Types::Function.empty(type), - block: nil, - location: nil - ), - member: member, - defined_in: type_name, - implemented_in: type_name + type: method_type, + member: overload, + defined_in: definition.type_name, + implemented_in: definition.type_name ) - ], - accessibility: accessibility, - alias_of: nil - ) - end + end - if member.is_a?(AST::Members::AttrWriter) || member.is_a?(AST::Members::AttrAccessor) - definition.methods[:"#{name}="] = Definition::Method.new( - super_method: nil, - defs: [ - Definition::Method::TypeDef.new( - type: MethodType.new( - type_params: [], - type: Types::Function.empty(type).update( - required_positionals: [Types::Function::Param.new(name: name, type: type)] - ), - block: nil, - location: nil - ), - member: member, - defined_in: type_name, - implemented_in: type_name - ), - ], - accessibility: accessibility, - alias_of: nil - ) + method.defs.unshift(*defs) + end + + definition.methods[method_name] = method end - if ivar_name - definition.instance_variables[ivar_name] = Definition::Variable.new( - parent_variable: nil, - type: type, - declared_in: type_name - ) + interface_methods.each do |name, method| + unless methods.methods.key?(name) + merge_method(definition.type_name, definition.methods, name, method, Substitution.new) + end end end - def merge_definitions(type_name, pairs, entry:, self_type:, ancestors:) - Definition.new(type_name: type_name, entry: entry, self_type: self_type, ancestors: ancestors).tap do |definition| - pairs.reverse_each do |ancestor, current_definition| - sub = case ancestor - when Definition::Ancestor::Instance - Substitution.build(current_definition.type_params, ancestor.args) - when Definition::Ancestor::Singleton - Substitution.build([], []) - 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 - # @type var kind: method_kind - kind = case ancestor - when Definition::Ancestor::Instance - :instance - when Definition::Ancestor::Singleton - :singleton - end + src.instance_variables.each do |name, variable| + merge_variable(dest.instance_variables, name, variable, subst, keep_super: keep_super) + end - current_definition.methods.each do |name, method| - merge_method type_name, definition.methods, name, method, sub, kind: kind - end - - current_definition.instance_variables.each do |name, variable| - merge_variable definition.instance_variables, name, variable - end - - current_definition.class_variables.each do |name, variable| - merge_variable definition.class_variables, name, variable - end - end + src.class_variables.each do |name, variable| + merge_variable(dest.class_variables, name, variable, subst, keep_super: keep_super) end end - def merge_variable(variables, name, variable) + def merge_variable(variables, name, variable, sub, keep_super: false) super_variable = variables[name] variables[name] = Definition::Variable.new( - parent_variable: super_variable, - type: variable.type, + parent_variable: keep_super ? variable.parent_variable : super_variable, + type: sub.empty? ? variable.type : variable.type.sub(sub), declared_in: variable.declared_in ) end - def merge_method(type_name, methods, name, method, sub, kind:) + def merge_method(type_name, methods, name, method, sub, implemented_in: :keep, keep_super: false) + defs = method.defs.yield_self do |defs| + if sub.empty? && implemented_in == :keep + defs + else + 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 + end + super_method = methods[name] - defs = if method.defs.all? {|d| d.overload? } - raise InvalidOverloadMethodError.new(type_name: type_name, method_name: name, kind: kind, members: method.members) unless super_method - method.defs + super_method.defs - else - method.defs - end - methods[name] = Definition::Method.new( - super_method: super_method, + super_method: keep_super ? method.super_method : super_method, accessibility: method.accessibility, - defs: sub.mapping.empty? ? defs : defs.map {|defn| defn.update(type: defn.type.sub(sub)) }, - alias_of: nil + defs: defs, + alias_of: method.alias_of ) end def try_cache(type_name, cache:) cached = _ = cache[type_name] @@ -1100,106 +733,9 @@ cache.delete(type_name) raise ex end else raise - end - 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 - ) - - Definition.new(type_name: type_name, entry: entry, self_type: self_type, ancestors: nil).tap do |definition| - include_members = [] - def_members = [] - alias_members = [] - - declaration.members.each do |member| - case member - when AST::Members::Include - include_members << member - when AST::Members::MethodDefinition - def_members << member - when AST::Members::Alias - alias_members << member - end - end - - include_members.each do |member| - NoMixinFoundError.check!(member.name, env: env, member: member) - - mixin = build_interface(member.name) - - args = member.args - # @type var interface_entry: Environment::SingleEntry[TypeName, AST::Declarations::Interface] - interface_entry = _ = mixin.entry - type_params = interface_entry.decl.type_params - - InvalidTypeApplicationError.check!( - type_name: type_name, - args: args, - params: type_params.each.map(&:name), - location: member.location - ) - - sub = Substitution.build(type_params.each.map(&:name), args) - mixin.methods.each do |name, method| - definition.methods[name] = method.sub(sub) - end - end - - def_members.each do |member| - DuplicatedMethodDefinitionError.check!( - decl: declaration, - methods: definition.methods, - name: member.name, - location: member.location - ) - - method = Definition::Method.new( - super_method: nil, - defs: member.types.map do |method_type| - Definition::Method::TypeDef.new( - type: method_type, - member: member, - defined_in: type_name, - implemented_in: nil - ) - end, - accessibility: :public, - alias_of: nil - ) - definition.methods[member.name] = method - end - - alias_members.each do |member| - UnknownMethodAliasError.check!( - methods: definition.methods, - original_name: member.old_name, - aliased_name: member.new_name, - location: member.location - ) - - DuplicatedMethodDefinitionError.check!( - decl: declaration, - methods: definition.methods, - name: member.new_name, - location: member.location - ) - - # FIXME: may cause a problem if #old_name has super type - definition.methods[member.new_name] = definition.methods[member.old_name] - end - end end end def expand_alias(type_name) entry = env.alias_decls[type_name] or raise "Unknown name for expand_alias: #{type_name}"