class RBS::DefinitionBuilder::AncestorBuilder - rbs: Ruby Standard Library Documentation

# class RBS::DefinitionBuilder::AncestorBuilder

### Attributes

env[R]
instance_ancestors_cache[R]
interface_ancestors_cache[R]
one_instance_ancestors_cache[R]
one_interface_ancestors_cache[R]
one_singleton_ancestors_cache[R]
singleton_ancestors_cache[R]

### Public Class Methods

new(env:) click to toggle source

    # File rbs-3.8.0/lib/rbs/definition_builder/ancestor_builder.rb, line 162
    def initialize(env:)
      @env = env

      @one_instance_ancestors_cache = {}
      @instance_ancestors_cache = {}

      @one_singleton_ancestors_cache = {}
      @singleton_ancestors_cache = {}

      @one_interface_ancestors_cache = {}
      @interface_ancestors_cache = {}
    end

### Public Instance Methods

fill_ancestor_source(ancestor, name:, source:, &block) click to toggle source

    # File rbs-3.8.0/lib/rbs/definition_builder/ancestor_builder.rb, line 606
    def fill_ancestor_source(ancestor, name:, source:, &block)
      case ancestor
      when Definition::Ancestor::Instance
        if ancestor.name == name && !ancestor.source
          Definition::Ancestor::Instance.new(name: ancestor.name, args: ancestor.args, source: source)
        else
          ancestor
        end
      else
        ancestor
      end
    end

instance_ancestors(type_name, building_ancestors: []) click to toggle source

    # File rbs-3.8.0/lib/rbs/definition_builder/ancestor_builder.rb, line 434
    def instance_ancestors(type_name, building_ancestors: [])
      as = instance_ancestors_cache[type_name] and return as

      entry = env.class_decls[type_name] or raise "Unknown name for instance_ancestors: #{type_name}"
      params = entry.type_params.each.map(&:name)
      args = entry.type_params.map do |type_param|
        Types::Variable.new(name: type_param.name, location: type_param.location)
      end
      self_ancestor = Definition::Ancestor::Instance.new(name: type_name, args: args, source: nil)

      RecursiveAncestorError.check!(self_ancestor,
                                    ancestors: building_ancestors,
                                    location: entry.primary.decl.location)
      building_ancestors.push self_ancestor

      one_ancestors = one_instance_ancestors(type_name)

      # @type var ancestors: Array[::RBS::Definition::Ancestor::t]
      ancestors = []

      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

          super_ancestors =
            instance_ancestors(super_name, building_ancestors: building_ancestors)
              .apply(super_args, env: env, location: entry.primary.decl.super_class&.location)
          super_ancestors.map! {|ancestor| fill_ancestor_source(ancestor, name: super_name, source: :super) }
          ancestors.unshift(*super_ancestors)
        end
      end

      if self_types = one_ancestors.self_types
        self_types.each do |mod|
          if mod.name.class?
            # Ensure there is no loop in ancestors chain
            instance_ancestors(mod.name, building_ancestors: building_ancestors)
          end
        end
      end

      if included_modules = one_ancestors.included_modules
        included_modules.each do |mod|
          name = mod.name
          arg_types = mod.args
          mod.source.is_a?(AST::Members::Include) or raise
          mod_ancestors =
            instance_ancestors(name, building_ancestors: building_ancestors)
              .apply(arg_types, env: env, location: mod.source.location)
          mod_ancestors.map! {|ancestor| fill_ancestor_source(ancestor, name: name, source: mod.source) }
          ancestors.unshift(*mod_ancestors)
        end
      end

      ancestors.unshift(self_ancestor)

      if prepended_modules = one_ancestors.prepended_modules
        prepended_modules.each do |mod|
          name = mod.name
          arg_types = mod.args
          mod.source.is_a?(AST::Members::Prepend) or raise
          mod_ancestors =
            instance_ancestors(name, building_ancestors: building_ancestors)
              .apply(arg_types, env: env, location: mod.source.location)
          mod_ancestors.map! {|ancestor| fill_ancestor_source(ancestor, name: name, source: mod.source) }
          ancestors.unshift(*mod_ancestors)
        end
      end

      building_ancestors.pop

      instance_ancestors_cache[type_name] = Definition::InstanceAncestors.new(
        type_name: type_name,
        params: params,
        ancestors: ancestors
      )
    end

