123456789_123456789_123456789_123456789_123456789_

Class: RBS::DefinitionBuilder

Class Method Summary

Instance Attribute Summary

Instance Method Summary

Constructor Details

.new(env:, ancestor_builder: nil, method_builder: nil) ⇒ DefinitionBuilder

[ GitHub ]

  
# File 'lib/rbs/definition_builder.rb', line 14

def initialize(env:, ancestor_builder: nil, method_builder: nil)
  @env = env
  @ancestor_builder = ancestor_builder || AncestorBuilder.new(env: env)
  @method_builder = method_builder || MethodBuilder.new(env: env)

  @instance_cache = {}
  @singleton_cache = {}
  @singleton0_cache = {}
  @interface_cache = {}
end

Instance Attribute Details

#ancestor_builder (readonly)

[ GitHub ]

  
# File 'lib/rbs/definition_builder.rb', line 6

attr_reader :ancestor_builder

#env (readonly)

[ GitHub ]

  
# File 'lib/rbs/definition_builder.rb', line 5

attr_reader :env

#instance_cache (readonly)

[ GitHub ]

  
# File 'lib/rbs/definition_builder.rb', line 9

attr_reader :instance_cache

#interface_cache (readonly)

[ GitHub ]

  
# File 'lib/rbs/definition_builder.rb', line 12

attr_reader :interface_cache

#method_builder (readonly)

[ GitHub ]

  
# File 'lib/rbs/definition_builder.rb', line 7

attr_reader :method_builder

#singleton0_cache (readonly)

[ GitHub ]

  
# File 'lib/rbs/definition_builder.rb', line 11

attr_reader :singleton0_cache

#singleton_cache (readonly)

[ GitHub ]

  
# File 'lib/rbs/definition_builder.rb', line 10

attr_reader :singleton_cache

Instance Method Details

#build_instance(type_name)

[ GitHub ]

  
# File 'lib/rbs/definition_builder.rb', line 168

def build_instance(type_name)
  type_name = env.normalize_module_name(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)

    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)

      validate_type_params definition, methods: methods, ancestors: one_ancestors

      if entry.is_a?(Environment::ClassEntry)
        if super_class = one_ancestors.super_class
          super_class.is_a?(Definition::Ancestor::Instance) or raise

          build_instance(super_class.name).tap do |defn|
            unless super_class.args.empty?
              super_class.args.each do |arg|
                validate_type_presence(arg)
              end

              subst = tapp_subst(super_class.name, super_class.args)
              defn = defn.sub(subst)
            end

            definition.methods.merge!(defn.methods)
            definition.instance_variables.merge!(defn.instance_variables)
            definition.class_variables.merge!(defn.class_variables)
          end
        end
      end

      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

            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
      end

      define_instance(definition, type_name, Substitution.new)
    end
  end
end

#build_interface(type_name)

[ GitHub ]

  
# File 'lib/rbs/definition_builder.rb', line 43

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)

    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|
      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)

      define_interface(definition, type_name, subst)
    end
  end
end

#build_singleton(type_name)

[ GitHub ]

  
# File 'lib/rbs/definition_builder.rb', line 301

def build_singleton(type_name)
  type_name = env.normalize_module_name(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)

    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|
      definition0 = build_singleton0(type_name)
      definition.methods.merge!(definition0.methods)
      definition.instance_variables.merge!(definition0.instance_variables)
      definition.class_variables.merge!(definition0.class_variables)

      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_.

          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

          instance = build_instance(type_name)
          initialize = instance.methods[:initialize]

          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

                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
                  end

                  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_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,
              alias_of: nil
            )

            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
          end
        end
      end
    end
  end
end

#build_singleton0(type_name)

Builds a definition for singleton without .new method.

[ GitHub ]

  
# File 'lib/rbs/definition_builder.rb', line 230

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)

    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)
      methods = method_builder.build_singleton(type_name)

      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

        definition.methods.merge!(defn.methods)
        definition.instance_variables.merge!(defn.instance_variables)
        definition.class_variables.merge!(defn.class_variables)
      end

      one_ancestors.each_extended_module 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

      all_interfaces = one_ancestors.each_extended_interface.flat_map do |interface|
        other_interfaces = ancestor_builder.interface_ancestors(interface.name).ancestors #: Array[Definition::Ancestor::Instance]
        other_interfaces = other_interfaces.select {|ancestor| ancestor.source }
        [interface, *other_interfaces]
      end
      interface_methods = interface_methods(all_interfaces)
      import_methods(definition, type_name, methods, interface_methods, Substitution.new, nil)

      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
        end
      end
    end
  end
end

#define_instance(definition, type_name, subst)

[ GitHub ]

  
# File 'lib/rbs/definition_builder.rb', line 85

