diff --git a/docs/syntax.md b/docs/syntax.md index b53a0b4ed..de550e108 100644 --- a/docs/syntax.md +++ b/docs/syntax.md @@ -236,7 +236,7 @@ We have contextual limitations on some types: These contextual limitation is introduced at RBS 3.3. The parser accepts those types even if it doesn't satisfy contextual limitation, but warning is reported with `rbs validate` command. -We plan to change the parser to reject those types if it breaks the contextual limitations in next release -- `3.4`. +Since RBS 4.0, it is reported during parsing. #### Limitations on `void` types diff --git a/ext/rbs_extension/main.c b/ext/rbs_extension/main.c index 30bea00af..304f03172 100644 --- a/ext/rbs_extension/main.c +++ b/ext/rbs_extension/main.c @@ -7,6 +7,7 @@ #include "rbs_string_bridging.h" #include "ruby/vm.h" +#include "rbs/parser.h" /** * Raises `RBS::ParsingError` or `RuntimeError` on `tok` with message constructed with given `fmt`. @@ -101,7 +102,7 @@ static VALUE parse_type_try(VALUE a) { } rbs_node_t *type; - rbs_parse_type(parser, &type); + rbs_parse_type(parser, &type, SkipValidation); raise_error_if_any(parser, arg->buffer); @@ -187,7 +188,7 @@ static VALUE parse_method_type_try(VALUE a) { } rbs_method_type_t *method_type = NULL; - rbs_parse_method_type(parser, &method_type); + rbs_parse_method_type(parser, &method_type, SkipValidation); raise_error_if_any(parser, arg->buffer); diff --git a/include/rbs/parser.h b/include/rbs/parser.h index c7f3c2e4f..9ada61197 100644 --- a/include/rbs/parser.h +++ b/include/rbs/parser.h @@ -126,8 +126,24 @@ rbs_ast_comment_t *rbs_parser_get_comment(rbs_parser_t *parser, int subject_line void rbs_parser_set_error(rbs_parser_t *parser, rbs_token_t tok, bool syntax_error, const char *fmt, ...) RBS_ATTRIBUTE_FORMAT(4, 5); -bool rbs_parse_type(rbs_parser_t *parser, rbs_node_t **type); -bool rbs_parse_method_type(rbs_parser_t *parser, rbs_method_type_t **method_type); +/** + * rbs_type_parsing_option_t represents the validation rules for type parsing. + * It controls whether certain types are allowed in specific contexts. + * */ +typedef struct { + bool no_void; /* If true, `void` type is not allowed.*/ + bool no_void_allowed_here; /* If true, `void` type is not allowed, but it's allowed in one depth.*/ + bool no_self; /* If true, `self` type is not allowed.*/ + bool no_classish; /* If true, `class` or `instance` types are not allowed.*/ +} rbs_type_parsing_option_t; + +/** + * SkipValidation is a rbs_type_parsing_option_t that allows all types. + * */ +extern const rbs_type_parsing_option_t SkipValidation; + +bool rbs_parse_type(rbs_parser_t *parser, rbs_node_t **type, rbs_type_parsing_option_t validation); +bool rbs_parse_method_type(rbs_parser_t *parser, rbs_method_type_t **method_type, rbs_type_parsing_option_t validation); bool rbs_parse_signature(rbs_parser_t *parser, rbs_signature_t **signature); bool rbs_parse_type_params(rbs_parser_t *parser, bool module_type_params, rbs_node_list_t **params); diff --git a/lib/rbs/cli/validate.rb b/lib/rbs/cli/validate.rb index d7feb02f8..1a94b2cf8 100644 --- a/lib/rbs/cli/validate.rb +++ b/lib/rbs/cli/validate.rb @@ -4,31 +4,18 @@ module RBS class CLI class Validate class Errors - def initialize(limit:, exit_error:) + def initialize(limit:) @limit = limit - @exit_error = exit_error @errors = [] - @has_syntax_error = false end def add(error) - if error.instance_of?(WillSyntaxError) - RBS.logger.warn(build_message(error)) - @has_syntax_error = true - else - @errors << error - end + @errors << error finish if @limit == 1 end def finish - if @errors.empty? - if @exit_error && @has_syntax_error - exit 1 - else - # success - end - else + unless @errors.empty? @errors.each do |error| RBS.logger.error(build_message(error)) end @@ -53,7 +40,6 @@ def initialize(args:, options:) @env = Environment.from_loader(loader).resolve_type_names @builder = DefinitionBuilder.new(env: @env) @validator = Validator.new(env: @env) - exit_error = false limit = nil #: Integer? OptionParser.new do |opts| opts.banner = < error @@ -288,9 +237,6 @@ def validate_constant RBS.logger.info "Validating constant: `#{name}`..." @validator.validate_type const.decl.type, context: const.context @builder.ensure_namespace!(name.namespace, location: const.decl.location) - no_self_type_validator(const.decl.type) - no_classish_type_validator(const.decl.type) - void_type_context_validator(const.decl.type) rescue BaseError => error @errors.add(error) end @@ -300,9 +246,6 @@ def validate_global @env.global_decls.each do |name, global| RBS.logger.info "Validating global: `#{name}`..." @validator.validate_type global.decl.type, context: nil - no_self_type_validator(global.decl.type) - no_classish_type_validator(global.decl.type) - void_type_context_validator(global.decl.type) rescue BaseError => error @errors.add(error) end @@ -325,9 +268,6 @@ def validate_type_alias decl.decl.type_params.each do |param| if ub = param.upper_bound_type - void_type_context_validator(ub) - no_self_type_validator(ub) - no_classish_type_validator(ub) @validator.validate_type(ub, context: nil) end @@ -339,45 +279,15 @@ def validate_type_alias end if dt = param.default_type - void_type_context_validator(dt, true) - no_self_type_validator(dt) - no_classish_type_validator(dt) @validator.validate_type(dt, context: nil) end end TypeParamDefaultReferenceError.check!(decl.decl.type_params) - - no_self_type_validator(decl.decl.type) - no_classish_type_validator(decl.decl.type) - void_type_context_validator(decl.decl.type) rescue BaseError => error @errors.add(error) end end - - private - - def no_self_type_validator(type) - if type.has_self_type? - @errors.add WillSyntaxError.new("`self` type is not allowed in this context", location: type.location) - end - end - - def no_classish_type_validator(type) - if type.has_classish_type? - @errors.add WillSyntaxError.new("`instance` or `class` type is not allowed in this context", location: type.location) - end - end - - def void_type_context_validator(type, allowed_here = false) - if allowed_here - return if type.is_a?(Types::Bases::Void) - end - if type.with_nonreturn_void? - @errors.add WillSyntaxError.new("`void` type is only allowed in return type or generics parameter", location: type.location) - end - end end end end diff --git a/lib/rbs/errors.rb b/lib/rbs/errors.rb index 1d21eca9b..fe374319a 100644 --- a/lib/rbs/errors.rb +++ b/lib/rbs/errors.rb @@ -591,17 +591,6 @@ def location end end - class WillSyntaxError < DefinitionError - include DetailedMessageable - - attr_reader :location - - def initialize(message, location:) - super "#{Location.to_string(location)}: #{message}" - @location = location - end - end - class TypeParamDefaultReferenceError < DefinitionError include DetailedMessageable diff --git a/lib/rbs/prototype/rb.rb b/lib/rbs/prototype/rb.rb index c5aedc12d..c90575eec 100644 --- a/lib/rbs/prototype/rb.rb +++ b/lib/rbs/prototype/rb.rb @@ -372,8 +372,8 @@ def process(node, decls:, comments:, context:) end value_node = node.children.last - type = if value_node.nil? - # Give up type prediction when node is MASGN. + type = if value_node.nil? || value_node.type == :SELF + # Give up type prediction when node is MASGN or SELF. Types::Bases::Any.new(location: nil) else literal_to_type(value_node) diff --git a/sig/cli/validate.rbs b/sig/cli/validate.rbs index 65909e73d..aa120c753 100644 --- a/sig/cli/validate.rbs +++ b/sig/cli/validate.rbs @@ -3,11 +3,9 @@ module RBS class Validate class Errors @limit: Integer? - @exit_error: boolish - @has_syntax_error: bool @errors: Array[BaseError] - def initialize: (limit: Integer?, exit_error: boolish) -> void + def initialize: (limit: Integer?) -> void def add: (BaseError) -> void diff --git a/sig/errors.rbs b/sig/errors.rbs index f041c99f7..95de6ee16 100644 --- a/sig/errors.rbs +++ b/sig/errors.rbs @@ -387,14 +387,6 @@ module RBS def location: () -> AST::Declarations::AliasDecl::loc? end - class WillSyntaxError < BaseError - include RBS::DetailedMessageable - - def initialize: (String message, location: Location[untyped, untyped]?) -> void - - attr_reader location: Location[untyped, untyped]? - end - class TypeParamDefaultReferenceError < BaseError include DetailedMessageable diff --git a/src/parser.c b/src/parser.c index 64ce26986..b87ddd865 100644 --- a/src/parser.c +++ b/src/parser.c @@ -106,6 +106,13 @@ typedef struct id_table { struct id_table *next; } id_table; +const rbs_type_parsing_option_t SkipValidation = { + .no_void = false, + .no_void_allowed_here = false, + .no_self = false, + .no_classish = false, +}; + static bool rbs_is_untyped_params(method_params *params) { return params->required_positionals == NULL; } @@ -120,8 +127,8 @@ static rbs_location_t *rbs_location_current_token(rbs_parser_t *parser) { return rbs_location_new(ALLOCATOR(), parser->current_token.range); } -static bool parse_optional(rbs_parser_t *parser, rbs_node_t **optional); -static bool parse_simple(rbs_parser_t *parser, rbs_node_t **type); +static bool parse_optional(rbs_parser_t *parser, rbs_node_t **optional, rbs_type_parsing_option_t validation); +static bool parse_simple(rbs_parser_t *parser, rbs_node_t **type, rbs_type_parsing_option_t validation); /** * @returns A borrowed copy of the current token, which does *not* need to be freed. @@ -244,10 +251,10 @@ error_handling: { | {} type `,` ... `,` eol */ NODISCARD -static bool parse_type_list(rbs_parser_t *parser, enum RBSTokenType eol, rbs_node_list_t *types) { +static bool parse_type_list(rbs_parser_t *parser, enum RBSTokenType eol, rbs_node_list_t *types, rbs_type_parsing_option_t validation) { while (true) { rbs_node_t *type; - CHECK_PARSE(rbs_parse_type(parser, &type)); + CHECK_PARSE(rbs_parse_type(parser, &type, validation)); rbs_node_list_append(types, type); if (parser->next_token.type == pCOMMA) { @@ -289,11 +296,11 @@ static bool is_keyword_token(enum RBSTokenType type) { | {} type */ NODISCARD -static bool parse_function_param(rbs_parser_t *parser, rbs_types_function_param_t **function_param) { +static bool parse_function_param(rbs_parser_t *parser, rbs_types_function_param_t **function_param, rbs_type_parsing_option_t validation) { rbs_range_t type_range; type_range.start = parser->next_token.range.start; rbs_node_t *type; - CHECK_PARSE(rbs_parse_type(parser, &type)); + CHECK_PARSE(rbs_parse_type(parser, &type, validation)); type_range.end = parser->current_token.range.end; if (parser->next_token.type == pCOMMA || parser->next_token.type == pRPAREN) { @@ -386,7 +393,7 @@ static bool parse_keyword(rbs_parser_t *parser, rbs_hash_t *keywords, rbs_hash_t ADVANCE_ASSERT(parser, pCOLON); rbs_types_function_param_t *param = NULL; - CHECK_PARSE(parse_function_param(parser, ¶m)); + CHECK_PARSE(parse_function_param(parser, ¶m, SkipValidation)); rbs_hash_set(keywords, (rbs_node_t *) key, (rbs_node_t *) param); @@ -457,7 +464,7 @@ static bool parser_advance_if(rbs_parser_t *parser, enum RBSTokenType type) { | {} `**` */ NODISCARD -static bool parse_params(rbs_parser_t *parser, method_params *params) { +static bool parse_params(rbs_parser_t *parser, method_params *params, rbs_type_parsing_option_t validation) { if (parser->next_token.type == pQUESTION && parser->next_token2.type == pRPAREN) { params->required_positionals = NULL; rbs_parser_advance(parser); @@ -486,7 +493,7 @@ static bool parse_params(rbs_parser_t *parser, method_params *params) { } rbs_types_function_param_t *param = NULL; - CHECK_PARSE(parse_function_param(parser, ¶m)); + CHECK_PARSE(parse_function_param(parser, ¶m, validation)); rbs_node_list_append(params->required_positionals, (rbs_node_t *) param); break; @@ -510,7 +517,7 @@ static bool parse_params(rbs_parser_t *parser, method_params *params) { } rbs_types_function_param_t *param = NULL; - CHECK_PARSE(parse_function_param(parser, ¶m)); + CHECK_PARSE(parse_function_param(parser, ¶m, validation)); rbs_node_list_append(params->optional_positionals, (rbs_node_t *) param); break; @@ -527,7 +534,7 @@ static bool parse_params(rbs_parser_t *parser, method_params *params) { if (parser->next_token.type == pSTAR) { rbs_parser_advance(parser); rbs_types_function_param_t *param = NULL; - CHECK_PARSE(parse_function_param(parser, ¶m)); + CHECK_PARSE(parse_function_param(parser, ¶m, validation)); params->rest_positionals = (rbs_node_t *) param; if (!parser_advance_if(parser, pCOMMA)) { @@ -554,7 +561,7 @@ static bool parse_params(rbs_parser_t *parser, method_params *params) { } rbs_types_function_param_t *param = NULL; - CHECK_PARSE(parse_function_param(parser, ¶m)); + CHECK_PARSE(parse_function_param(parser, ¶m, validation)); rbs_node_list_append(params->trailing_positionals, (rbs_node_t *) param); break; @@ -581,7 +588,7 @@ static bool parse_params(rbs_parser_t *parser, method_params *params) { case pSTAR2: rbs_parser_advance(parser); rbs_types_function_param_t *param = NULL; - CHECK_PARSE(parse_function_param(parser, ¶m)); + CHECK_PARSE(parse_function_param(parser, ¶m, validation)); params->rest_keywords = (rbs_node_t *) param; break; @@ -623,12 +630,12 @@ static bool parse_params(rbs_parser_t *parser, method_params *params) { | {} simple_type <`?`> */ NODISCARD -static bool parse_optional(rbs_parser_t *parser, rbs_node_t **optional) { +static bool parse_optional(rbs_parser_t *parser, rbs_node_t **optional, rbs_type_parsing_option_t validation) { rbs_range_t rg; rg.start = parser->next_token.range.start; rbs_node_t *type = NULL; - CHECK_PARSE(parse_simple(parser, &type)); + CHECK_PARSE(parse_simple(parser, &type, validation)); if (parser->next_token.type == pQUESTION) { rbs_parser_advance(parser); @@ -659,13 +666,13 @@ static void initialize_method_params(method_params *params, rbs_allocator_t *all | {} `[` `self` `:` type <`]`> */ NODISCARD -static bool parse_self_type_binding(rbs_parser_t *parser, rbs_node_t **self_type) { +static bool parse_self_type_binding(rbs_parser_t *parser, rbs_node_t **self_type, rbs_type_parsing_option_t validation) { if (parser->next_token.type == pLBRACKET) { rbs_parser_advance(parser); ADVANCE_ASSERT(parser, kSELF); ADVANCE_ASSERT(parser, pCOLON); rbs_node_t *type; - CHECK_PARSE(rbs_parse_type(parser, &type)); + CHECK_PARSE(rbs_parse_type(parser, &type, validation)); ADVANCE_ASSERT(parser, pRBRACKET); *self_type = type; } @@ -687,25 +694,27 @@ typedef struct { | {} self_type_binding? `->` */ NODISCARD -static bool parse_function(rbs_parser_t *parser, bool accept_type_binding, parse_function_result **result) { +static bool parse_function(rbs_parser_t *parser, bool accept_type_binding, parse_function_result **result, rbs_type_parsing_option_t validation) { rbs_node_t *function = NULL; rbs_types_block_t *block = NULL; rbs_node_t *function_self_type = NULL; rbs_range_t function_range; function_range.start = parser->current_token.range.start; + rbs_type_parsing_option_t no_void_allowed_here = validation; + no_void_allowed_here.no_void_allowed_here = true; method_params params; initialize_method_params(¶ms, ALLOCATOR()); if (parser->next_token.type == pLPAREN) { rbs_parser_advance(parser); - CHECK_PARSE(parse_params(parser, ¶ms)); + CHECK_PARSE(parse_params(parser, ¶ms, validation)); ADVANCE_ASSERT(parser, pRPAREN); } // Passing NULL to function_self_type means the function itself doesn't accept self type binding. (== method type) if (accept_type_binding) { - CHECK_PARSE(parse_self_type_binding(parser, &function_self_type)); + CHECK_PARSE(parse_self_type_binding(parser, &function_self_type, validation)); } else { if (rbs_is_untyped_params(¶ms)) { if (parser->next_token.type != pARROW) { @@ -735,16 +744,16 @@ static bool parse_function(rbs_parser_t *parser, bool accept_type_binding, parse if (parser->next_token.type == pLPAREN) { rbs_parser_advance(parser); - CHECK_PARSE(parse_params(parser, &block_params)); + CHECK_PARSE(parse_params(parser, &block_params, validation)); ADVANCE_ASSERT(parser, pRPAREN); } rbs_node_t *self_type = NULL; - CHECK_PARSE(parse_self_type_binding(parser, &self_type)); + CHECK_PARSE(parse_self_type_binding(parser, &self_type, validation)); ADVANCE_ASSERT(parser, pARROW); rbs_node_t *block_return_type = NULL; - CHECK_PARSE(parse_optional(parser, &block_return_type)); + CHECK_PARSE(parse_optional(parser, &block_return_type, no_void_allowed_here)); ADVANCE_ASSERT(parser, pRBRACE); @@ -774,7 +783,7 @@ static bool parse_function(rbs_parser_t *parser, bool accept_type_binding, parse ADVANCE_ASSERT(parser, pARROW); rbs_node_t *type = NULL; - CHECK_PARSE(parse_optional(parser, &type)); + CHECK_PARSE(parse_optional(parser, &type, no_void_allowed_here)); function_range.end = parser->current_token.range.end; rbs_location_t *loc = rbs_location_new(ALLOCATOR(), function_range); @@ -805,10 +814,10 @@ static bool parse_function(rbs_parser_t *parser, bool accept_type_binding, parse proc_type ::= {`^`} */ NODISCARD -static bool parse_proc_type(rbs_parser_t *parser, rbs_types_proc_t **proc) { +static bool parse_proc_type(rbs_parser_t *parser, rbs_types_proc_t **proc, rbs_type_parsing_option_t validation) { rbs_position_t start = parser->current_token.range.start; parse_function_result *result = rbs_allocator_alloc(ALLOCATOR(), parse_function_result); - CHECK_PARSE(parse_function(parser, true, &result)); + CHECK_PARSE(parse_function(parser, true, &result, validation)); rbs_position_t end = parser->current_token.range.end; rbs_location_t *loc = rbs_location_new(ALLOCATOR(), (rbs_range_t) { .start = start, .end = end }); @@ -833,7 +842,7 @@ static void check_key_duplication(rbs_parser_t *parser, rbs_hash_t *fields, rbs_ | {} literal_type `=>` */ NODISCARD -static bool parse_record_attributes(rbs_parser_t *parser, rbs_hash_t **fields) { +static bool parse_record_attributes(rbs_parser_t *parser, rbs_hash_t **fields, rbs_type_parsing_option_t validation) { *fields = rbs_hash_new(ALLOCATOR()); if (parser->next_token.type == pRBRACE) return true; @@ -866,7 +875,7 @@ static bool parse_record_attributes(rbs_parser_t *parser, rbs_hash_t **fields) { case kTRUE: case kFALSE: { rbs_node_t *type = NULL; - CHECK_PARSE(parse_simple(parser, &type)); + CHECK_PARSE(parse_simple(parser, &type, validation)); key = (rbs_ast_symbol_t *) ((rbs_types_literal_t *) type)->literal; break; @@ -883,7 +892,7 @@ static bool parse_record_attributes(rbs_parser_t *parser, rbs_hash_t **fields) { field_range.start = parser->current_token.range.end; rbs_node_t *type; - CHECK_PARSE(rbs_parse_type(parser, &type)); + CHECK_PARSE(rbs_parse_type(parser, &type, validation)); field_range.end = parser->current_token.range.end; rbs_location_t *loc = rbs_location_new(ALLOCATOR(), field_range); @@ -990,7 +999,13 @@ static bool parse_instance_type(rbs_parser_t *parser, bool parse_alias, rbs_node if (parser->next_token.type == pLBRACKET) { rbs_parser_advance(parser); args_range.start = parser->current_token.range.start; - CHECK_PARSE(parse_type_list(parser, pRBRACKET, types)); + rbs_type_parsing_option_t no_void_allowed_here = { + .no_void = false, + .no_void_allowed_here = true, + .no_self = false, + .no_classish = false, + }; + CHECK_PARSE(parse_type_list(parser, pRBRACKET, types, no_void_allowed_here)); ADVANCE_ASSERT(parser, pRBRACKET); args_range.end = parser->current_token.range.end; } else { @@ -1077,13 +1092,17 @@ static bool parser_typevar_member(rbs_parser_t *parser, rbs_constant_id_t id) { | {} `^` */ NODISCARD -static bool parse_simple(rbs_parser_t *parser, rbs_node_t **type) { +static bool parse_simple(rbs_parser_t *parser, rbs_node_t **type, rbs_type_parsing_option_t validation) { rbs_parser_advance(parser); + if (parser->current_token.type != kVOID) { + validation.no_void_allowed_here = false; + } + switch (parser->current_token.type) { case pLPAREN: { rbs_node_t *lparen_type; - CHECK_PARSE(rbs_parse_type(parser, &lparen_type)); + CHECK_PARSE(rbs_parse_type(parser, &lparen_type, validation)); ADVANCE_ASSERT(parser, pRPAREN); *type = lparen_type; return true; @@ -1099,11 +1118,19 @@ static bool parse_simple(rbs_parser_t *parser, rbs_node_t **type) { return true; } case kCLASS: { + if (validation.no_classish) { + rbs_parser_set_error(parser, parser->current_token, true, "`class` type is not allowed in this context"); + return false; + } rbs_location_t *loc = rbs_location_current_token(parser); *type = (rbs_node_t *) rbs_types_bases_class_new(ALLOCATOR(), loc); return true; } case kINSTANCE: { + if (validation.no_classish) { + rbs_parser_set_error(parser, parser->current_token, true, "`instance` type is not allowed in this context"); + return false; + } rbs_location_t *loc = rbs_location_current_token(parser); *type = (rbs_node_t *) rbs_types_bases_instance_new(ALLOCATOR(), loc); return true; @@ -1114,6 +1141,10 @@ static bool parse_simple(rbs_parser_t *parser, rbs_node_t **type) { return true; } case kSELF: { + if (validation.no_self) { + rbs_parser_set_error(parser, parser->current_token, true, "`self` type is not allowed in this context"); + return false; + } rbs_location_t *loc = rbs_location_current_token(parser); *type = (rbs_node_t *) rbs_types_bases_self_new(ALLOCATOR(), loc); return true; @@ -1124,6 +1155,10 @@ static bool parse_simple(rbs_parser_t *parser, rbs_node_t **type) { return true; } case kVOID: { + if (validation.no_void && !validation.no_void_allowed_here) { + rbs_parser_set_error(parser, parser->current_token, true, "`void` type is only allowed in return type or generics parameter"); + return false; + } rbs_location_t *loc = rbs_location_current_token(parser); *type = (rbs_node_t *) rbs_types_bases_void_new(ALLOCATOR(), loc); return true; @@ -1212,7 +1247,7 @@ static bool parse_simple(rbs_parser_t *parser, rbs_node_t **type) { rg.start = parser->current_token.range.start; rbs_node_list_t *types = rbs_node_list_new(ALLOCATOR()); if (parser->next_token.type != pRBRACKET) { - CHECK_PARSE(parse_type_list(parser, pRBRACKET, types)); + CHECK_PARSE(parse_type_list(parser, pRBRACKET, types, validation)); } ADVANCE_ASSERT(parser, pRBRACKET); rg.end = parser->current_token.range.end; @@ -1230,7 +1265,7 @@ static bool parse_simple(rbs_parser_t *parser, rbs_node_t **type) { case pLBRACE: { rbs_position_t start = parser->current_token.range.start; rbs_hash_t *fields = NULL; - CHECK_PARSE(parse_record_attributes(parser, &fields)); + CHECK_PARSE(parse_record_attributes(parser, &fields, validation)); ADVANCE_ASSERT(parser, pRBRACE); rbs_position_t end = parser->current_token.range.end; rbs_location_t *loc = rbs_location_new(ALLOCATOR(), (rbs_range_t) { .start = start, .end = end }); @@ -1239,7 +1274,7 @@ static bool parse_simple(rbs_parser_t *parser, rbs_node_t **type) { } case pHAT: { rbs_types_proc_t *value = NULL; - CHECK_PARSE(parse_proc_type(parser, &value)); + CHECK_PARSE(parse_proc_type(parser, &value, validation)); *type = (rbs_node_t *) value; return true; } @@ -1254,12 +1289,12 @@ static bool parse_simple(rbs_parser_t *parser, rbs_node_t **type) { | {} */ NODISCARD -static bool parse_intersection(rbs_parser_t *parser, rbs_node_t **type) { +static bool parse_intersection(rbs_parser_t *parser, rbs_node_t **type, rbs_type_parsing_option_t validation) { rbs_range_t rg; rg.start = parser->next_token.range.start; rbs_node_t *optional = NULL; - CHECK_PARSE(parse_optional(parser, &optional)); + CHECK_PARSE(parse_optional(parser, &optional, validation)); *type = optional; rbs_node_list_t *intersection_types = rbs_node_list_new(ALLOCATOR()); @@ -1268,7 +1303,7 @@ static bool parse_intersection(rbs_parser_t *parser, rbs_node_t **type) { while (parser->next_token.type == pAMP) { rbs_parser_advance(parser); rbs_node_t *type = NULL; - CHECK_PARSE(parse_optional(parser, &type)); + CHECK_PARSE(parse_optional(parser, &type, validation)); rbs_node_list_append(intersection_types, type); } @@ -1286,19 +1321,19 @@ static bool parse_intersection(rbs_parser_t *parser, rbs_node_t **type) { union ::= {} intersection '|' ... '|' | {} */ -bool rbs_parse_type(rbs_parser_t *parser, rbs_node_t **type) { +bool rbs_parse_type(rbs_parser_t *parser, rbs_node_t **type, rbs_type_parsing_option_t validation) { rbs_range_t rg; rg.start = parser->next_token.range.start; rbs_node_list_t *union_types = rbs_node_list_new(ALLOCATOR()); - CHECK_PARSE(parse_intersection(parser, type)); + CHECK_PARSE(parse_intersection(parser, type, validation)); rbs_node_list_append(union_types, *type); while (parser->next_token.type == pBAR) { rbs_parser_advance(parser); rbs_node_t *intersection = NULL; - CHECK_PARSE(parse_intersection(parser, &intersection)); + CHECK_PARSE(parse_intersection(parser, &intersection, validation)); rbs_node_list_append(union_types, intersection); } @@ -1391,7 +1426,7 @@ static bool parse_type_params(rbs_parser_t *parser, rbs_range_t *rg, bool module rbs_parser_advance(parser); upper_bound_range.start = parser->current_token.range.start; - CHECK_PARSE(rbs_parse_type(parser, &upper_bound)); + CHECK_PARSE(rbs_parse_type(parser, &upper_bound, (rbs_type_parsing_option_t) { .no_void = true, .no_self = true, .no_classish = true })); upper_bound_range.end = parser->current_token.range.end; break; @@ -1403,7 +1438,7 @@ static bool parse_type_params(rbs_parser_t *parser, rbs_range_t *rg, bool module rbs_parser_advance(parser); lower_bound_range.start = parser->current_token.range.start; - CHECK_PARSE(rbs_parse_type(parser, &lower_bound)); + CHECK_PARSE(rbs_parse_type(parser, &lower_bound, (rbs_type_parsing_option_t) { .no_void = true, .no_self = true, .no_classish = true })); lower_bound_range.end = parser->current_token.range.end; break; @@ -1418,7 +1453,7 @@ static bool parse_type_params(rbs_parser_t *parser, rbs_range_t *rg, bool module rbs_parser_advance(parser); default_type_range.start = parser->current_token.range.start; - CHECK_PARSE(rbs_parse_type(parser, &default_type)); + CHECK_PARSE(rbs_parse_type(parser, &default_type, (rbs_type_parsing_option_t) { .no_void = true, .no_void_allowed_here = true, .no_self = true, .no_classish = true })); default_type_range.end = parser->current_token.range.end; required_param_allowed = false; @@ -1488,7 +1523,7 @@ static bool parser_pop_typevar_table(rbs_parser_t *parser) { method_type ::= {} type_params */ // TODO: Should this be NODISCARD? -bool rbs_parse_method_type(rbs_parser_t *parser, rbs_method_type_t **method_type) { +bool rbs_parse_method_type(rbs_parser_t *parser, rbs_method_type_t **method_type, rbs_type_parsing_option_t validation) { rbs_parser_push_typevar_table(parser, false); rbs_range_t rg; @@ -1502,7 +1537,7 @@ bool rbs_parse_method_type(rbs_parser_t *parser, rbs_method_type_t **method_type type_range.start = parser->next_token.range.start; parse_function_result *result = rbs_allocator_alloc(ALLOCATOR(), parse_function_result); - CHECK_PARSE(parse_function(parser, false, &result)); + CHECK_PARSE(parse_function(parser, false, &result, validation)); rg.end = parser->current_token.range.end; type_range.end = rg.end; @@ -1537,7 +1572,7 @@ static bool parse_global_decl(rbs_parser_t *parser, rbs_node_list_t *annotations rbs_range_t colon_range = parser->current_token.range; rbs_node_t *type; - CHECK_PARSE(rbs_parse_type(parser, &type)); + CHECK_PARSE(rbs_parse_type(parser, &type, (rbs_type_parsing_option_t) { .no_void = true, .no_self = true, .no_classish = true })); decl_range.end = parser->current_token.range.end; rbs_location_t *loc = rbs_location_new(ALLOCATOR(), decl_range); @@ -1567,7 +1602,7 @@ static bool parse_const_decl(rbs_parser_t *parser, rbs_node_list_t *annotations, rbs_range_t colon_range = parser->current_token.range; rbs_node_t *type; - CHECK_PARSE(rbs_parse_type(parser, &type)); + CHECK_PARSE(rbs_parse_type(parser, &type, (rbs_type_parsing_option_t) { .no_void = true, .no_self = true, .no_classish = true })); decl_range.end = parser->current_token.range.end; @@ -1607,7 +1642,7 @@ static bool parse_type_decl(rbs_parser_t *parser, rbs_position_t comment_pos, rb rbs_range_t eq_range = parser->current_token.range; rbs_node_t *type; - CHECK_PARSE(rbs_parse_type(parser, &type)); + CHECK_PARSE(rbs_parse_type(parser, &type, (rbs_type_parsing_option_t) { .no_void = true, .no_self = true, .no_classish = true })); decl_range.end = parser->current_token.range.end; @@ -1916,7 +1951,7 @@ static bool parse_member_def(rbs_parser_t *parser, bool instance_only, bool acce case pLBRACKET: case pQUESTION: { rbs_method_type_t *method_type = NULL; - CHECK_PARSE(rbs_parse_method_type(parser, &method_type)); + CHECK_PARSE(rbs_parse_method_type(parser, &method_type, instance_only ? (rbs_type_parsing_option_t) { .no_void = true, .no_classish = true } : (rbs_type_parsing_option_t) { .no_void = true })); overload_range.end = parser->current_token.range.end; rbs_location_t *loc = rbs_location_new(ALLOCATOR(), overload_range); @@ -1991,7 +2026,7 @@ static bool parse_member_def(rbs_parser_t *parser, bool instance_only, bool acce * @param kind * */ NODISCARD -static bool class_instance_name(rbs_parser_t *parser, TypeNameKind kind, rbs_node_list_t *args, rbs_range_t *name_range, rbs_range_t *args_range, rbs_type_name_t **name) { +static bool class_instance_name(rbs_parser_t *parser, TypeNameKind kind, rbs_node_list_t *args, rbs_range_t *name_range, rbs_range_t *args_range, rbs_type_name_t **name, rbs_type_parsing_option_t validation) { rbs_parser_advance(parser); rbs_type_name_t *type_name = NULL; @@ -2001,7 +2036,7 @@ static bool class_instance_name(rbs_parser_t *parser, TypeNameKind kind, rbs_nod if (parser->next_token.type == pLBRACKET) { rbs_parser_advance(parser); args_range->start = parser->current_token.range.start; - CHECK_PARSE(parse_type_list(parser, pRBRACKET, args)); + CHECK_PARSE(parse_type_list(parser, pRBRACKET, args, validation)); ADVANCE_ASSERT(parser, pRBRACKET); args_range->end = parser->current_token.range.end; } else { @@ -2062,7 +2097,8 @@ static bool parse_mixin_member(rbs_parser_t *parser, bool from_interface, rbs_po args, &name_range, &args_range, - &name + &name, + (rbs_type_parsing_option_t) { .no_void = true, .no_void_allowed_here = true, .no_self = true } )); CHECK_PARSE(parser_pop_typevar_table(parser)); @@ -2154,7 +2190,7 @@ static bool parse_alias_member(rbs_parser_t *parser, bool instance_only, rbs_pos | {tA2IDENT} `:` */ NODISCARD -static bool parse_variable_member(rbs_parser_t *parser, rbs_position_t comment_pos, rbs_node_list_t *annotations, rbs_node_t **variable_member) { +static bool parse_variable_member(rbs_parser_t *parser, rbs_position_t comment_pos, rbs_node_list_t *annotations, rbs_node_t **variable_member, rbs_type_parsing_option_t validation) { if (annotations->length > 0) { rbs_parser_set_error(parser, parser->current_token, true, "annotation cannot be given to variable members"); return false; @@ -2176,7 +2212,7 @@ static bool parse_variable_member(rbs_parser_t *parser, rbs_position_t comment_p rbs_range_t colon_range = parser->current_token.range; rbs_node_t *type; - CHECK_PARSE(rbs_parse_type(parser, &type)); + CHECK_PARSE(rbs_parse_type(parser, &type, validation)); member_range.end = parser->current_token.range.end; rbs_location_t *loc = rbs_location_new(ALLOCATOR(), member_range); @@ -2199,7 +2235,7 @@ static bool parse_variable_member(rbs_parser_t *parser, rbs_position_t comment_p rbs_parser_push_typevar_table(parser, true); rbs_node_t *type; - CHECK_PARSE(rbs_parse_type(parser, &type)); + CHECK_PARSE(rbs_parse_type(parser, &type, validation)); CHECK_PARSE(parser_pop_typevar_table(parser)); @@ -2238,7 +2274,7 @@ static bool parse_variable_member(rbs_parser_t *parser, rbs_position_t comment_p rbs_parser_push_typevar_table(parser, true); rbs_node_t *type; - CHECK_PARSE(rbs_parse_type(parser, &type)); + CHECK_PARSE(rbs_parse_type(parser, &type, validation)); CHECK_PARSE(parser_pop_typevar_table(parser)); @@ -2379,7 +2415,7 @@ static bool parse_attribute_member(rbs_parser_t *parser, rbs_position_t comment_ rbs_parser_push_typevar_table(parser, is_kind == SINGLETON_KIND); rbs_node_t *type; - CHECK_PARSE(rbs_parse_type(parser, &type)); + CHECK_PARSE(rbs_parse_type(parser, &type, (rbs_type_parsing_option_t) { .no_void = true })); CHECK_PARSE(parser_pop_typevar_table(parser)); @@ -2532,7 +2568,7 @@ static bool parse_module_self_types(rbs_parser_t *parser, rbs_node_list_t *array if (parser->next_token.type == pLBRACKET) { rbs_parser_advance(parser); args_range.start = parser->current_token.range.start; - CHECK_PARSE(parse_type_list(parser, pRBRACKET, args)); + CHECK_PARSE(parse_type_list(parser, pRBRACKET, args, (rbs_type_parsing_option_t) { .no_void = true, .no_void_allowed_here = true, .no_self = true, .no_classish = true })); rbs_parser_advance(parser); self_range.end = args_range.end = parser->current_token.range.end; } @@ -2605,7 +2641,11 @@ static bool parse_module_members(rbs_parser_t *parser, rbs_node_list_t **members case tA2IDENT: case kATRBS: case kSELF: { - CHECK_PARSE(parse_variable_member(parser, annot_pos, annotations, &member)); + rbs_type_parsing_option_t validation = { .no_void = true }; + if (parser->current_token.type == tA2IDENT) { + validation.no_self = true; + } + CHECK_PARSE(parse_variable_member(parser, annot_pos, annotations, &member, validation)); break; } @@ -2767,7 +2807,15 @@ static bool parse_class_decl_super(rbs_parser_t *parser, rbs_range_t *lt_range, rbs_node_list_t *args = rbs_node_list_new(ALLOCATOR()); rbs_type_name_t *name = NULL; rbs_range_t name_range, args_range; - CHECK_PARSE(class_instance_name(parser, CLASS_NAME, args, &name_range, &args_range, &name)); + CHECK_PARSE(class_instance_name( + parser, + CLASS_NAME, + args, + &name_range, + &args_range, + &name, + (rbs_type_parsing_option_t) { .no_void = true, .no_void_allowed_here = true, .no_self = true, .no_classish = true } + )); super_range.end = parser->current_token.range.end; @@ -3521,7 +3569,7 @@ static bool parse_method_overload(rbs_parser_t *parser, rbs_node_list_t *annotat return false; } - return rbs_parse_method_type(parser, method_type); + return rbs_parse_method_type(parser, method_type, SkipValidation); } /* @@ -3680,7 +3728,7 @@ static bool parse_inline_leading_annotation(rbs_parser_t *parser, rbs_ast_ruby_a rbs_location_t *colon_loc = rbs_location_new(ALLOCATOR(), colon_range); rbs_node_t *return_type = NULL; - if (!rbs_parse_type(parser, &return_type)) { + if (!rbs_parse_type(parser, &return_type, SkipValidation)) { return false; } @@ -3730,7 +3778,7 @@ static bool parse_inline_trailing_annotation(rbs_parser_t *parser, rbs_ast_ruby_ rbs_parser_advance(parser); rbs_node_t *type = NULL; - if (!rbs_parse_type(parser, &type)) { + if (!rbs_parse_type(parser, &type, SkipValidation)) { return false; } diff --git a/test/multiple_error.rbs b/test/multiple_error.rbs index 88df91ef5..3f76ecbe0 100644 --- a/test/multiple_error.rbs +++ b/test/multiple_error.rbs @@ -1,6 +1,6 @@ class TypeArg[T] - def foo: (void) -> void - def bar: (void) -> void + def foo: () -> void + def bar: () -> void end class InvalidTypeApplication def foo: () -> TypeArg diff --git a/test/rbs/cli_test.rb b/test/rbs/cli_test.rb index 04b5830c0..cc4753761 100644 --- a/test/rbs/cli_test.rb +++ b/test/rbs/cli_test.rb @@ -556,32 +556,6 @@ module X7 : A[String, untyped] end end - def test_validate__generics_default_self - with_cli do |cli| - Dir.mktmpdir do |dir| - (Pathname(dir) + 'a.rbs').write(<<~RBS) - module A[T = self] - end - - class B[S = self] - end - - interface _C[T = self] - end - - type t[T = self] = untyped - RBS - - cli.run(["-I", dir, "validate"]) - - assert_include stdout.string, "/a.rbs:1:13...1:17: `self` type is not allowed in this context (RBS::WillSyntaxError)\n" - assert_include stdout.string, "/a.rbs:4:12...4:16: `self` type is not allowed in this context (RBS::WillSyntaxError)\n" - assert_include stdout.string, "/a.rbs:7:17...7:21: `self` type is not allowed in this context (RBS::WillSyntaxError)\n" - assert_include stdout.string, "/a.rbs:10:11...10:15: `self` type is not allowed in this context (RBS::WillSyntaxError)\n" - end - end - end - def test_validate__generics_default_ref with_cli do |cli| Dir.mktmpdir do |dir| @@ -615,15 +589,20 @@ def test_validate_multiple Dir.mktmpdir do |dir| (Pathname(dir) + 'a.rbs').write(<<~RBS) class Foo - def foo: (void) -> void - def bar: (void) -> void + def foo: () -> Nothing + end + + class Bar + def bar: () -> Nothing end RBS - cli.run(["-I", dir, "--log-level=warn", "validate"]) + assert_raises SystemExit do + cli.run(["-I", dir, "--log-level=warn", "validate"]) + end - assert_include stdout.string, "a.rbs:2:11...2:25: `void` type is only allowed in return type or generics parameter (RBS::WillSyntaxError)" - assert_include stdout.string, "a.rbs:3:11...3:25: `void` type is only allowed in return type or generics parameter (RBS::WillSyntaxError)" + assert_include stdout.string, "a.rbs:2:17...2:24: Could not find Nothing (RBS::NoTypeFoundError)" + assert_include stdout.string, "a.rbs:6:17...6:24: Could not find Nothing (RBS::NoTypeFoundError)" end end end @@ -633,52 +612,20 @@ def test_validate_multiple_with_fail_fast Dir.mktmpdir do |dir| (Pathname(dir) + 'a.rbs').write(<<~RBS) class Foo - def foo: (void) -> void - def bar: (void) -> void + def foo: () -> Nothing end - RBS - - cli.run(["-I", dir, "--log-level=warn", "validate", "--fail-fast"]) - assert_include stdout.string, "a.rbs:2:11...2:25: `void` type is only allowed in return type or generics parameter (RBS::WillSyntaxError)" - assert_include stdout.string, "a.rbs:3:11...3:25: `void` type is only allowed in return type or generics parameter (RBS::WillSyntaxError)" - end - end - end - def test_validate_multiple_with_exit_error_on_syntax_error - with_cli do |cli| - Dir.mktmpdir do |dir| - (Pathname(dir) + 'a.rbs').write(<<~RBS) - class Foo - def foo: (void) -> void - def bar: (void) -> void + class Bar + def bar: () -> Nothing end RBS assert_raises SystemExit do - cli.run(["-I", dir, "--log-level=warn", "validate", "--exit-error-on-syntax-error"]) + cli.run(["-I", dir, "--log-level=warn", "validate", "--fail-fast"]) end - assert_include stdout.string, "a.rbs:2:11...2:25: `void` type is only allowed in return type or generics parameter (RBS::WillSyntaxError)" - assert_include stdout.string, "a.rbs:3:11...3:25: `void` type is only allowed in return type or generics parameter (RBS::WillSyntaxError)" - end - end - end - - def test_validate_multiple_with_fail_fast_and_exit_error_on_syntax_error - with_cli do |cli| - Dir.mktmpdir do |dir| - (Pathname(dir) + 'a.rbs').write(<<~RBS) - class Foo - def foo: (void) -> void - def bar: (void) -> void - end - RBS - assert_raises SystemExit do - cli.run(["-I", dir, "--log-level=warn", "validate", "--fail-fast", "--exit-error-on-syntax-error"]) - end - assert_include stdout.string, "a.rbs:2:11...2:25: `void` type is only allowed in return type or generics parameter (RBS::WillSyntaxError)" - assert_not_include stdout.string, "a.rbs:3:11...3:25: `void` type is only allowed in return type or generics parameter (RBS::WillSyntaxError)" + assert_include stdout.string, "a.rbs:2:17...2:24: Could not find Nothing (RBS::NoTypeFoundError)" + assert_not_include stdout.string, "a.rbs:6:17...6:24: Could not find Nothing (RBS::NoTypeFoundError)" end end end @@ -688,7 +635,6 @@ def test_validate_multiple_with_many_errors assert_raise SystemExit do cli.run(%w(--log-level=warn -I test/multiple_error.rbs validate)) end - assert_include(stdout.string, "`void` type is only allowed in return type or generics parameter") assert_include(stdout.string, "test/multiple_error.rbs:6:17...6:24: ::TypeArg expects parameters [T], but given args [] (RBS::InvalidTypeApplicationError)") assert_include(stdout.string, "test/multiple_error.rbs:8:0...9:3: Detected recursive ancestors: ::RecursiveAncestor < ::RecursiveAncestor (RBS::RecursiveAncestorError)") assert_include(stdout.string, "test/multiple_error.rbs:11:15...11:22: Could not find Nothing (RBS::NoTypeFoundError)") @@ -718,81 +664,10 @@ def test_validate_multiple_fail_fast assert_raise SystemExit do cli.run(%w(--log-level=warn -I test/multiple_error.rbs validate --fail-fast)) end - assert_include(stdout.string, "test/multiple_error.rbs:2:11...2:25: `void` type is only allowed in return type or generics parameter (RBS::WillSyntaxError)") - assert_include(stdout.string, "test/multiple_error.rbs:3:11...3:25: `void` type is only allowed in return type or generics parameter (RBS::WillSyntaxError)") assert_include(stdout.string, "test/multiple_error.rbs:6:17...6:24: ::TypeArg expects parameters [T], but given args []") end end - def test_validate_multiple_fail_fast_and_exit_error_on_syntax_error - with_cli do |cli| - assert_raise SystemExit do - cli.run(%w(--log-level=warn -I test/multiple_error.rbs validate --fail-fast --exit-error-on-syntax-error)) - end - assert_include(stdout.string, "test/multiple_error.rbs:2:11...2:25: `void` type is only allowed in return type or generics parameter (RBS::WillSyntaxError)") - end - end - - def test_context_validation - tests = [ - <<~RBS, - class Foo - def foo: (void) -> untyped - end - RBS - <<~RBS, - class Bar[A] - end - class Foo < Bar[instance] - end - RBS - <<~RBS, - module Bar : _Each[instance] - end - RBS - <<~RBS, - module Foo[A < _Each[self]] - end - RBS - <<~RBS, - class Foo - @@bar: self - end - RBS - <<~RBS, - type foo = instance - RBS - <<~RBS, - BAR: instance - RBS - <<~RBS, - class Foo - include Enumerable[self] - end - RBS - <<~RBS, - $FOO: instance - RBS - ] - - tests.each do |rbs| - with_cli do |cli| - Dir.mktmpdir do |dir| - (Pathname(dir) + 'a.rbs').write(rbs) - - cli.run(["-I", dir, "validate"]) - - assert_match(/void|self|instance|class/, stdout.string) - - cli.run(["-I", dir, "validate", "--no-exit-error-on-syntax-error"]) - assert_raises SystemExit do - cli.run(["-I", dir, "validate", "--exit-error-on-syntax-error"]) - end - end - end - end - end - def test_validate_878 with_cli do |cli| Dir.mktmpdir do |dir| diff --git a/test/rbs/rb_prototype_test.rb b/test/rbs/rb_prototype_test.rb index 804b0d48c..2722347ec 100644 --- a/test/rbs/rb_prototype_test.rb +++ b/test/rbs/rb_prototype_test.rb @@ -763,7 +763,7 @@ def test_literal_types H: { id: 123 } -I: self +I: untyped EOF end diff --git a/test/rbs/signature_parsing_test.rb b/test/rbs/signature_parsing_test.rb index 17dbabbce..585d0e41f 100644 --- a/test/rbs/signature_parsing_test.rb +++ b/test/rbs/signature_parsing_test.rb @@ -2370,4 +2370,673 @@ def return: (untyped return) -> void end RBS end + + def test_context_syntax_error_method + assert_nothing_raised do + Parser.parse_signature(<<~RBS) + class Foo + def foo: () -> void + def foo: (Array[void]) -> void + def foo: (self) -> self + def foo: (class) -> class + def foo: (instance) -> instance + end + RBS + end + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature(<<~RBS) + class Foo + def foo: (void) -> void + end + RBS + end + assert_equal "a.rbs:2:12...2:16: Syntax error: `void` type is only allowed in return type or generics parameter, token=`void` (kVOID)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature(<<~RBS) + class Foo + def foo: ([void]) -> void + end + RBS + end + assert_equal "a.rbs:2:13...2:17: Syntax error: `void` type is only allowed in return type or generics parameter, token=`void` (kVOID)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature(<<~RBS) + class Foo + def foo: () -> ^(void) -> void + end + RBS + end + assert_equal "a.rbs:2:19...2:23: Syntax error: `void` type is only allowed in return type or generics parameter, token=`void` (kVOID)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature(<<~RBS) + class Foo + def foo: () { () -> ^(void) -> void } -> void + end + RBS + end + assert_equal "a.rbs:2:24...2:28: Syntax error: `void` type is only allowed in return type or generics parameter, token=`void` (kVOID)", ex.message + end + + def test_context_syntax_error_interface + assert_nothing_raised do + Parser.parse_signature(<<~RBS) + interface _Foo + def foo: () -> void + def foo: () { () -> void } -> ^() -> void + def foo: (Array[void]) -> void + def foo: (self) -> self + end + RBS + end + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature(<<~RBS) + interface _Foo + def foo: (void) -> void + end + RBS + end + assert_equal "a.rbs:2:12...2:16: Syntax error: `void` type is only allowed in return type or generics parameter, token=`void` (kVOID)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature(<<~RBS) + interface _Foo + def foo: () { (void) -> void } -> void + end + RBS + end + assert_equal "a.rbs:2:17...2:21: Syntax error: `void` type is only allowed in return type or generics parameter, token=`void` (kVOID)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature(<<~RBS) + interface _Foo + def foo: ([void]) -> void + end + RBS + end + assert_equal "a.rbs:2:13...2:17: Syntax error: `void` type is only allowed in return type or generics parameter, token=`void` (kVOID)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature(<<~RBS) + interface _Foo + def foo: () -> ^(void) -> void + end + RBS + end + assert_equal "a.rbs:2:19...2:23: Syntax error: `void` type is only allowed in return type or generics parameter, token=`void` (kVOID)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature(<<~RBS) + interface _Foo + def foo: () -> class + end + RBS + end + assert_equal "a.rbs:2:17...2:22: Syntax error: `class` type is not allowed in this context, token=`class` (kCLASS)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature(<<~RBS) + interface _Foo + def foo: () -> ^() -> class + end + RBS + end + assert_equal "a.rbs:2:24...2:29: Syntax error: `class` type is not allowed in this context, token=`class` (kCLASS)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature(<<~RBS) + interface _Foo + def foo: () -> instance + end + RBS + end + assert_equal "a.rbs:2:17...2:25: Syntax error: `instance` type is not allowed in this context, token=`instance` (kINSTANCE)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature(<<~RBS) + interface _Foo + def foo: () { () -> instance } -> void + end + RBS + end + assert_equal "a.rbs:2:22...2:30: Syntax error: `instance` type is not allowed in this context, token=`instance` (kINSTANCE)", ex.message + end + + def test_context_syntax_error_attribute + assert_nothing_raised do + Parser.parse_signature(<<~RBS) + class Foo + attr_reader foo: ^() -> void + attr_reader foo: self + attr_reader foo: class + attr_reader foo: instance + attr_reader self.foo: self + attr_reader self.foo: class + attr_reader self.foo: instance + end + RBS + end + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature(<<~RBS) + class Foo + attr_reader foo: void + end + RBS + end + assert_equal "a.rbs:2:19...2:23: Syntax error: `void` type is only allowed in return type or generics parameter, token=`void` (kVOID)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature(<<~RBS) + class Foo + attr_reader foo: ^(void) -> void + end + RBS + end + assert_equal "a.rbs:2:21...2:25: Syntax error: `void` type is only allowed in return type or generics parameter, token=`void` (kVOID)", ex.message + end + + def test_context_syntax_error_super_class + assert_nothing_raised do + Parser.parse_signature("class Foo < Array[void] end") + end + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("class Foo < Array[[void]] end") + end + assert_equal "a.rbs:1:19...1:23: Syntax error: `void` type is only allowed in return type or generics parameter, token=`void` (kVOID)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("class Foo < Array[self] end") + end + assert_equal "a.rbs:1:18...1:22: Syntax error: `self` type is not allowed in this context, token=`self` (kSELF)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("class Foo < Array[class] end") + end + assert_equal "a.rbs:1:18...1:23: Syntax error: `class` type is not allowed in this context, token=`class` (kCLASS)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("class Foo < Array[instance] end") + end + assert_equal "a.rbs:1:18...1:26: Syntax error: `instance` type is not allowed in this context, token=`instance` (kINSTANCE)", ex.message + end + + def test_context_syntax_error_module_self_type + assert_nothing_raised do + Parser.parse_signature("module Foo : Array[void] end") + end + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("module Foo : Array[[void]] end") + end + assert_equal "a.rbs:1:20...1:24: Syntax error: `void` type is only allowed in return type or generics parameter, token=`void` (kVOID)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("module Foo : Array[self] end") + end + assert_equal "a.rbs:1:19...1:23: Syntax error: `self` type is not allowed in this context, token=`self` (kSELF)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("module Foo : Array[class] end") + end + assert_equal "a.rbs:1:19...1:24: Syntax error: `class` type is not allowed in this context, token=`class` (kCLASS)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("module Foo : Array[instance] end") + end + assert_equal "a.rbs:1:19...1:27: Syntax error: `instance` type is not allowed in this context, token=`instance` (kINSTANCE)", ex.message + end + + def test_context_syntax_error_global + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("$glob: void") + end + assert_equal "a.rbs:1:7...1:11: Syntax error: `void` type is only allowed in return type or generics parameter, token=`void` (kVOID)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("$glob: self") + end + assert_equal "a.rbs:1:7...1:11: Syntax error: `self` type is not allowed in this context, token=`self` (kSELF)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("$glob: class") + end + assert_equal "a.rbs:1:7...1:12: Syntax error: `class` type is not allowed in this context, token=`class` (kCLASS)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("$glob: instance") + end + assert_equal "a.rbs:1:7...1:15: Syntax error: `instance` type is not allowed in this context, token=`instance` (kINSTANCE)", ex.message + end + + def test_context_syntax_error_constant + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("CONST: void") + end + assert_equal "a.rbs:1:7...1:11: Syntax error: `void` type is only allowed in return type or generics parameter, token=`void` (kVOID)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("CONST: self") + end + assert_equal "a.rbs:1:7...1:11: Syntax error: `self` type is not allowed in this context, token=`self` (kSELF)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("CONST: class") + end + assert_equal "a.rbs:1:7...1:12: Syntax error: `class` type is not allowed in this context, token=`class` (kCLASS)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("CONST: instance") + end + assert_equal "a.rbs:1:7...1:15: Syntax error: `instance` type is not allowed in this context, token=`instance` (kINSTANCE)", ex.message + end + + def test_context_syntax_error_type_alias + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("type a = void") + end + assert_equal "a.rbs:1:9...1:13: Syntax error: `void` type is only allowed in return type or generics parameter, token=`void` (kVOID)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("type a = self") + end + assert_equal "a.rbs:1:9...1:13: Syntax error: `self` type is not allowed in this context, token=`self` (kSELF)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("type a = class") + end + assert_equal "a.rbs:1:9...1:14: Syntax error: `class` type is not allowed in this context, token=`class` (kCLASS)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("type a = instance") + end + assert_equal "a.rbs:1:9...1:17: Syntax error: `instance` type is not allowed in this context, token=`instance` (kINSTANCE)", ex.message + end + + def test_context_syntax_error_mixin + assert_nothing_raised do + Parser.parse_signature(<<~SIG) + class C + include M[void] + include M[class] + include M[instance] + end + SIG + end + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("class C include M[self] end") + end + assert_equal "a.rbs:1:18...1:22: Syntax error: `self` type is not allowed in this context, token=`self` (kSELF)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("class C include M[[void]] end") + end + assert_equal "a.rbs:1:19...1:23: Syntax error: `void` type is only allowed in return type or generics parameter, token=`void` (kVOID)", ex.message + end + + def test_context_syntax_error_variable + assert_nothing_raised do + Parser.parse_signature(<<~SIG) + class Foo + @s: self + @c: class + @i: instance + self.@s: self + self.@c: class + self.@i: instance + @@c: class + @@i: instance + end + SIG + end + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("class Foo @foo: void end") + end + assert_equal "a.rbs:1:16...1:20: Syntax error: `void` type is only allowed in return type or generics parameter, token=`void` (kVOID)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("class Foo self.@foo: void end") + end + assert_equal "a.rbs:1:21...1:25: Syntax error: `void` type is only allowed in return type or generics parameter, token=`void` (kVOID)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("class Foo @@foo: self end") + end + assert_equal "a.rbs:1:17...1:21: Syntax error: `self` type is not allowed in this context, token=`self` (kSELF)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("class Foo @@foo: void end") + end + assert_equal "a.rbs:1:17...1:21: Syntax error: `void` type is only allowed in return type or generics parameter, token=`void` (kVOID)", ex.message + end + + def test_context_syntax_error_upper_bound + assert_nothing_raised do + Parser.parse_signature(<<~SIG) + class C[T < Array[void]] + end + module M[T < Array[void]] + end + interface _I[T < Array[void]] + end + type a[T < Array[void]] = 1 + SIG + end + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("class C[T < void] end") + end + assert_equal "a.rbs:1:12...1:16: Syntax error: `void` type is only allowed in return type or generics parameter, token=`void` (kVOID)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("class C[T < self] end") + end + assert_equal "a.rbs:1:12...1:16: Syntax error: `self` type is not allowed in this context, token=`self` (kSELF)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("class C[T < class] end") + end + assert_equal "a.rbs:1:12...1:17: Syntax error: `class` type is not allowed in this context, token=`class` (kCLASS)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("class C[T < instance] end") + end + assert_equal "a.rbs:1:12...1:20: Syntax error: `instance` type is not allowed in this context, token=`instance` (kINSTANCE)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("module M[T < void] end") + end + assert_equal "a.rbs:1:13...1:17: Syntax error: `void` type is only allowed in return type or generics parameter, token=`void` (kVOID)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("module M[T < self] end") + end + assert_equal "a.rbs:1:13...1:17: Syntax error: `self` type is not allowed in this context, token=`self` (kSELF)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("module M[T < class] end") + end + assert_equal "a.rbs:1:13...1:18: Syntax error: `class` type is not allowed in this context, token=`class` (kCLASS)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("module M[T < instance] end") + end + assert_equal "a.rbs:1:13...1:21: Syntax error: `instance` type is not allowed in this context, token=`instance` (kINSTANCE)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("interface _I[T < void] end") + end + assert_equal "a.rbs:1:17...1:21: Syntax error: `void` type is only allowed in return type or generics parameter, token=`void` (kVOID)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("interface _I[T < self] end") + end + assert_equal "a.rbs:1:17...1:21: Syntax error: `self` type is not allowed in this context, token=`self` (kSELF)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("interface _I[T < class] end") + end + assert_equal "a.rbs:1:17...1:22: Syntax error: `class` type is not allowed in this context, token=`class` (kCLASS)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("interface _I[T < instance] end") + end + assert_equal "a.rbs:1:17...1:25: Syntax error: `instance` type is not allowed in this context, token=`instance` (kINSTANCE)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("type a[T < void] = 1") + end + assert_equal "a.rbs:1:11...1:15: Syntax error: `void` type is only allowed in return type or generics parameter, token=`void` (kVOID)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("type a[T < self] = 1") + end + assert_equal "a.rbs:1:11...1:15: Syntax error: `self` type is not allowed in this context, token=`self` (kSELF)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("type a[T < class] = 1") + end + assert_equal "a.rbs:1:11...1:16: Syntax error: `class` type is not allowed in this context, token=`class` (kCLASS)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("type a[T < instance] = 1") + end + assert_equal "a.rbs:1:11...1:19: Syntax error: `instance` type is not allowed in this context, token=`instance` (kINSTANCE)", ex.message + end + + def test_context_syntax_error_lower_bound + assert_nothing_raised do + Parser.parse_signature(<<~SIG) + class C[T > Array[void]] + end + module M[T > Array[void]] + end + interface _I[T > Array[void]] + end + type a[T > Array[void]] = 1 + SIG + end + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("class C[T > void] end") + end + assert_equal "a.rbs:1:12...1:16: Syntax error: `void` type is only allowed in return type or generics parameter, token=`void` (kVOID)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("class C[T > self] end") + end + assert_equal "a.rbs:1:12...1:16: Syntax error: `self` type is not allowed in this context, token=`self` (kSELF)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("class C[T > class] end") + end + assert_equal "a.rbs:1:12...1:17: Syntax error: `class` type is not allowed in this context, token=`class` (kCLASS)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("class C[T > instance] end") + end + assert_equal "a.rbs:1:12...1:20: Syntax error: `instance` type is not allowed in this context, token=`instance` (kINSTANCE)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("module M[T > void] end") + end + assert_equal "a.rbs:1:13...1:17: Syntax error: `void` type is only allowed in return type or generics parameter, token=`void` (kVOID)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("module M[T > self] end") + end + assert_equal "a.rbs:1:13...1:17: Syntax error: `self` type is not allowed in this context, token=`self` (kSELF)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("module M[T > class] end") + end + assert_equal "a.rbs:1:13...1:18: Syntax error: `class` type is not allowed in this context, token=`class` (kCLASS)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("module M[T > instance] end") + end + assert_equal "a.rbs:1:13...1:21: Syntax error: `instance` type is not allowed in this context, token=`instance` (kINSTANCE)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("interface _I[T > void] end") + end + assert_equal "a.rbs:1:17...1:21: Syntax error: `void` type is only allowed in return type or generics parameter, token=`void` (kVOID)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("interface _I[T > self] end") + end + assert_equal "a.rbs:1:17...1:21: Syntax error: `self` type is not allowed in this context, token=`self` (kSELF)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("interface _I[T > class] end") + end + assert_equal "a.rbs:1:17...1:22: Syntax error: `class` type is not allowed in this context, token=`class` (kCLASS)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("interface _I[T > instance] end") + end + assert_equal "a.rbs:1:17...1:25: Syntax error: `instance` type is not allowed in this context, token=`instance` (kINSTANCE)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("type a[T > void] = 1") + end + assert_equal "a.rbs:1:11...1:15: Syntax error: `void` type is only allowed in return type or generics parameter, token=`void` (kVOID)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("type a[T > self] = 1") + end + assert_equal "a.rbs:1:11...1:15: Syntax error: `self` type is not allowed in this context, token=`self` (kSELF)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("type a[T > class] = 1") + end + assert_equal "a.rbs:1:11...1:16: Syntax error: `class` type is not allowed in this context, token=`class` (kCLASS)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("type a[T > instance] = 1") + end + assert_equal "a.rbs:1:11...1:19: Syntax error: `instance` type is not allowed in this context, token=`instance` (kINSTANCE)", ex.message + end + + def test_context_syntax_error_upper_and_lower_bound + assert_nothing_raised do + Parser.parse_signature(<<~SIG) + class C[T < Array[void] > Array[void]] + end + module M[T > Array[void] < Array[void]] + end + interface _I[T < Array[void] > Array[void]] + end + type a[T < Array[void] > Array[void]] = 1 + SIG + end + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("class C[T < void > Integer] end") + end + assert_equal "a.rbs:1:12...1:16: Syntax error: `void` type is only allowed in return type or generics parameter, token=`void` (kVOID)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("class C[T > Integer < void] end") + end + assert_equal "a.rbs:1:22...1:26: Syntax error: `void` type is only allowed in return type or generics parameter, token=`void` (kVOID)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("class C[T < Integer > void] end") + end + assert_equal "a.rbs:1:22...1:26: Syntax error: `void` type is only allowed in return type or generics parameter, token=`void` (kVOID)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("class C[T > void < Integer] end") + end + assert_equal "a.rbs:1:12...1:16: Syntax error: `void` type is only allowed in return type or generics parameter, token=`void` (kVOID)", ex.message + end + + def test_context_syntax_error_default_type + assert_nothing_raised do + Parser.parse_signature(<<~SIG) + class C[T = void] + end + class CA[T = Array[void]] + end + module M[T = void] + end + module MA[T = Array[void]] + end + interface _I[T = void] + end + interface _IA[T = Array[void]] + end + type a[T = void] = 1 + type aa[T = Array[void]] = 1 + SIG + end + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("class C[T = [void]] end") + end + assert_equal "a.rbs:1:13...1:17: Syntax error: `void` type is only allowed in return type or generics parameter, token=`void` (kVOID)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("class C[T = self] end") + end + assert_equal "a.rbs:1:12...1:16: Syntax error: `self` type is not allowed in this context, token=`self` (kSELF)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("class C[T = class] end") + end + assert_equal "a.rbs:1:12...1:17: Syntax error: `class` type is not allowed in this context, token=`class` (kCLASS)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("class C[T = instance] end") + end + assert_equal "a.rbs:1:12...1:20: Syntax error: `instance` type is not allowed in this context, token=`instance` (kINSTANCE)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("module M[T = [void]] end") + end + assert_equal "a.rbs:1:14...1:18: Syntax error: `void` type is only allowed in return type or generics parameter, token=`void` (kVOID)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("module M[T = self] end") + end + assert_equal "a.rbs:1:13...1:17: Syntax error: `self` type is not allowed in this context, token=`self` (kSELF)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("module M[T = class] end") + end + assert_equal "a.rbs:1:13...1:18: Syntax error: `class` type is not allowed in this context, token=`class` (kCLASS)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("module M[T = instance] end") + end + assert_equal "a.rbs:1:13...1:21: Syntax error: `instance` type is not allowed in this context, token=`instance` (kINSTANCE)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("interface _I[T = [void]] end") + end + assert_equal "a.rbs:1:18...1:22: Syntax error: `void` type is only allowed in return type or generics parameter, token=`void` (kVOID)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("interface _I[T = self] end") + end + assert_equal "a.rbs:1:17...1:21: Syntax error: `self` type is not allowed in this context, token=`self` (kSELF)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("interface _I[T = class] end") + end + assert_equal "a.rbs:1:17...1:22: Syntax error: `class` type is not allowed in this context, token=`class` (kCLASS)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("interface _I[T = instance] end") + end + assert_equal "a.rbs:1:17...1:25: Syntax error: `instance` type is not allowed in this context, token=`instance` (kINSTANCE)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("type a[T = [void]] = 1") + end + assert_equal "a.rbs:1:12...1:16: Syntax error: `void` type is only allowed in return type or generics parameter, token=`void` (kVOID)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("type a[T = self] = 1") + end + assert_equal "a.rbs:1:11...1:15: Syntax error: `self` type is not allowed in this context, token=`self` (kSELF)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("type a[T = class] = 1") + end + assert_equal "a.rbs:1:11...1:16: Syntax error: `class` type is not allowed in this context, token=`class` (kCLASS)", ex.message + + ex = assert_raises RBS::ParsingError do + Parser.parse_signature("type a[T = instance] = 1") + end + assert_equal "a.rbs:1:11...1:19: Syntax error: `instance` type is not allowed in this context, token=`instance` (kINSTANCE)", ex.message + end end