interface_ancestors(type_name, building_ancestors: []) click to toggle source

    # File rbs-3.8.0/lib/rbs/definition_builder/ancestor_builder.rb, line 570
    def interface_ancestors(type_name, building_ancestors: [])
      as = interface_ancestors_cache[type_name] and return as

      entry = env.interface_decls[type_name] or raise "Unknown name for interface_ancestors: #{type_name}"
      params = entry.decl.type_params.each.map(&:name)
      args = Types::Variable.build(params)
      self_ancestor = Definition::Ancestor::Instance.new(name: type_name, args: args, source: nil)

      RecursiveAncestorError.check!(self_ancestor,
                                    ancestors: building_ancestors,
                                    location: entry.decl.location)
      building_ancestors.push self_ancestor

      one_ancestors = one_interface_ancestors(type_name)
      ancestors = [] #: Array[Definition::Ancestor::t]

      included_interfaces = one_ancestors.included_interfaces or raise
      included_interfaces.each do |a|
        a.source.is_a?(AST::Members::Include) or raise
        included_ancestors =
          interface_ancestors(a.name, building_ancestors: building_ancestors)
            .apply(a.args, env: env, location: a.source.location)
        included_ancestors.map! {|ancestor| fill_ancestor_source(ancestor, name: a.name, source: a.source) }
        ancestors.unshift(*included_ancestors)
      end

      ancestors.unshift(self_ancestor)
      building_ancestors.pop

      interface_ancestors_cache[type_name] = Definition::InstanceAncestors.new(
        type_name: type_name,
        params: params,
        ancestors: ancestors
      )
    end

mixin_ancestors(entry, type_name, included_modules:, included_interfaces:, extended_modules:, prepended_modules:, extended_interfaces:) click to toggle source

    # File rbs-3.8.0/lib/rbs/definition_builder/ancestor_builder.rb, line 414
    def mixin_ancestors(entry, type_name, included_modules:, included_interfaces:, extended_modules:, prepended_modules:, extended_interfaces:)
      entry.decls.each do |d|
        decl = d.decl

        align_params = Substitution.build(
          decl.type_params.each.map(&:name),
          entry.type_params.map {|param| Types::Variable.new(name: param.name, location: param.location) }
        )

        mixin_ancestors0(decl,
                         type_name,
                         align_params: align_params,
                         included_modules: included_modules,
                         included_interfaces: included_interfaces,
                         extended_modules: extended_modules,
                         prepended_modules: prepended_modules,
                         extended_interfaces: extended_interfaces)
      end
    end