def define_instance(definition, type_name, subst)
  one_ancestors = ancestor_builder.one_instance_ancestors(type_name)
  methods = method_builder.build_instance(type_name)

  self_type_methods = one_ancestors.each_self_type.with_object({}) do |self_type, hash| #$ Hash[Symbol, Definition::Method]
    self_type.args.each do |arg|
      validate_type_presence(arg)
    end

    self_type_defn = self_type.name.interface? ? build_interface(self_type.name) : build_instance(self_type.name)

    s = subst + tapp_subst(self_type.name, self_type.args)
    self_type_defn.methods.each do |method_name, method_def|
      hash[method_name] = method_def.sub(s)
    end
  end

  one_ancestors.each_included_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

  all_interfaces = one_ancestors.each_included_interface.flat_map do |interface|
    other_interfaces = ancestor_builder.interface_ancestors(interface.name).ancestors #: Array[Definition::Ancestor::Instance]
    other_interfaces = other_interfaces.select {|ancestor| ancestor.source }
    [interface, *other_interfaces]
  end
  interface_methods = interface_methods(all_interfaces)
  import_methods(definition, type_name, methods, interface_methods, subst, self_type_methods)

  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
        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)
      end
    end
  end
end

#define_interface(definition, type_name, subst)

[ GitHub ]

  
# File 'lib/rbs/definition_builder.rb', line 33

def define_interface(definition, type_name, subst)
  included_interfaces = ancestor_builder.interface_ancestors(type_name).ancestors #: Array[Definition::Ancestor::Instance]
  included_interfaces = included_interfaces.reject {|ancestor| ancestor.source == nil }

  interface_methods = interface_methods(included_interfaces)
  methods = method_builder.build_interface(type_name)

  import_methods(definition, type_name, methods, interface_methods, subst, nil)
end

#define_method(methods, definition, method, subst, self_type_methods, defined_in:, implemented_in: defined_in)

[ GitHub ]

  
# File 'lib/rbs/definition_builder.rb', line 606

def define_method(methods, definition, method, subst, self_type_methods, defined_in:, implemented_in: defined_in)
  existing_method = methods[method.name] || definition.methods[method.name]

  case original = method.original
  when AST::Members::Alias
    original_method = methods[original.old_name] || definition.methods[original.old_name] || self_type_methods&.fetch(original.old_name, nil)

    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 = 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

    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

    # @type var accessibility: RBS::Definition::accessibility
    accessibility =
      if original.instance? && [:initialize, :initialize_copy, :initialize_clone, :initialize_dup, :respond_to_missing?].include?(method.name)
        :private
      else
        method.accessibility
      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

    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

    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: original.location
        )
      else
        # getter
        MethodType.new(
          type_params: [],
          type: Types::Function.empty(attr_type),
          block: nil,
          location: original.location
        )
      end

    if implemented_in
      super_method = existing_method
    end

    method_definition = Definition::Method.new(
      super_method: super_method,
      defs: [
        Definition::Method::TypeDef.new(
          type: method_type,
          member: original,
          defined_in: defined_in,
          implemented_in: implemented_in
        )
      ],
      accessibility: method.accessibility,
      alias_of: nil
    )
  when nil
    # Overloading method definition only

    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

    method_definition = Definition::Method.new(
      super_method: super_method,
      defs: existing_method.defs.map do |defn|
        defn.update(implemented_in: implemented_in)
      end,
      accessibility: existing_method.accessibility,
      alias_of: existing_method.alias_of
    )
  end

  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: defined_in,
        implemented_in: implemented_in
      )

      method_definition.defs.unshift(type_def)
    end
  end

  methods[method.name] = method_definition
end

#ensure_namespace!(namespace, location:)

[ GitHub ]

  
# File 'lib/rbs/definition_builder.rb', line 25

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

#expand_alias(type_name)

[ GitHub ]

  
# File 'lib/rbs/definition_builder.rb', line 767

def expand_alias(type_name)
  expand_alias2(type_name, [])
end

#expand_alias1(type_name)

[ GitHub ]

  
# File 'lib/rbs/definition_builder.rb', line 771

def expand_alias1(type_name)
  type_name = env.normalize_type_name(type_name)
  entry = env.type_alias_decls[type_name] or raise "Unknown alias name: #{type_name}"
  as = entry.decl.type_params.each.map { Types::Bases::Any.new(location: nil) }
  expand_alias2(type_name, as)
end

#expand_alias2(type_name, args)

[ GitHub ]

  
# File 'lib/rbs/definition_builder.rb', line 778

def expand_alias2(type_name, args)
  type_name = env.normalize_type_name(type_name)
  entry = env.type_alias_decls[type_name] or raise "Unknown alias name: #{type_name}"

  ensure_namespace!(type_name.namespace, location: entry.decl.location)
  params = entry.decl.type_params.each.map(&:name)

  unless params.size == args.size
    as = "[#{args.join(", ")}]" unless args.empty?
    ps = "[#{params.join(", ")}]" unless params.empty?

    raise "Invalid type application: type = #{type_name}#{as}, decl = #{type_name}#{ps}"
  end

  type = entry.decl.type

  unless params.empty?
    subst = Substitution.build(params, args)
    type = type.sub(subst)
  end

  type
end

#import_methods(definition, module_name, module_methods, interfaces_methods, subst, self_type_methods)

[ GitHub ]

  
# File 'lib/rbs/definition_builder.rb', line 545

