123456789_123456789_123456789_123456789_123456789_

Class: RBS::Validator

Relationships & Source Files
Inherits: Object
Defined in: lib/rbs/validator.rb

Class Method Summary

Instance Attribute Summary

Instance Method Summary

Constructor Details

.new(env:, resolver:) ⇒ Validator

[ GitHub ]

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

def initialize(env:, resolver:)
  @env = env
  @resolver = resolver
  @definition_builder = DefinitionBuilder.new(env: env)
end

Instance Attribute Details

#definition_builder (readonly)

[ GitHub ]

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

attr_reader :definition_builder

#env (readonly)

[ GitHub ]

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

attr_reader :env

#resolver (readonly)

[ GitHub ]

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

attr_reader :resolver

Instance Method Details

#absolute_type(type, context:)

[ GitHub ]

  
# File 'lib/rbs/validator.rb', line 15

def absolute_type(type, context:)
  type.map_type_name do |type_name, _, type|
    resolver.resolve(type_name, context: context) || yield(type)
  end
end

#type_alias_dependency

[ GitHub ]

  
# File 'lib/rbs/validator.rb', line 149

def type_alias_dependency
  @type_alias_dependency ||= TypeAliasDependency.new(env: env)
end

#type_alias_regularity

[ GitHub ]

  
# File 'lib/rbs/validator.rb', line 153

def type_alias_regularity
  @type_alias_regularity ||= TypeAliasRegularity.validate(env: env)
end

#validate_method_definition(method_def, type_name:)

[ GitHub ]

  
# File 'lib/rbs/validator.rb', line 100

def validate_method_definition(method_def, type_name:)
  method_def.types.each do |method_type|
    unless method_type.type_params.empty?
      loc = method_type.location&.aref(:type_params)

      validate_type_params(
        method_type.type_params,
        type_name: type_name,
        method_name: method_def.name,
        location: loc
      )
    end
  end
end

#validate_type(type, context:)

Validates presence of the relative type, and application arity match.

[ GitHub ]

  
# File 'lib/rbs/validator.rb', line 22

def validate_type(type, context:)
  case type
  when Types::ClassInstance, Types::Interface, Types::Alias
    # @type var type: Types::ClassInstance | Types::Interface | Types::Alias
    if type.name.namespace.relative?
      type = _ = absolute_type(type, context: context) do |_|
        NoTypeFoundError.check!(type.name.absolute!, env: env, location: type.location)
      end
    end

    definition_builder.validate_type_name(type.name, type.location)

    type_params = case type
                  when Types::ClassInstance
                    env.class_decls[type.name].type_params
                  when Types::Interface
                    env.interface_decls[type.name].decl.type_params
                  when Types::Alias
                    env.alias_decls[type.name].decl.type_params
                  end

    InvalidTypeApplicationError.check!(
      type_name: type.name,
      args: type.args,
      params: type_params.each.map(&:name),
      location: type.location
    )

  when Types::ClassSingleton
    definition_builder.validate_type_presence(type)
  end

  type.each_type do |type|
    validate_type(type, context: context)
  end
end

#validate_type_alias(entry:)

[ GitHub ]

  
# File 'lib/rbs/validator.rb', line 59

def validate_type_alias(entry:)
  type_name = entry.decl.name

  if type_alias_dependency.circular_definition?(type_name)
    location = entry.decl.location or raise
    raise RecursiveTypeAliasError.new(alias_names: [type_name], location: location)
  end

  if diagnostic = type_alias_regularity.nonregular?(type_name)
    location = entry.decl.location or raise
    raise NonregularTypeAliasError.new(diagnostic: diagnostic, location: location)
  end

  unless entry.decl.type_params.empty?
    calculator = VarianceCalculator.new(builder: definition_builder)
    result = calculator.in_type_alias(name: type_name)
    if set = result.incompatible?(entry.decl.type_params)
      set.each do |param_name|
        param = entry.decl.type_params.find {|param| param.name == param_name } or raise
        next if param.unchecked?

        raise InvalidVarianceAnnotationError.new(
          type_name: type_name,
          param: param,
          location: entry.decl.type.location
        )
      end
    end

    validate_type_params(
      entry.decl.type_params,
      type_name: type_name,
      location: entry.decl.location&.aref(:type_params)
    )
  end

  if block_given?
    yield entry.decl.type
  end
end

#validate_type_params(params, type_name:, method_name: nil, location:)

[ GitHub ]

  
# File 'lib/rbs/validator.rb', line 115

def validate_type_params(params, type_name: , method_name: nil, location:)
  # @type var each_node: TSort::_EachNode[Symbol]
  each_node = __skip__ = -> (&block) do
    params.each do |param|
      block[param.name]
    end
  end
  # @type var each_child: TSort::_EachChild[Symbol]
  each_child = __skip__ = -> (name, &block) do
    if param = params.find {|p| p.name == name }
      if b = param.upper_bound
        b.free_variables.each do |tv|
          block[tv]
        end
      end
    end
  end

  TSort.each_strongly_connected_component(each_node, each_child) do |names|
    if names.size > 1
      params = names.map do |name|
        params.find {|param| param.name == name} or raise
      end

      raise CyclicTypeParameterBound.new(
        type_name: type_name,
        method_name: method_name,
        params: params,
        location: location
      )
    end
  end
end