diff --git a/config.yml b/config.yml index 389f2033e..0d0ee2bf1 100644 --- a/config.yml +++ b/config.yml @@ -345,7 +345,7 @@ nodes: - name: RBS::Types::Bases::Top - name: RBS::Types::Bases::Void - name: RBS::Types::Block - expose_location: false + expose_location: true fields: - name: type c_type: rbs_node diff --git a/ext/rbs_extension/ast_translation.c b/ext/rbs_extension/ast_translation.c index 3a3d0c83e..3f589cbdb 100644 --- a/ext/rbs_extension/ast_translation.c +++ b/ext/rbs_extension/ast_translation.c @@ -905,6 +905,7 @@ VALUE rbs_struct_to_ruby_value(rbs_translation_context_t ctx, rbs_node_t *instan rbs_types_block_t *node = (rbs_types_block_t *)instance; VALUE h = rb_hash_new(); + rb_hash_aset(h, ID2SYM(rb_intern("location")), rbs_loc_to_ruby_location(ctx, node->base.location)); rb_hash_aset(h, ID2SYM(rb_intern("type")), rbs_struct_to_ruby_value(ctx, (rbs_node_t *) node->type)); // rbs_node rb_hash_aset(h, ID2SYM(rb_intern("required")), node->required ? Qtrue : Qfalse); rb_hash_aset(h, ID2SYM(rb_intern("self_type")), rbs_struct_to_ruby_value(ctx, (rbs_node_t *) node->self_type)); // rbs_node diff --git a/lib/rbs/types.rb b/lib/rbs/types.rb index aa5fdf496..3b99d9def 100644 --- a/lib/rbs/types.rb +++ b/lib/rbs/types.rb @@ -1339,8 +1339,10 @@ class Block attr_reader :type attr_reader :required attr_reader :self_type + attr_reader :location - def initialize(type:, required:, self_type: nil) + def initialize(location: nil, type:, required:, self_type: nil) + @location = location @type = type @required = required ? true : false @self_type = self_type diff --git a/sig/types.rbs b/sig/types.rbs index 81b45d58c..38b3f75dc 100644 --- a/sig/types.rbs +++ b/sig/types.rbs @@ -518,7 +518,10 @@ module RBS attr_reader self_type: t? - def initialize: (type: function, ?self_type: t?, required: boolish) -> void + type loc = Location[bot, bot] + attr_reader location: loc? + + def initialize: (?location: loc?, type: function, ?self_type: t?, required: boolish) -> void def ==: (untyped other) -> bool diff --git a/src/parser.c b/src/parser.c index 5b559e40a..e315ac2fc 100644 --- a/src/parser.c +++ b/src/parser.c @@ -722,11 +722,17 @@ static bool parse_function(rbs_parser_t *parser, bool accept_type_binding, parse } bool required = true; + rbs_range_t block_range; + if (parser->next_token.type == pQUESTION && parser->next_token2.type == pLBRACE) { // Optional block + block_range.start = parser->next_token.range.start; required = false; rbs_parser_advance(parser); + } else if (parser->next_token.type == pLBRACE) { + block_range.start = parser->next_token.range.start; } + if (parser->next_token.type == pLBRACE) { rbs_parser_advance(parser); @@ -746,9 +752,12 @@ static bool parse_function(rbs_parser_t *parser, bool accept_type_binding, parse rbs_node_t *block_return_type = NULL; CHECK_PARSE(parse_optional(parser, &block_return_type)); + ADVANCE_ASSERT(parser, pRBRACE); + + block_range.end = parser->current_token.range.end; + rbs_location_t *loc = rbs_location_new(ALLOCATOR(), block_range); + rbs_node_t *block_function = NULL; - function_range.end = parser->current_token.range.end; - rbs_location_t *loc = rbs_location_new(ALLOCATOR(), function_range); if (rbs_is_untyped_params(&block_params)) { block_function = (rbs_node_t *) rbs_types_untyped_function_new(ALLOCATOR(), loc, block_return_type); } else { @@ -767,8 +776,6 @@ static bool parse_function(rbs_parser_t *parser, bool accept_type_binding, parse } block = rbs_types_block_new(ALLOCATOR(), loc, block_function, required, self_type); - - ADVANCE_ASSERT(parser, pRBRACE); } ADVANCE_ASSERT(parser, pARROW); diff --git a/test/rbs/parser_test.rb b/test/rbs/parser_test.rb index dd5bc1848..294a41cbf 100644 --- a/test/rbs/parser_test.rb +++ b/test/rbs/parser_test.rb @@ -733,6 +733,20 @@ def test_parse_method_type2 end end + def test_parse_method_type_block + RBS::Parser.parse_method_type(buffer("{ -> void } -> void")).tap do |method_type| + assert_equal "{ -> void }", method_type.block.location.source + end + + RBS::Parser.parse_method_type(buffer("(Integer) { (Integer) -> void } -> void")).tap do |method_type| + assert_equal "{ (Integer) -> void }", method_type.block.location.source + end + + RBS::Parser.parse_method_type(buffer("() ?{ () -> void } -> void")).tap do |method_type| + assert_equal "?{ () -> void }", method_type.block.location.source + end + end + def test_newline_inconsistency code = "module Test\r\nend"