mixin_ancestors0(decl, type_name, align_params:, included_modules:, included_interfaces:, extended_modules:, prepended_modules:, extended_interfaces:) click to toggle source

    # File rbs-3.8.0/lib/rbs/definition_builder/ancestor_builder.rb, line 348
    def mixin_ancestors0(decl, type_name, align_params:, included_modules:, included_interfaces:, extended_modules:, prepended_modules:, extended_interfaces:)
      decl.each_mixin do |member|
        case member
        when AST::Members::Include
          module_name = member.name
          module_args = member.args.map {|type| align_params ? type.sub(align_params) : type }

          case
          when member.name.class? && included_modules
            MixinClassError.check!(type_name: type_name, env: env, member: member)
            NoMixinFoundError.check!(member.name, env: env, member: member)

            module_decl = env.normalized_module_entry(module_name) or raise
            module_args = AST::TypeParam.normalize_args(module_decl.type_params, module_args)

            module_name = env.normalize_module_name(module_name)
            included_modules << Definition::Ancestor::Instance.new(name: module_name, args: module_args, source: member)
          when member.name.interface? && included_interfaces
            NoMixinFoundError.check!(member.name, env: env, member: member)

            interface_decl = env.interface_decls.fetch(module_name)
            module_args = AST::TypeParam.normalize_args(interface_decl.decl.type_params, module_args)

            included_interfaces << Definition::Ancestor::Instance.new(name: module_name, args: module_args, source: member)
          end

        when AST::Members::Prepend
          if prepended_modules
            MixinClassError.check!(type_name: type_name, env: env, member: member)
            NoMixinFoundError.check!(member.name, env: env, member: member)

            module_decl = env.normalized_module_entry(member.name) or raise
            module_name = module_decl.name

            module_args = member.args.map {|type| align_params ? type.sub(align_params) : type }
            module_args = AST::TypeParam.normalize_args(module_decl.type_params, module_args)

            prepended_modules << Definition::Ancestor::Instance.new(name: module_name, args: module_args, source: member)
          end

        when AST::Members::Extend
          module_name = member.name
          module_args = member.args

          case
          when member.name.class? && extended_modules
            MixinClassError.check!(type_name: type_name, env: env, member: member)
            NoMixinFoundError.check!(member.name, env: env, member: member)

            module_decl = env.normalized_module_entry(module_name) or raise
            module_args = AST::TypeParam.normalize_args(module_decl.type_params, module_args)

            module_name = env.normalize_module_name(module_name)
            extended_modules << Definition::Ancestor::Instance.new(name: module_name, args: module_args, source: member)
          when member.name.interface? && extended_interfaces
            NoMixinFoundError.check!(member.name, env: env, member: member)

            interface_decl = env.interface_decls.fetch(module_name)
            module_args = AST::TypeParam.normalize_args(interface_decl.decl.type_params, module_args)

            extended_interfaces << Definition::Ancestor::Instance.new(name: module_name, args: module_args, source: member)
          end
        end
      end
    end

one_instance_ancestors(type_name) click to toggle source

    # File rbs-3.8.0/lib/rbs/definition_builder/ancestor_builder.rb, line 192
    def one_instance_ancestors(type_name)
      type_name = env.normalize_module_name(type_name)

      as = one_instance_ancestors_cache[type_name] and return as

      entry = env.class_decls[type_name] or raise "Unknown name for one_instance_ancestors: #{type_name}"
      params = entry.type_params.each.map(&: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
            super_args = super_class.args
          else
            super_name = BuiltinNames::Object.name
            super_args = [] #: Array[Types::t]
          end

          super_name = env.normalize_module_name(super_name)

          NoSuperclassFoundError.check!(super_name, env: env, location: primary.decl.location)
          if super_class
            InheritModuleError.check!(super_class, env: env)
          end

          super_entry = env.normalized_class_entry(super_name) or raise
          super_args = AST::TypeParam.normalize_args(super_entry.type_params, super_args)

          ancestors = OneAncestors.class_instance(
            type_name: type_name,
            params: params,
            super_class: Definition::Ancestor::Instance.new(name: super_name, args: super_args, source: :super)
          )
        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)

        self_types = ancestors.self_types or raise
        if entry.self_types.empty?
          self_types.push Definition::Ancestor::Instance.new(name: BuiltinNames::Object.name, args: [], source: nil)
        else
          entry.self_types.each do |module_self|
            NoSelfTypeFoundError.check!(module_self, env: env)

            module_name = module_self.name
            if module_name.class?
              module_entry = env.normalized_module_class_entry(module_name) or raise
              module_name = module_entry.name
              self_args = AST::TypeParam.normalize_args(module_entry.type_params, module_self.args)
            end
            if module_name.interface?
              interface_entry = env.interface_decls.fetch(module_name)
              self_args = AST::TypeParam.normalize_args(interface_entry.decl.type_params, module_self.args)
            end
            self_args or raise

            self_types.push Definition::Ancestor::Instance.new(name: module_name, args: self_args, source: module_self)
          end
        end
      end

      mixin_ancestors(entry,
                      type_name,
                      included_modules: ancestors.included_modules,
                      included_interfaces: ancestors.included_interfaces,
                      prepended_modules: ancestors.prepended_modules,
                      extended_modules: nil,
                      extended_interfaces: nil)

      one_instance_ancestors_cache[type_name] = ancestors
    end

