Skip to content

Commit 13bd8e7

Browse files
soutaroclaude
andcommitted
Add inline parser support for module-self annotation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 98484b8 commit 13bd8e7

5 files changed

Lines changed: 132 additions & 1 deletion

File tree

lib/rbs/ast/ruby/declarations.rb

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,17 @@ def each_decl(&block)
137137

138138
def type_params = []
139139

140-
def self_types = []
140+
def self_types
141+
members.filter_map do |member|
142+
if member.is_a?(Members::ModuleSelfMember)
143+
AST::Declarations::Module::Self.new(
144+
name: member.name,
145+
args: member.args,
146+
location: member.location
147+
)
148+
end
149+
end
150+
end
141151

142152
def location
143153
rbs_location(node.location)

lib/rbs/ast/ruby/members.rb

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,34 @@ def type_fingerprint
717717
]
718718
end
719719
end
720+
721+
class ModuleSelfMember < Base
722+
attr_reader :annotation
723+
724+
def initialize(buffer, annotation)
725+
super(buffer)
726+
@annotation = annotation
727+
end
728+
729+
def name
730+
annotation.name
731+
end
732+
733+
def args
734+
annotation.args
735+
end
736+
737+
def location
738+
annotation.location
739+
end
740+
741+
def type_fingerprint
742+
[
743+
"members/module_self",
744+
annotation.type_fingerprint
745+
]
746+
end
747+
end
720748
end
721749
end
722750
end

lib/rbs/inline_parser.rb

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,32 @@ def visit_module_node(node)
134134
end
135135

136136
module_decl = AST::Ruby::Declarations::ModuleDecl.new(buffer, module_name, node)
137+
138+
if leading_ref = comments.leading_block(node)
139+
unused_annotations = [] #: Array[AST::Ruby::CommentBlock::AnnotationSyntaxError | AST::Ruby::Annotations::leading_annotation]
140+
141+
leading_ref.block.each_paragraph([]) do |paragraph|
142+
case paragraph
143+
when AST::Ruby::Annotations::ModuleSelfAnnotation
144+
module_decl.members << AST::Ruby::Members::ModuleSelfMember.new(buffer, paragraph)
145+
when Location
146+
# Skip
147+
when AST::Ruby::CommentBlock::AnnotationSyntaxError
148+
unused_annotations << paragraph
149+
when AST::Ruby::Annotations::SkipAnnotation
150+
# Already handled by skip_node?
151+
else
152+
unused_annotations << paragraph
153+
end
154+
end
155+
156+
unless unused_annotations.empty?
157+
report_unused_annotation(*unused_annotations)
158+
end
159+
160+
leading_ref.associate!
161+
end
162+
137163
insert_declaration(module_decl)
138164
visit_class_or_module_body(module_decl, node)
139165
end

sig/ast/ruby/members.rbs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ module RBS
1616
| IncludeMember | ExtendMember | PrependMember
1717
| AttrReaderMember | AttrWriterMember | AttrAccessorMember
1818
| InstanceVariableMember
19+
| ModuleSelfMember
1920

2021
class MethodTypeAnnotation
2122
class DocStyle
@@ -172,6 +173,20 @@ module RBS
172173

173174
def type_fingerprint: () -> untyped
174175
end
176+
177+
class ModuleSelfMember < Base
178+
attr_reader annotation: Annotations::ModuleSelfAnnotation
179+
180+
def initialize: (Buffer, Annotations::ModuleSelfAnnotation) -> void
181+
182+
def name: () -> TypeName
183+
184+
def args: () -> Array[Types::t]
185+
186+
def location: () -> Location
187+
188+
def type_fingerprint: () -> untyped
189+
end
175190
end
176191
end
177192
end

test/rbs/inline_parser_test.rb

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1564,6 +1564,58 @@ def foo
15641564
end
15651565
end
15661566

1567+
def test_parse__module_self
1568+
result = parse(<<~RUBY)
1569+
# @rbs module-self: _Each[String]
1570+
module Enumerable2
1571+
end
1572+
RUBY
1573+
1574+
assert_empty result.diagnostics
1575+
1576+
result.declarations[0].tap do |decl|
1577+
assert_instance_of RBS::AST::Ruby::Declarations::ModuleDecl, decl
1578+
assert_equal RBS::TypeName.parse("Enumerable2"), decl.module_name
1579+
1580+
assert_equal 1, decl.members.size
1581+
assert_equal 1, decl.self_types.size
1582+
1583+
decl.members[0].tap do |member|
1584+
assert_instance_of RBS::AST::Ruby::Members::ModuleSelfMember, member
1585+
assert_equal "_Each", member.name.to_s
1586+
assert_equal 1, member.args.size
1587+
assert_equal "String", member.args[0].to_s
1588+
end
1589+
end
1590+
end
1591+
1592+
def test_parse__module_self_multiple
1593+
result = parse(<<~RUBY)
1594+
# @rbs module-self: _Each[String]
1595+
# @rbs module-self: Comparable
1596+
module StringCollection
1597+
end
1598+
RUBY
1599+
1600+
assert_empty result.diagnostics
1601+
1602+
result.declarations[0].tap do |decl|
1603+
assert_instance_of RBS::AST::Ruby::Declarations::ModuleDecl, decl
1604+
1605+
assert_equal 2, decl.self_types.size
1606+
1607+
decl.self_types[0].tap do |member|
1608+
assert_equal "_Each", member.name.to_s
1609+
assert_equal 1, member.args.size
1610+
end
1611+
1612+
decl.self_types[1].tap do |member|
1613+
assert_equal "Comparable", member.name.to_s
1614+
assert_equal 0, member.args.size
1615+
end
1616+
end
1617+
end
1618+
15671619
def test_parse__constant_declaration_basic
15681620
result = parse(<<~RUBY)
15691621
class Example

0 commit comments

Comments
 (0)