Class: RBS::Validator
- Inherits:
-
Object
- Object
- RBS::Validator
- Defined in:
- lib/rbs/validator.rb,
sig/validator.rbs
Instance Attribute Summary collapse
-
#definition_builder ⇒ DefinitionBuilder
readonly
Returns the value of attribute definition_builder.
-
#env ⇒ Environment
readonly
Returns the value of attribute env.
-
#resolver ⇒ Resolver::TypeNameResolver?
readonly
Returns the value of attribute resolver.
-
#type_alias_dependency ⇒ TypeAliasDependency
readonly
Returns the value of attribute type_alias_dependency.
-
#type_alias_regularity ⇒ TypeAliasRegularity
readonly
Returns the value of attribute type_alias_regularity.
Instance Method Summary collapse
-
#absolute_type(type, context:, &block) ⇒ void
Resolves relative type names to absolute type names in given context.
-
#initialize(env:, resolver: nil) ⇒ Validator
constructor
A new instance of Validator.
-
#validate_class_alias(entry:) ⇒ void
Validates class alias declaration.
-
#validate_method_definition(method_def, type_name:) ⇒ void
Validates the type parameters in generic methods.
-
#validate_type(type, context:) ⇒ void
Validates the presence of type names and type application arity match.
-
#validate_type_alias(entry:) ⇒ void
Validates type alias definition:.
-
#validate_type_params(params, type_name:, method_name: nil, location:) ⇒ void
Validates the type parameters if there is no circular dependencies between the bounds.
-
#validate_variable(var) ⇒ void
Validates instance/class-instance/class variables.
Constructor Details
#initialize(env:, resolver: nil) ⇒ Validator
Returns a new instance of Validator.
9 10 11 12 13 |
# File 'lib/rbs/validator.rb', line 9 def initialize(env:, resolver: nil) @env = env @resolver = resolver @definition_builder = DefinitionBuilder.new(env: env) end |
Instance Attribute Details
#definition_builder ⇒ DefinitionBuilder (readonly)
Returns the value of attribute definition_builder.
7 8 9 |
# File 'lib/rbs/validator.rb', line 7 def definition_builder @definition_builder end |
#env ⇒ Environment (readonly)
Returns the value of attribute env.
5 6 7 |
# File 'lib/rbs/validator.rb', line 5 def env @env end |
#resolver ⇒ Resolver::TypeNameResolver? (readonly)
Returns the value of attribute resolver.
6 7 8 |
# File 'lib/rbs/validator.rb', line 6 def resolver @resolver end |
#type_alias_dependency ⇒ TypeAliasDependency (readonly)
Returns the value of attribute type_alias_dependency.
178 179 180 |
# File 'lib/rbs/validator.rb', line 178 def type_alias_dependency @type_alias_dependency ||= TypeAliasDependency.new(env: env) end |
#type_alias_regularity ⇒ TypeAliasRegularity (readonly)
Returns the value of attribute type_alias_regularity.
182 183 184 |
# File 'lib/rbs/validator.rb', line 182 def type_alias_regularity @type_alias_regularity ||= TypeAliasRegularity.validate(env: env) end |
Instance Method Details
#absolute_type(type, context:, &block) ⇒ void
This method returns an undefined value.
Resolves relative type names to absolute type names in given context.
Yields the type when the type name resolution using #resolver fails.
61 62 63 64 65 66 67 |
# File 'sig/validator.rbs', line 61 def absolute_type(type, context:, &block) return type unless resolver type.map_type_name do |type_name, _, type| resolver.resolve(type_name, context: context) || (block ? yield(type) : type_name) end end |
#validate_class_alias(entry:) ⇒ void
This method returns an undefined value.
Validates class alias declaration
- The right hand side can be normalized
- No mixing alias declaration between class and modules
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
# File 'sig/validator.rbs', line 50 def validate_class_alias(entry:) case env.normalize_module_name?(entry.decl.new_name) when nil raise NoTypeFoundError.new(type_name: entry.decl.old_name, location: entry.decl.location&.[](:old_name)) when false raise CyclicClassAliasDefinitionError.new(entry) end case entry when Environment::ClassAliasEntry unless env.class_entry(entry.decl.old_name) raise InconsistentClassModuleAliasError.new(entry) end when Environment::ModuleAliasEntry unless env.module_entry(entry.decl.old_name) raise InconsistentClassModuleAliasError.new(entry) end end end |
#validate_method_definition(method_def, type_name:) ⇒ void
This method returns an undefined value.
Validates the type parameters in generic methods.
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
# File 'sig/validator.rbs', line 32 def validate_method_definition(method_def, type_name:) method_def.overloads.each do |overload| method_type = overload.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:) ⇒ void
This method returns an undefined value.
Validates the presence of type names and type application arity match.
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/rbs/validator.rb', line 24 def validate_type(type, context:) case type when Types::ClassInstance, Types::Interface, Types::Alias type = absolute_type(type, context: context) #: Types::ClassInstance | Types::Interface | Types::Alias definition_builder.validate_type_name(type.name, type.location) normalized_type_name = env.normalize_type_name?(type.name) if normalized_type_name type_params = case type when Types::ClassInstance entry = env.class_decls[normalized_type_name] or raise entry.type_params when Types::Interface env.interface_decls[normalized_type_name].decl.type_params when Types::Alias env.type_alias_decls[normalized_type_name].decl.type_params end InvalidTypeApplicationError.check!( type_name: type.name, args: type.args, params: type_params, location: type.location ) end when Types::ClassSingleton type = absolute_type(type, context: context) #: 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:) ⇒ void
This method returns an undefined value.
Validates type alias definition:
- There is no circular definition between aliases
- The type alias is regular
- The generics type parameter variance annotation is consistent with respect to their usage
- There is no circular dependencies between the generics type parameter bounds
It yields the rhs type if block is given, so that you can validate the rhs type.
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'sig/validator.rbs', line 28 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:) ⇒ void
This method returns an undefined value.
Validates the type parameters if there is no circular dependencies between the bounds.
[X, Y] # OK
[X, Y < _Foo[X]] # OK
[X < _Foo[Y], Y] # OK
[X < _Foo[Y], Y < _Foo[X]] # Error
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
# File 'sig/validator.rbs', line 43 def validate_type_params(params, type_name: , method_name: nil, location:) # @type var each_node: ^() { (Symbol) -> void } -> void each_node = -> (&block) do params.each do |param| block[param.name] end end # @type var each_child: ^(Symbol) { (Symbol) -> void } -> void each_child = -> (name, &block) do if param = params.find {|p| p.name == name } [param.upper_bound_type, param.lower_bound_type].compact.each do |bound| bound.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 |
#validate_variable(var) ⇒ void
This method returns an undefined value.
Validates instance/class-instance/class variables.
54 55 56 |
# File 'sig/validator.rbs', line 54 def validate_variable(var) validate_type(var.type, context: nil) end |