def import_methods(definition, module_name, module_methods, interfaces_methods, subst, self_type_methods)
  new_methods = {} #: Hash[Symbol, Definition::Method]
  interface_method_duplicates = Set[] #: Set[Symbol]

  interfaces_methods.each do |interface, (methods, member)|
    unless interface.args.empty?
      methods.type.is_a?(Types::Interface) or raise

      interface.args.each do |arg|
        validate_type_presence(arg)
      end

      type_params = env.interface_decls.fetch(interface.name).decl.type_params
      if s = AST::TypeParam.application(type_params, interface.args)
        subst_ = subst + s
      else
        subst_ = subst
      end
    else
      subst_ = subst
    end

    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

        raise DuplicatedInterfaceMethodDefinitionError.new(
          type: definition.self_type,
          method_name: method.name,
          member: member
        )
      end

      interface_method_duplicates << method.name
      define_method(
        new_methods,
        definition,
        method,
        subst_,
        nil,
        defined_in: interface.name,
        implemented_in: module_name
      )
    end
  end

  module_methods.each do |method|
    define_method(
      new_methods,
      definition,
      method,
      subst,
      self_type_methods,
      defined_in: module_name,
      implemented_in: module_name.interface? ? nil : module_name
    )
  end

  definition.methods.merge!(new_methods)
end

#insert_variable(type_name, variables, name:, type:)

[ GitHub ]

  
# File 'lib/rbs/definition_builder.rb', line 537

def insert_variable(type_name, variables, name:, type:)
  variables[name] = Definition::Variable.new(
    parent_variable: variables[name],
    type: type,
    declared_in: type_name
  )
end

#interface_methods(interface_ancestors)

[ GitHub ]

  
# File 'lib/rbs/definition_builder.rb', line 411

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

#source_location(source, decl)

[ GitHub ]

  
# File 'lib/rbs/definition_builder.rb', line 441

def source_location(source, decl)
  case source
  when nil
    decl.location
  when :super
    case decl
    when AST::Declarations::Class
      decl.super_class&.location
    end
  else
    source.location
  end
end

#tapp_subst(name, args)

[ GitHub ]

  
# File 'lib/rbs/definition_builder.rb', line 66

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.type_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

  AST::TypeParam.application(params, args) || Substitution.new()
end

#try_cache(type_name, cache:)

[ GitHub ]

  
# File 'lib/rbs/definition_builder.rb', line 763

def try_cache(type_name, cache:)
  cache[type_name] ||= yield
end

#update(env:, except:, ancestor_builder:)

[ GitHub ]

  
# File 'lib/rbs/definition_builder.rb', line 802

def update(env:, except:, ancestor_builder:)
  method_builder = self.method_builder.update(env: env, except: except)

  DefinitionBuilder.new(env: env, ancestor_builder: ancestor_builder, method_builder: method_builder).tap do |builder|
    builder.instance_cache.merge!(instance_cache)
    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)
      builder.singleton_cache.delete(name)
      builder.singleton0_cache.delete(name)
      builder.interface_cache.delete(name)
    end
  end
end

#validate_params_with(type_params, result:)

[ GitHub ]

  
# File 'lib/rbs/definition_builder.rb', line 431

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
      end
    end
  end
end

#validate_type_name(name, location)

Raises:

[ GitHub ]

  
# File 'lib/rbs/definition_builder.rb', line 831

def validate_type_name(name, location)
  name = name.absolute! unless name.absolute?
  return if env.type_name?(env.normalize_type_name(name))

  raise NoTypeFoundError.new(type_name: name, location: location)
end

#validate_type_params(definition, ancestors:, methods:)

[ GitHub ]

  
# File 'lib/rbs/definition_builder.rb', line 455

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)

  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|
        decl = case entry = definition.entry
               when Environment::ModuleEntry, Environment::ClassEntry
                 entry.primary.decl
               when Environment::SingleEntry
                 entry.decl
               end

        raise InvalidVarianceAnnotationError.new(
          type_name: definition.type_name,
          param: param,
          location: source_location(ancestor.source, decl)
        )
      end
    end
  end

  methods.each do |defn|
    next if defn.name == :initialize

    method_types = case original = defn.original
                   when AST::Members::MethodDefinition
                     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: [],
                           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
                   end

    if method_types
      method_types.each do |method_type|
        merged_params = type_params
          .reject {|param| method_type.type_param_names.include?(param.name) }
          .concat(method_type.type_params)

        result = calculator.in_method_type(method_type: method_type, variables: param_names)
        validate_params_with(merged_params, result: result) do |param|
          raise InvalidVarianceAnnotationError.new(
            type_name: definition.type_name,
            param: param,
            location: method_type.location
          )
        end
      end
    end
  end
end

#validate_type_presence(type)

[ GitHub ]

  
# File 'lib/rbs/definition_builder.rb', line 820

def validate_type_presence(type)
  case type
  when Types::ClassInstance, Types::ClassSingleton, Types::Interface, Types::Alias
    validate_type_name(type.name, type.location)
  end

  type.each_type do |type|
    validate_type_presence(type)
  end
end