diff --git a/ext/rbs_extension/main.c b/ext/rbs_extension/main.c index 30bea00afa..6d3237b4e1 100644 --- a/ext/rbs_extension/main.c +++ b/ext/rbs_extension/main.c @@ -85,6 +85,21 @@ struct parse_type_arg { rb_encoding *encoding; rbs_parser_t *parser; VALUE require_eof; + VALUE void_allowed; +}; + +struct parse_method_type_arg { + VALUE buffer; + rb_encoding *encoding; + rbs_parser_t *parser; + VALUE require_eof; +}; + +struct parse_signature_arg { + VALUE buffer; + rb_encoding *encoding; + rbs_parser_t *parser; + VALUE require_eof; }; static VALUE ensure_free_parser(VALUE parser) { @@ -100,8 +115,10 @@ static VALUE parse_type_try(VALUE a) { return Qnil; } + bool void_allowed = RTEST(arg->void_allowed); + rbs_node_t *type; - rbs_parse_type(parser, &type); + rbs_parse_type(parser, &type, void_allowed); raise_error_if_any(parser, arg->buffer); @@ -157,7 +174,7 @@ static rbs_parser_t *alloc_parser_from_buffer(VALUE buffer, int start_pos, int e ); } -static VALUE rbsparser_parse_type(VALUE self, VALUE buffer, VALUE start_pos, VALUE end_pos, VALUE variables, VALUE require_eof) { +static VALUE rbsparser_parse_type(VALUE self, VALUE buffer, VALUE start_pos, VALUE end_pos, VALUE variables, VALUE require_eof, VALUE void_allowed) { VALUE string = rb_funcall(buffer, rb_intern("content"), 0); StringValue(string); rb_encoding *encoding = rb_enc_get(string); @@ -168,7 +185,8 @@ static VALUE rbsparser_parse_type(VALUE self, VALUE buffer, VALUE start_pos, VAL .buffer = buffer, .encoding = encoding, .parser = parser, - .require_eof = require_eof + .require_eof = require_eof, + .void_allowed = void_allowed }; VALUE result = rb_ensure(parse_type_try, (VALUE) &arg, ensure_free_parser, (VALUE) parser); @@ -179,7 +197,7 @@ static VALUE rbsparser_parse_type(VALUE self, VALUE buffer, VALUE start_pos, VAL } static VALUE parse_method_type_try(VALUE a) { - struct parse_type_arg *arg = (struct parse_type_arg *) a; + struct parse_method_type_arg *arg = (struct parse_method_type_arg *) a; rbs_parser_t *parser = arg->parser; if (parser->next_token.type == pEOF) { @@ -215,7 +233,7 @@ static VALUE rbsparser_parse_method_type(VALUE self, VALUE buffer, VALUE start_p rbs_parser_t *parser = alloc_parser_from_buffer(buffer, FIX2INT(start_pos), FIX2INT(end_pos)); declare_type_variables(parser, variables, buffer); - struct parse_type_arg arg = { + struct parse_method_type_arg arg = { .buffer = buffer, .encoding = encoding, .parser = parser, @@ -230,7 +248,7 @@ static VALUE rbsparser_parse_method_type(VALUE self, VALUE buffer, VALUE start_p } static VALUE parse_signature_try(VALUE a) { - struct parse_type_arg *arg = (struct parse_type_arg *) a; + struct parse_signature_arg *arg = (struct parse_signature_arg *) a; rbs_parser_t *parser = arg->parser; rbs_signature_t *signature = NULL; @@ -253,7 +271,7 @@ static VALUE rbsparser_parse_signature(VALUE self, VALUE buffer, VALUE start_pos rb_encoding *encoding = rb_enc_get(string); rbs_parser_t *parser = alloc_parser_from_buffer(buffer, FIX2INT(start_pos), FIX2INT(end_pos)); - struct parse_type_arg arg = { + struct parse_signature_arg arg = { .buffer = buffer, .encoding = encoding, .parser = parser, @@ -432,7 +450,7 @@ void rbs__init_parser(void) { VALUE empty_array = rb_obj_freeze(rb_ary_new()); rb_gc_register_mark_object(empty_array); - rb_define_singleton_method(RBS_Parser, "_parse_type", rbsparser_parse_type, 5); + rb_define_singleton_method(RBS_Parser, "_parse_type", rbsparser_parse_type, 6); rb_define_singleton_method(RBS_Parser, "_parse_method_type", rbsparser_parse_method_type, 5); rb_define_singleton_method(RBS_Parser, "_parse_signature", rbsparser_parse_signature, 3); rb_define_singleton_method(RBS_Parser, "_parse_type_params", rbsparser_parse_type_params, 4); diff --git a/include/rbs/parser.h b/include/rbs/parser.h index c7f3c2e4f8..a7dc97af62 100644 --- a/include/rbs/parser.h +++ b/include/rbs/parser.h @@ -126,7 +126,7 @@ 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_type(rbs_parser_t *parser, rbs_node_t **type, bool void_allowed); bool rbs_parse_method_type(rbs_parser_t *parser, rbs_method_type_t **method_type); bool rbs_parse_signature(rbs_parser_t *parser, rbs_signature_t **signature); diff --git a/lib/rbs/cli/validate.rb b/lib/rbs/cli/validate.rb index 7ba52665a9..5247a9a705 100644 --- a/lib/rbs/cli/validate.rb +++ b/lib/rbs/cli/validate.rb @@ -122,7 +122,6 @@ def validate_class_module_definition entry.each_decl do |decl| if super_class = decl.super_class super_class.args.each do |arg| - void_type_context_validator(arg, true) no_self_type_validator(arg) no_classish_type_validator(arg) @validator.validate_type(arg, context: nil) @@ -133,7 +132,6 @@ def validate_class_module_definition entry.each_decl do |decl| decl.self_types.each do |self_type| self_type.args.each do |arg| - void_type_context_validator(arg, true) no_self_type_validator(arg) no_classish_type_validator(arg) @validator.validate_type(arg, context: nil) @@ -163,21 +161,18 @@ def validate_class_module_definition d.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 if lb = param.lower_bound_type - void_type_context_validator(lb) no_self_type_validator(lb) no_classish_type_validator(lb) @validator.validate_type(lb, context: nil) 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) @@ -193,17 +188,9 @@ def validate_class_module_definition case member when AST::Members::MethodDefinition @validator.validate_method_definition(member, type_name: name) - member.overloads.each do |ov| - void_type_context_validator(ov.method_type) - end - when AST::Members::Attribute - void_type_context_validator(member.type) when AST::Members::Mixin member.args.each do |arg| no_self_type_validator(arg) - unless arg.is_a?(Types::Bases::Void) - void_type_context_validator(arg, true) - end end params = if member.name.class? @@ -216,7 +203,6 @@ def validate_class_module_definition InvalidTypeApplicationError.check!(type_name: member.name, params: params, args: member.args, location: member.location) when AST::Members::Var @validator.validate_variable(member) - void_type_context_validator(member.type) if member.is_a?(AST::Members::ClassVariable) no_self_type_validator(member.type) end @@ -255,21 +241,18 @@ def validate_interface 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 if lb = param.lower_bound_type - void_type_context_validator(lb) no_self_type_validator(lb) no_classish_type_validator(lb) @validator.validate_type(lb, context: nil) 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) @@ -283,7 +266,6 @@ def validate_interface when AST::Members::MethodDefinition @validator.validate_method_definition(member, type_name: name) member.overloads.each do |ov| - void_type_context_validator(ov.method_type) no_classish_type_validator(ov.method_type) end end @@ -300,7 +282,6 @@ def validate_constant @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 @@ -312,7 +293,6 @@ def validate_global @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 @@ -335,21 +315,18 @@ 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 if lb = param.lower_bound_type - void_type_context_validator(lb) no_self_type_validator(lb) no_classish_type_validator(lb) @validator.validate_type(lb, context: nil) 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) @@ -360,7 +337,6 @@ def validate_type_alias 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 @@ -384,7 +360,7 @@ 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? + if type.with_nonreturn_void? # steep:ignore DeprecatedReference @errors.add WillSyntaxError.new("`void` type is only allowed in return type or generics parameter", location: type.location) end end diff --git a/lib/rbs/method_type.rb b/lib/rbs/method_type.rb index 7ac56cd68d..b5182fed2c 100644 --- a/lib/rbs/method_type.rb +++ b/lib/rbs/method_type.rb @@ -129,11 +129,13 @@ def has_classish_type? end def with_nonreturn_void? - if type.with_nonreturn_void? + if type.with_nonreturn_void? # steep:ignore DeprecatedReference true else if block = block() - block.type.with_nonreturn_void? || block.self_type&.with_nonreturn_void? || false + block.type.with_nonreturn_void? || # steep:ignore DeprecatedReference + block.self_type&.with_nonreturn_void? || # steep:ignore DeprecatedReference + false else false end diff --git a/lib/rbs/parser_aux.rb b/lib/rbs/parser_aux.rb index 79171faa3f..529cfb806e 100644 --- a/lib/rbs/parser_aux.rb +++ b/lib/rbs/parser_aux.rb @@ -5,9 +5,9 @@ module RBS class Parser - def self.parse_type(source, range: 0..., variables: [], require_eof: false) + def self.parse_type(source, range: 0..., variables: [], require_eof: false, void_allowed: true) buf = buffer(source) - _parse_type(buf, range.begin || 0, range.end || buf.last_position, variables, require_eof) + _parse_type(buf, range.begin || 0, range.end || buf.last_position, variables, require_eof, void_allowed) end def self.parse_method_type(source, range: 0..., variables: [], require_eof: false) diff --git a/lib/rbs/types.rb b/lib/rbs/types.rb index 3b99d9def2..3c0787ebb3 100644 --- a/lib/rbs/types.rb +++ b/lib/rbs/types.rb @@ -303,7 +303,7 @@ def with_nonreturn_void? # `void` in immediate generics parameter is allowed false else - type.with_nonreturn_void? + type.with_nonreturn_void? # steep:ignore DeprecatedReference end end end @@ -520,7 +520,7 @@ def has_classish_type? end def with_nonreturn_void? - each_type.any? {|type| type.with_nonreturn_void? } + each_type.any? {|type| type.with_nonreturn_void? } # steep:ignore DeprecatedReference end end @@ -638,7 +638,7 @@ def has_classish_type? end def with_nonreturn_void? - each_type.any? {|type| type.with_nonreturn_void? } + each_type.any? {|type| type.with_nonreturn_void? } # steep:ignore DeprecatedReference end end @@ -724,7 +724,7 @@ def has_classish_type? end def with_nonreturn_void? - each_type.any? {|type| type.with_nonreturn_void? } + each_type.any? {|type| type.with_nonreturn_void? } # steep:ignore DeprecatedReference end end @@ -815,7 +815,7 @@ def has_classish_type? end def with_nonreturn_void? - each_type.any? {|type| type.with_nonreturn_void? } + each_type.any? {|type| type.with_nonreturn_void? } # steep:ignore DeprecatedReference end end @@ -898,7 +898,7 @@ def has_classish_type? end def with_nonreturn_void? - each_type.any? {|type| type.with_nonreturn_void? } + each_type.any? {|type| type.with_nonreturn_void? } # steep:ignore DeprecatedReference end end @@ -1226,13 +1226,13 @@ def has_classish_type? end def with_nonreturn_void? - if each_param.any? {|param| param.type.with_nonreturn_void? } + if each_param.any? {|param| param.type.with_nonreturn_void? } # steep:ignore DeprecatedReference true else if return_type.is_a?(Bases::Void) false else - return_type.with_nonreturn_void? + return_type.with_nonreturn_void? # steep:ignore DeprecatedReference end end end @@ -1505,11 +1505,11 @@ def has_classish_type? end def with_nonreturn_void? - if type.with_nonreturn_void? || self_type&.with_nonreturn_void? + if type.with_nonreturn_void? || self_type&.with_nonreturn_void? # steep:ignore DeprecatedReference true else if block = block() - block.type.with_nonreturn_void? || block.self_type&.with_nonreturn_void? || false + block.type.with_nonreturn_void? || block.self_type&.with_nonreturn_void? || false # steep:ignore DeprecatedReference else false end diff --git a/sig/cli/validate.rbs b/sig/cli/validate.rbs index 790a97c8c9..c57adc67bb 100644 --- a/sig/cli/validate.rbs +++ b/sig/cli/validate.rbs @@ -46,7 +46,7 @@ module RBS def validate_type_alias: () -> void def no_self_type_validator: (::RBS::Types::t | ::RBS::MethodType type) -> void def no_classish_type_validator: (::RBS::Types::t | ::RBS::MethodType type) -> void - def void_type_context_validator: (::RBS::Types::t | ::RBS::MethodType type, ?bool allowed_here) -> void + %a{deprecated} def void_type_context_validator: (::RBS::Types::t | ::RBS::MethodType type, ?bool allowed_here) -> void end end end diff --git a/sig/method_types.rbs b/sig/method_types.rbs index eabeeda2db..322e3ff8a2 100644 --- a/sig/method_types.rbs +++ b/sig/method_types.rbs @@ -53,6 +53,6 @@ module RBS def has_classish_type?: () -> bool - def with_nonreturn_void?: () -> bool + %a{deprecated} def with_nonreturn_void?: () -> bool end end diff --git a/sig/parser.rbs b/sig/parser.rbs index c405212d9f..e9328d0a2b 100644 --- a/sig/parser.rbs +++ b/sig/parser.rbs @@ -62,7 +62,14 @@ module RBS # RBS::Parser.parse_type("", require_eof: true) # => nil # ``` # - def self.parse_type: (Buffer | String, ?range: Range[Integer?], ?variables: Array[Symbol], ?require_eof: bool) -> Types::t? + # The `void_allowed` keyword controls whether `void` is allowed as a type. + # + # ```ruby + # RBS::Parser.parse_type("void", void_allowed: true) # => `void` + # RBS::Parser.parse_type("void", void_allowed: false) # => Raises an syntax error + # ``` + # + def self.parse_type: (Buffer | String, ?range: Range[Integer?], ?variables: Array[Symbol], ?require_eof: bool, ?void_allowed: bool) -> Types::t? # Parse whole RBS file and return an array of declarations # @@ -116,7 +123,7 @@ module RBS def self.buffer: (String | Buffer source) -> Buffer - def self._parse_type: (Buffer, Integer start_pos, Integer end_pos, Array[Symbol] variables, bool require_eof) -> Types::t? + def self._parse_type: (Buffer, Integer start_pos, Integer end_pos, Array[Symbol] variables, bool require_eof, bool void_allowed) -> Types::t? def self._parse_method_type: (Buffer, Integer start_pos, Integer end_pos, Array[Symbol] variables, bool require_eof) -> MethodType? diff --git a/sig/types.rbs b/sig/types.rbs index 38b3f75dc5..18db8995b9 100644 --- a/sig/types.rbs +++ b/sig/types.rbs @@ -54,7 +54,7 @@ module RBS # * The function return type is a return position (`() -> void`) # * Generic parameter is a return position (`Enumerator[Integer, void]`) # - def with_nonreturn_void?: () -> bool + %a{deprecated} def with_nonreturn_void?: () -> bool end # t represents union of all possible types. @@ -213,7 +213,7 @@ module RBS def has_classish_type?: () -> bool - def with_nonreturn_void?: () -> bool + %a{deprecated} def with_nonreturn_void?: () -> bool end class Interface @@ -452,7 +452,7 @@ module RBS def has_classish_type?: () -> bool - def with_nonreturn_void?: () -> bool + %a{deprecated} def with_nonreturn_void?: () -> bool def ==: (untyped) -> bool @@ -495,7 +495,7 @@ module RBS def has_classish_type?: () -> bool - def with_nonreturn_void?: () -> bool + %a{deprecated} def with_nonreturn_void?: () -> bool # Returns `?` def param_to_s: () -> String diff --git a/src/parser.c b/src/parser.c index 41cc64acc7..faa366100d 100644 --- a/src/parser.c +++ b/src/parser.c @@ -120,8 +120,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, bool void_allowed); +static bool parse_simple(rbs_parser_t *parser, rbs_node_t **type, bool void_allowed); /** * @returns A borrowed copy of the current token, which does *not* need to be freed. @@ -244,10 +244,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, bool void_allowed) { while (true) { rbs_node_t *type; - CHECK_PARSE(rbs_parse_type(parser, &type)); + CHECK_PARSE(rbs_parse_type(parser, &type, void_allowed)); rbs_node_list_append(types, type); if (parser->next_token.type == pCOMMA) { @@ -274,10 +274,10 @@ static bool parse_type_list(rbs_parser_t *parser, enum RBSTokenType eol, rbs_nod | {} type `,` ... `,` eol */ NODISCARD -static bool parse_type_list_with_commas(rbs_parser_t *parser, enum RBSTokenType eol, rbs_node_list_t *types, rbs_location_list_t *comma_locations) { +static bool parse_type_list_with_commas(rbs_parser_t *parser, enum RBSTokenType eol, rbs_node_list_t *types, rbs_location_list_t *comma_locations, bool void_allowed) { while (true) { rbs_node_t *type; - CHECK_PARSE(rbs_parse_type(parser, &type)); + CHECK_PARSE(rbs_parse_type(parser, &type, void_allowed)); rbs_node_list_append(types, type); if (parser->next_token.type == pCOMMA) { @@ -330,7 +330,7 @@ static bool parse_function_param(rbs_parser_t *parser, rbs_types_function_param_ 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, false)); type_range.end = parser->current_token.range.end; if (parser->next_token.type == pCOMMA || parser->next_token.type == pRPAREN) { @@ -660,14 +660,19 @@ 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, bool void_allowed) { 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, void_allowed)); if (parser->next_token.type == pQUESTION) { + if (void_allowed && type->type == RBS_TYPES_BASES_VOID) { + rbs_parser_set_error(parser, parser->current_token, true, "void type is not allowed here"); + return false; + } + rbs_parser_advance(parser); rg.end = parser->current_token.range.end; rbs_location_t *location = rbs_location_new(ALLOCATOR(), rg); @@ -702,7 +707,7 @@ static bool parse_self_type_binding(rbs_parser_t *parser, rbs_node_t **self_type 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, false)); ADVANCE_ASSERT(parser, pRBRACKET); *self_type = type; } @@ -781,7 +786,7 @@ static bool parse_function(rbs_parser_t *parser, bool accept_type_binding, parse 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, true)); ADVANCE_ASSERT(parser, pRBRACE); @@ -811,7 +816,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, true)); function_range.end = parser->current_token.range.end; rbs_location_t *loc = rbs_location_new(ALLOCATOR(), function_range); @@ -903,7 +908,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, false)); key = (rbs_ast_symbol_t *) ((rbs_types_literal_t *) type)->literal; break; @@ -920,7 +925,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, false)); field_range.end = parser->current_token.range.end; rbs_location_t *loc = rbs_location_new(ALLOCATOR(), field_range); @@ -1027,7 +1032,7 @@ 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)); + CHECK_PARSE(parse_type_list(parser, pRBRACKET, types, true)); ADVANCE_ASSERT(parser, pRBRACKET); args_range.end = parser->current_token.range.end; } else { @@ -1114,13 +1119,13 @@ 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, bool void_allowed) { rbs_parser_advance(parser); 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, false)); ADVANCE_ASSERT(parser, pRPAREN); *type = lparen_type; return true; @@ -1161,6 +1166,11 @@ static bool parse_simple(rbs_parser_t *parser, rbs_node_t **type) { return true; } case kVOID: { + if (!void_allowed) { + rbs_parser_set_error(parser, parser->current_token, true, "void type is not allowed here"); + return false; + } + rbs_location_t *loc = rbs_location_current_token(parser); *type = (rbs_node_t *) rbs_types_bases_void_new(ALLOCATOR(), loc); return true; @@ -1249,7 +1259,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, false)); } ADVANCE_ASSERT(parser, pRBRACKET); rg.end = parser->current_token.range.end; @@ -1291,21 +1301,26 @@ 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, bool void_allowed) { 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, void_allowed)); *type = optional; rbs_node_list_t *intersection_types = rbs_node_list_new(ALLOCATOR()); rbs_node_list_append(intersection_types, optional); while (parser->next_token.type == pAMP) { + if (void_allowed && (*type)->type == RBS_TYPES_BASES_VOID) { + rbs_parser_set_error(parser, parser->current_token, true, "void type is not allowed here"); + return false; + } + rbs_parser_advance(parser); rbs_node_t *type = NULL; - CHECK_PARSE(parse_optional(parser, &type)); + CHECK_PARSE(parse_optional(parser, &type, false)); rbs_node_list_append(intersection_types, type); } @@ -1323,19 +1338,24 @@ 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, bool void_allowed) { 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, void_allowed)); rbs_node_list_append(union_types, *type); while (parser->next_token.type == pBAR) { + if (void_allowed && (*type)->type == RBS_TYPES_BASES_VOID) { + rbs_parser_set_error(parser, parser->current_token, true, "void type is not allowed here"); + return false; + } + rbs_parser_advance(parser); rbs_node_t *intersection = NULL; - CHECK_PARSE(parse_intersection(parser, &intersection)); + CHECK_PARSE(parse_intersection(parser, &intersection, false)); rbs_node_list_append(union_types, intersection); } @@ -1428,7 +1448,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, false)); upper_bound_range.end = parser->current_token.range.end; break; @@ -1440,7 +1460,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, false)); lower_bound_range.end = parser->current_token.range.end; break; @@ -1455,7 +1475,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, true)); default_type_range.end = parser->current_token.range.end; required_param_allowed = false; @@ -1574,7 +1594,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, false)); decl_range.end = parser->current_token.range.end; rbs_location_t *loc = rbs_location_new(ALLOCATOR(), decl_range); @@ -1604,7 +1624,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, false)); decl_range.end = parser->current_token.range.end; @@ -1644,7 +1664,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, false)); decl_range.end = parser->current_token.range.end; @@ -2038,7 +2058,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, true)); ADVANCE_ASSERT(parser, pRBRACKET); args_range->end = parser->current_token.range.end; } else { @@ -2213,7 +2233,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, false)); member_range.end = parser->current_token.range.end; rbs_location_t *loc = rbs_location_new(ALLOCATOR(), member_range); @@ -2236,7 +2256,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, false)); CHECK_PARSE(parser_pop_typevar_table(parser)); @@ -2275,7 +2295,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, false)); CHECK_PARSE(parser_pop_typevar_table(parser)); @@ -2416,7 +2436,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, false)); CHECK_PARSE(parser_pop_typevar_table(parser)); @@ -2569,7 +2589,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, false)); rbs_parser_advance(parser); self_range.end = args_range.end = parser->current_token.range.end; } @@ -3717,7 +3737,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, true)) { return false; } @@ -3767,7 +3787,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, true)) { return false; } @@ -3800,7 +3820,7 @@ static bool parse_inline_trailing_annotation(rbs_parser_t *parser, rbs_ast_ruby_ } // Parse type list with comma tracking - CHECK_PARSE(parse_type_list_with_commas(parser, pRBRACKET, type_args, comma_locations)); + CHECK_PARSE(parse_type_list_with_commas(parser, pRBRACKET, type_args, comma_locations, true)); rbs_range_t close_bracket_range = parser->next_token.range; rbs_location_t *close_bracket_loc = rbs_location_new(ALLOCATOR(), close_bracket_range); diff --git a/test/multiple_error.rbs b/test/multiple_error.rbs index 88df91ef54..d18207e9ca 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 @@ -76,3 +76,4 @@ interface _CyclicTypeParameterBound[A] end class InconsistentClassModuleAlias = Nothing class CyclicClassAliasDefinition = CyclicClassAliasDefinition +type unknownTypeName = UNKNOWN_TYPE_NAME diff --git a/test/rbs/cli_test.rb b/test/rbs/cli_test.rb index 69cea0a285..151e9cfe4c 100644 --- a/test/rbs/cli_test.rb +++ b/test/rbs/cli_test.rb @@ -655,8 +655,8 @@ def test_validate_multiple Dir.mktmpdir do |dir| (Pathname(dir) + 'a.rbs').write(<<~RBS) class Foo - def foo: (void) -> void - def bar: (void) -> void + type foo = self + type bar = instance end RBS @@ -664,8 +664,8 @@ def bar: (void) -> void 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:13...2:17: `self` type is not allowed in this context (RBS::WillSyntaxError)" + assert_include stdout.string, "a.rbs:3:13...3:21: `instance` or `class` type is not allowed in this context (RBS::WillSyntaxError)" end end end @@ -675,16 +675,16 @@ 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 + type foo = self + type bar = instance end RBS assert_cli_success do 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)" + assert_include stdout.string, "a.rbs:2:13...2:17: `self` type is not allowed in this context (RBS::WillSyntaxError)" + assert_include stdout.string, "a.rbs:3:13...3:21: `instance` or `class` type is not allowed in this context (RBS::WillSyntaxError)" end end end @@ -694,16 +694,16 @@ def test_validate_multiple_with_exit_error_on_syntax_error Dir.mktmpdir do |dir| (Pathname(dir) + 'a.rbs').write(<<~RBS) class Foo - def foo: (void) -> void - def bar: (void) -> void + type foo = self + type bar = instance end RBS refute_cli_success do cli.run(["-I", dir, "--log-level=warn", "validate", "--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_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:13...2:17: `self` type is not allowed in this context (RBS::WillSyntaxError)" + assert_include stdout.string, "a.rbs:3:13...3:21: `instance` or `class` type is not allowed in this context (RBS::WillSyntaxError)" end end end @@ -713,16 +713,16 @@ def test_validate_multiple_with_fail_fast_and_exit_error_on_syntax_error Dir.mktmpdir do |dir| (Pathname(dir) + 'a.rbs').write(<<~RBS) class Foo - def foo: (void) -> void - def bar: (void) -> void + def foo: (T) -> void + def bar: (T) -> void end RBS refute_cli_success 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:12...2:13: Could not find T (RBS::NoTypeFoundError)" + assert_not_include stdout.string, "/a.rbs:3:12...3:13: Could not find T (RBS::NoTypeFoundError)" end end end @@ -732,7 +732,6 @@ def test_validate_multiple_with_many_errors refute_cli_success 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)") @@ -762,8 +761,6 @@ def test_validate_multiple_fail_fast refute_cli_success 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 @@ -773,17 +770,12 @@ def test_validate_multiple_fail_fast_and_exit_error_on_syntax_error refute_cli_success 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)") + assert_include(stdout.string, "test/multiple_error.rbs:6:17...6:24: ::TypeArg expects parameters [T], but given args [] (RBS::InvalidTypeApplicationError)") end end def test_context_validation tests = [ - <<~RBS, - class Foo - def foo: (void) -> untyped - end - RBS <<~RBS, class Bar[A] end diff --git a/test/rbs/signature_parsing_test.rb b/test/rbs/signature_parsing_test.rb index 17dbabbcea..130c6aa980 100644 --- a/test/rbs/signature_parsing_test.rb +++ b/test/rbs/signature_parsing_test.rb @@ -1005,7 +1005,7 @@ def ===: (untyped) -> bool assert_valid_signature do <<-EOS class X - def foo: (type: untyped, class: untyped, module: untyped, if: untyped, include: untyped, yield: untyped, def: untyped, self: untyped, instance: untyped, any: untyped, void: void) -> untyped + def foo: (type: untyped, class: untyped, module: untyped, if: untyped, include: untyped, yield: untyped, def: untyped, self: untyped, instance: untyped, any: untyped, void: untyped) -> untyped def bar: (untyped `type`, void: untyped `void`) -> untyped end EOS @@ -2370,4 +2370,11 @@ def return: (untyped return) -> void end RBS end + + def test_generics__default_type_void + Parser.parse_signature(<<~RBS) + class Foo[T = void] + end + RBS + end end diff --git a/test/rbs/type_parsing_test.rb b/test/rbs/type_parsing_test.rb index 8195db7e55..7848f0e348 100644 --- a/test/rbs/type_parsing_test.rb +++ b/test/rbs/type_parsing_test.rb @@ -170,14 +170,13 @@ def test_interface end def test_tuple - Parser.parse_type("[untyped, nil, void]").yield_self do |type| + Parser.parse_type("[untyped, nil]").yield_self do |type| assert_instance_of Types::Tuple, type assert_equal [ Types::Bases::Any.new(location: nil), - Types::Bases::Nil.new(location: nil), - Types::Bases::Void.new(location: nil) + Types::Bases::Nil.new(location: nil) ], type.types - assert_equal "[untyped, nil, void]", type.location.source + assert_equal "[untyped, nil]", type.location.source end Parser.parse_type("[untyped]").yield_self do |type| @@ -206,49 +205,48 @@ def test_tuple end def test_union_intersection - Parser.parse_type("untyped | void | nil").yield_self do |type| + Parser.parse_type("untyped | nil").yield_self do |type| assert_instance_of Types::Union, type assert_equal [ Types::Bases::Any.new(location: nil), - Types::Bases::Void.new(location: nil), Types::Bases::Nil.new(location: nil) ], type.types - assert_equal "untyped | void | nil", type.location.source + assert_equal "untyped | nil", type.location.source end - Parser.parse_type("untyped & void & nil").yield_self do |type| + Parser.parse_type("untyped & top & nil").yield_self do |type| assert_instance_of Types::Intersection, type assert_equal [ Types::Bases::Any.new(location: nil), - Types::Bases::Void.new(location: nil), + Types::Bases::Top.new(location: nil), Types::Bases::Nil.new(location: nil) ], type.types - assert_equal "untyped & void & nil", type.location.source + assert_equal "untyped & top & nil", type.location.source end - Parser.parse_type("untyped | void & nil").yield_self do |type| + Parser.parse_type("untyped | top & nil").yield_self do |type| assert_instance_of Types::Union, type assert_instance_of Types::Intersection, type.types[1] - assert_equal "untyped | void & nil", type.location.source + assert_equal "untyped | top & nil", type.location.source end - Parser.parse_type("untyped & void | nil").yield_self do |type| + Parser.parse_type("untyped & top | nil").yield_self do |type| assert_instance_of Types::Union, type assert_instance_of Types::Intersection, type.types[0] - assert_equal "untyped & void | nil", type.location.source + assert_equal "untyped & top | nil", type.location.source end - Parser.parse_type("untyped & (void | nil)").yield_self do |type| + Parser.parse_type("untyped & (top | nil)").yield_self do |type| assert_instance_of Types::Intersection, type assert_instance_of Types::Union, type.types[1] - assert_equal "untyped & (void | nil)", type.location.source + assert_equal "untyped & (top | nil)", type.location.source end end @@ -303,14 +301,14 @@ def test_proc_type assert_equal "^(untyped) -> void", type.location.source end - Parser.parse_type("^(untyped, void) -> void").yield_self do |type| + Parser.parse_type("^(untyped, top) -> void").yield_self do |type| assert_instance_of Types::Proc, type fun = type.type assert_equal [ Types::Function::Param.new(type: Types::Bases::Any.new(location: nil), name: nil), - Types::Function::Param.new(type: Types::Bases::Void.new(location: nil), name: nil), + Types::Function::Param.new(type: Types::Bases::Top.new(location: nil), name: nil), ], fun.required_positionals assert_equal [], fun.optional_positionals assert_nil fun.rest_positionals @@ -319,17 +317,17 @@ def test_proc_type assert_equal({}, fun.optional_keywords) assert_nil fun.rest_keywords - assert_equal "^(untyped, void) -> void", type.location.source + assert_equal "^(untyped, top) -> void", type.location.source end - Parser.parse_type("^(untyped x, void _y, bool `type`) -> void").yield_self do |type| + Parser.parse_type("^(untyped x, top _y, bool `type`) -> void").yield_self do |type| assert_instance_of Types::Proc, type fun = type.type assert_equal [ Types::Function::Param.new(type: Types::Bases::Any.new(location: nil), name: :x), - Types::Function::Param.new(type: Types::Bases::Void.new(location: nil), name: :_y), + Types::Function::Param.new(type: Types::Bases::Top.new(location: nil), name: :_y), Types::Function::Param.new(type: Types::Bases::Bool.new(location: nil), name: :type), ], fun.required_positionals assert_equal [], fun.optional_positionals @@ -339,10 +337,10 @@ def test_proc_type assert_equal({}, fun.optional_keywords) assert_nil fun.rest_keywords - assert_equal "^(untyped x, void _y, bool `type`) -> void", type.location.source + assert_equal "^(untyped x, top _y, bool `type`) -> void", type.location.source end - Parser.parse_type("^(untyped x, ?void, ?nil y) -> void").yield_self do |type| + Parser.parse_type("^(untyped x, ?top, ?nil y) -> void").yield_self do |type| assert_instance_of Types::Proc, type fun = type.type @@ -351,7 +349,7 @@ def test_proc_type Types::Function::Param.new(type: Types::Bases::Any.new(location: nil), name: :x), ], fun.required_positionals assert_equal [ - Types::Function::Param.new(type: Types::Bases::Void.new(location: nil), name: nil), + Types::Function::Param.new(type: Types::Bases::Top.new(location: nil), name: nil), Types::Function::Param.new(type: Types::Bases::Nil.new(location: nil), name: :y), ], fun.optional_positionals assert_nil fun.rest_positionals @@ -360,10 +358,10 @@ def test_proc_type assert_equal({}, fun.optional_keywords) assert_nil fun.rest_keywords - assert_equal "^(untyped x, ?void, ?nil y) -> void", type.location.source + assert_equal "^(untyped x, ?top, ?nil y) -> void", type.location.source end - Parser.parse_type("^(untyped x, ?void, ?nil y, *untyped a) -> void").yield_self do |type| + Parser.parse_type("^(untyped x, ?top, ?nil y, *untyped a) -> void").yield_self do |type| assert_instance_of Types::Proc, type fun = type.type @@ -372,7 +370,7 @@ def test_proc_type Types::Function::Param.new(type: Types::Bases::Any.new(location: nil), name: :x), ], fun.required_positionals assert_equal [ - Types::Function::Param.new(type: Types::Bases::Void.new(location: nil), name: nil), + Types::Function::Param.new(type: Types::Bases::Top.new(location: nil), name: nil), Types::Function::Param.new(type: Types::Bases::Nil.new(location: nil), name: :y), ], fun.optional_positionals assert_equal Types::Function::Param.new(type: Types::Bases::Any.new(location: nil), name: :a), @@ -382,7 +380,7 @@ def test_proc_type assert_equal({}, fun.optional_keywords) assert_nil fun.rest_keywords - assert_equal "^(untyped x, ?void, ?nil y, *untyped a) -> void", type.location.source + assert_equal "^(untyped x, ?top, ?nil y, *untyped a) -> void", type.location.source end Parser.parse_type("^(untyped x, *untyped a, nil z) -> void").yield_self do |type| @@ -518,7 +516,7 @@ def test_optional assert_instance_of Types::Proc, type end - Parser.parse_type("untyped | void?").yield_self do |type| + Parser.parse_type("untyped | top").yield_self do |type| assert_instance_of Types::Union, type end @@ -883,4 +881,54 @@ def test_escape_sequences assert_equal "\x00", type.types[2].literal end end + + def test_parse__void__top_level + Parser.parse_type("void").tap do |type| + assert_instance_of Types::Bases::Void, type + assert_equal "void", type.location.source + end + + Parser.parse_type("void", void_allowed: true).tap do |type| + assert_instance_of Types::Bases::Void, type + assert_equal "void", type.location.source + end + + assert_raises RBS::ParsingError do + Parser.parse_type("void", void_allowed: false) + end + end + + def test_parse__void__generics_params + Parser.parse_type("Array[void]").tap do |type| + assert_instance_of Types::ClassInstance, type + end + end + + def test_parse__void__return_types + Parser.parse_type("^() -> void").tap do |type| + assert_instance_of Types::Proc, type + end + + Parser.parse_type("^() { () -> void } -> void").tap do |type| + assert_instance_of Types::Proc, type + end + end + + def test_parse__void__prohibited + assert_raises RBS::ParsingError do + Parser.parse_type("void?") + end + + assert_raises RBS::ParsingError do + Parser.parse_type("void | true") + end + + assert_raises RBS::ParsingError do + Parser.parse_type("void & true") + end + + assert_raises RBS::ParsingError do + Parser.parse_type("[void]") + end + end end diff --git a/test/rbs/types_test.rb b/test/rbs/types_test.rb index 1b343a020e..b4ba8e882a 100644 --- a/test/rbs/types_test.rb +++ b/test/rbs/types_test.rb @@ -77,25 +77,4 @@ def test_has_classish_type? refute_predicate type, :has_classish_type? end end - - def test_with_nonreturn_void? - [ - "void", - "[void]", - "void?", - "^() [self: void] -> void" - ].each do |str| - type = parse_type(str) - assert_predicate type, :with_nonreturn_void? - end - - [ - "^() -> void", - "[Integer, String]", - "Enumerator[Integer, void]" - ].each do |str| - type = parse_type(str) - refute_predicate type, :with_nonreturn_void? - end - end end