one_interface_ancestors(type_name) click to toggle source

    # File rbs-3.8.0/lib/rbs/definition_builder/ancestor_builder.rb, line 329
    def one_interface_ancestors(type_name)
      one_interface_ancestors_cache[type_name] ||=
        begin
          entry = env.interface_decls[type_name] or raise "Unknown name for one_interface_ancestors: #{type_name}"
          params = entry.decl.type_params.each.map(&:name)

          OneAncestors.interface(type_name: type_name, params: params).tap do |ancestors|
            mixin_ancestors0(entry.decl,
                             type_name,
                             align_params: nil,
                             included_modules: nil,
                             included_interfaces: ancestors.included_interfaces,
                             prepended_modules: nil,
                             extended_modules: nil,
                             extended_interfaces: nil)
          end
        end
    end

one_singleton_ancestors(type_name) click to toggle source

    # File rbs-3.8.0/lib/rbs/definition_builder/ancestor_builder.rb, line 275
    def one_singleton_ancestors(type_name)
      type_name = env.normalize_module_name(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
          end

          super_name = env.normalize_module_name(super_name)

          NoSuperclassFoundError.check!(super_name, env: env, location: primary.decl.location)
          if super_class
            InheritModuleError.check!(super_class, env: env)
          end

          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: [], source: :super)
          )
        end
      when Environment::ModuleEntry
        ancestors = OneAncestors.singleton(
          type_name: type_name,
          super_class: Definition::Ancestor::Instance.new(name: BuiltinNames::Module.name, args: [], source: :super)
        )
      end

      mixin_ancestors(entry,
                      type_name,
                      included_modules: nil,
                      included_interfaces: nil,
                      prepended_modules: nil,
                      extended_modules: ancestors.extended_modules,
                      extended_interfaces: ancestors.extended_interfaces)

      one_singleton_ancestors_cache[type_name] = ancestors
    end

singleton_ancestors(type_name, building_ancestors: []) click to toggle source

    # File rbs-3.8.0/lib/rbs/definition_builder/ancestor_builder.rb, line 515
    def singleton_ancestors(type_name, building_ancestors: [])
      as = singleton_ancestors_cache[type_name] and return as

      entry = env.class_decls[type_name] or raise "Unknown name for singleton_ancestors: #{type_name}"
      self_ancestor = Definition::Ancestor::Singleton.new(name: type_name)

      RecursiveAncestorError.check!(self_ancestor,
                                    ancestors: building_ancestors,
                                    location: entry.primary.decl.location)
      building_ancestors.push self_ancestor

      one_ancestors = one_singleton_ancestors(type_name)

      ancestors = [] #: Array[Definition::Ancestor::t]

      case super_class = one_ancestors.super_class
      when Definition::Ancestor::Instance
        super_name = super_class.name
        super_args = super_class.args

        super_ancestors =
          instance_ancestors(super_name, building_ancestors: building_ancestors)
            .apply(super_args, env: env, location: nil)
        super_ancestors.map! {|ancestor| fill_ancestor_source(ancestor, name: super_name, source: :super) }
        ancestors.unshift(*super_ancestors)

      when Definition::Ancestor::Singleton
        super_name = super_class.name

        super_ancestors = singleton_ancestors(super_name, building_ancestors: [])
        ancestors.unshift(*super_ancestors.ancestors)
      end

      extended_modules = one_ancestors.extended_modules or raise
      extended_modules.each do |mod|
        name = mod.name
        args = mod.args
        mod.source.is_a?(AST::Members::Extend) or raise
        mod_ancestors =
          instance_ancestors(name, building_ancestors: building_ancestors)
            .apply(args, env: env, location: mod.source.location)
        mod_ancestors.map! {|ancestor| fill_ancestor_source(ancestor, name: name, source: mod.source) }
        ancestors.unshift(*mod_ancestors)
      end

      ancestors.unshift(self_ancestor)

      building_ancestors.pop

      singleton_ancestors_cache[type_name] = Definition::SingletonAncestors.new(
        type_name: type_name,
        ancestors: ancestors
      )
    end

validate_super_class!(type_name, entry) click to toggle source

    # File rbs-3.8.0/lib/rbs/definition_builder/ancestor_builder.rb, line 175
    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)
      end

      super_types.uniq!

      return if super_types.size == 1

      raise SuperclassMismatchError.new(name: type_name, entry: entry)
    end