Skip to content

Commit dd404fb

Browse files
committed
WIP
1 parent d67b82e commit dd404fb

14 files changed

Lines changed: 110 additions & 88 deletions

lib/rbi/model.rb

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -269,13 +269,16 @@ def fully_qualified_name
269269

270270
class Const < NodeWithComments
271271
#: String
272-
attr_reader :name, :value
272+
attr_reader :name
273273

274-
#: (String name, String value, ?loc: Loc?, ?comments: Array[Comment]) ?{ (Const node) -> void } -> void
275-
def initialize(name, value, loc: nil, comments: [], &block)
274+
#: (String | Type)?
275+
attr_reader :type
276+
277+
#: (String name, (String | Type)? type, ?loc: Loc?, ?comments: Array[Comment]) ?{ (Const node) -> void } -> void
278+
def initialize(name, type: nil, loc: nil, comments: [], &block)
276279
super(loc: loc, comments: comments)
277280
@name = name
278-
@value = value
281+
@type = type
279282
block&.call(self)
280283
end
281284

lib/rbi/parser.rb

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ def visit_constant_assign(node)
237237
when Prism::ConstantPathWriteNode
238238
node_string!(node.target)
239239
end,
240-
node_string!(node.value),
240+
type: parse_t_let_type(node.value),
241241
loc: node_loc(node),
242242
comments: node_comments(node),
243243
)
@@ -791,6 +791,24 @@ def parse_visibility(name, node)
791791
end
792792
end
793793

794+
# Parse a string containing a `T.let(x, X)` and extract the type
795+
#
796+
# Returns `nil` is the string is not a `T.let`.
797+
#: (Prism::Node? node) -> String?
798+
def parse_t_let_type(node)
799+
return unless node
800+
801+
return unless node.is_a?(Prism::CallNode)
802+
return unless node.name == :let
803+
return unless node.receiver&.slice =~ /^(::)?T$/
804+
805+
arguments = node.arguments&.arguments
806+
return unless arguments
807+
return unless arguments.size == 2
808+
809+
arguments.fetch(1, nil)&.slice
810+
end
811+
794812
#: -> void
795813
def separate_header_comments
796814
current_scope.nodes.dup.each do |child_node|

lib/rbi/printer.rb

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,11 @@ def visit_const(node)
233233
print_loc(node)
234234
visit_all(node.comments)
235235

236-
printl("#{node.name} = #{node.value}")
236+
if node.type
237+
printl("#{node.name} = T.let(T.unsafe(nil), #{node.type})")
238+
else
239+
printl("#{node.name} = T.unsafe(nil)")
240+
end
237241
end
238242

239243
# @override
@@ -537,7 +541,19 @@ def visit_tenum_block(node)
537541

538542
printl("enums do")
539543
indent
540-
visit_all(node.nodes)
544+
@previous_node = nil
545+
node.nodes.each do |child|
546+
if child.is_a?(Const) && child.type.nil?
547+
print_blank_line_before(child)
548+
print_loc(child)
549+
visit_all(child.comments)
550+
printl("#{child.name} = new")
551+
else
552+
visit(child)
553+
end
554+
@previous_node = child
555+
end
556+
@previous_node = node
541557
dedent
542558
printl("end")
543559
end

lib/rbi/rbs_printer.rb

Lines changed: 10 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ def visit_const(node)
229229
print_loc(node)
230230
visit_all(node.comments)
231231

232-
type = parse_t_let(node.value)
232+
type = node.type
233233
if type
234234
type = parse_type(type)
235235
printl("#{node.name}: #{type.rbs_string}")
@@ -645,20 +645,20 @@ def visit_tenum(node)
645645
# @override
646646
#: (TEnumBlock node) -> void
647647
def visit_tenum_block(node)
648+
@previous_node = nil
649+
parent = node.parent_scope
648650
node.nodes.each do |child|
649-
child = if child.is_a?(Const) && child.value == "new"
650-
parent = node.parent_scope
651-
Const.new(
652-
child.name,
653-
"T.let(nil, #{parent.is_a?(TEnum) ? parent.name : "T.untyped"})",
654-
comments: child.comments,
655-
)
651+
if child.is_a?(Const) && child.type.nil?
652+
print_blank_line_before(child)
653+
print_loc(child)
654+
visit_all(child.comments)
655+
printl("#{child.name}: #{parent.is_a?(TEnum) ? parent.name : "untyped"}")
656656
else
657-
child
657+
visit(child)
658658
end
659-
visit(child)
660659
@previous_node = child
661660
end
661+
@previous_node = node
662662
end
663663

664664
# @override
@@ -850,30 +850,6 @@ def parse_type(type)
850850
rescue Type::Error => e
851851
raise Error, "Failed to parse type `#{type}` (#{e.message})"
852852
end
853-
854-
# Parse a string containing a `T.let(x, X)` and extract the type
855-
#
856-
# Returns `nil` is the string is not a `T.let`.
857-
#: (String? code) -> String?
858-
def parse_t_let(code)
859-
return unless code
860-
861-
res = Prism.parse(code)
862-
return unless res.success?
863-
864-
node = res.value
865-
return unless node.is_a?(Prism::ProgramNode)
866-
867-
node = node.statements.body.first
868-
return unless node.is_a?(Prism::CallNode)
869-
return unless node.name == :let
870-
return unless node.receiver&.slice =~ /^(::)?T$/
871-
872-
arguments = node.arguments&.arguments
873-
return unless arguments
874-
875-
arguments.fetch(1, nil)&.slice
876-
end
877853
end
878854

879855
class TypePrinter

lib/rbi/rewriters/merge_trees.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,7 @@ class Const
384384
# @override
385385
#: (Node other) -> bool
386386
def compatible_with?(other)
387-
other.is_a?(Const) && name == other.name && value == other.value
387+
other.is_a?(Const) && name == other.name && type == other.type
388388
end
389389
end
390390

test/rbi/model_test.rb

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def test_model_block_builders
4242
tree << SingletonClass.new do |node|
4343
node.comments << Comment.new("comment")
4444
end
45-
tree << Const.new("C", "42") do |node|
45+
tree << Const.new("C", type: "Integer") do |node|
4646
node.comments << Comment.new("comment")
4747
end
4848
tree << AttrAccessor.new(:a1) do |node|
@@ -108,8 +108,8 @@ def test_model_block_builders
108108
tree << TEnum.new("Enum") do |node|
109109
node << TEnumBlock.new do |block|
110110
block.comments << Comment.new("comment")
111-
block << Const.new("A", "new", comments: [Comment.new("comment")])
112-
block << Const.new("B", "new", comments: [Comment.new("comment")])
111+
block << Const.new("A", comments: [Comment.new("comment")])
112+
block << Const.new("B", comments: [Comment.new("comment")])
113113
end
114114
end
115115
tree << Helper.new("foo") do |node|
@@ -270,19 +270,19 @@ def test_model_fully_qualified_names
270270
cls1 << singleton_class
271271
assert_equal("::Foo::Bar::<self>", singleton_class.fully_qualified_name)
272272

273-
const = Const.new("Foo", "42")
273+
const = Const.new("Foo", type: "Integer")
274274
assert_equal("::Foo", const.fully_qualified_name)
275275

276276
mod << const
277277
assert_equal("::Foo::Foo", const.fully_qualified_name)
278278

279-
const2 = Const.new("Foo::Bar", "42")
279+
const2 = Const.new("Foo::Bar", type: "42")
280280
assert_equal("::Foo::Bar", const2.fully_qualified_name)
281281

282282
mod << const2
283283
assert_equal("::Foo::Foo::Bar", const2.fully_qualified_name)
284284

285-
const3 = Const.new("::Foo::Bar", "42")
285+
const3 = Const.new("::Foo::Bar", type: "42")
286286
assert_equal("::Foo::Bar", const3.fully_qualified_name)
287287

288288
mod << const3
@@ -344,13 +344,13 @@ def test_model_nodes_as_strings
344344
cls << singleton_class
345345
assert_equal("::Foo::Bar::<self>", singleton_class.to_s)
346346

347-
const = Const.new("Foo", "42")
347+
const = Const.new("Foo", type: "Integer")
348348
assert_equal("::Foo", const.to_s)
349349

350350
mod << const
351351
assert_equal("::Foo::Foo", const.to_s)
352352

353-
const2 = Const.new("Foo::Bar", "42")
353+
const2 = Const.new("Foo::Bar", type: "42")
354354
assert_equal("::Foo::Bar", const2.to_s)
355355

356356
mod << const2
@@ -404,8 +404,8 @@ def test_model_nodes_as_strings
404404
assert_equal("::Foo::Enum", enum.to_s)
405405

406406
block = TEnumBlock.new
407-
block << Const.new("A", "new")
408-
block << Const.new("B", "new")
407+
block << Const.new("A", comments: [Comment.new("comment")])
408+
block << Const.new("B", comments: [Comment.new("comment")])
409409
enum << block
410410
assert_equal("::Foo::Enum.enums", block.to_s)
411411

test/rbi/parser_test.rb

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,16 @@ def test_parse_constants
8585
RBI
8686

8787
tree = parse_rbi(rbi)
88-
assert_equal(rbi, tree.string)
88+
assert_equal(<<~RBI, tree.string)
89+
Foo = T.unsafe(nil)
90+
Bar = T.unsafe(nil)
91+
Baz = T.unsafe(nil)
92+
A = T.unsafe(nil)
93+
B = T.unsafe(nil)
94+
C = T.unsafe(nil)
95+
D = T.unsafe(nil)
96+
A::B::C = T.unsafe(nil)
97+
RBI
8998
end
9099

91100
def test_parse_constants_with_newlines
@@ -546,13 +555,13 @@ def test_parse_constants_locations
546555
tree = parse_rbi(rbi)
547556
assert_equal(<<~RBI, tree.string(print_locs: true))
548557
# -:1:0-1:8
549-
Foo = 42
558+
Foo = T.unsafe(nil)
550559
# -:2:0-2:11
551-
Bar = "foo"
560+
Bar = T.unsafe(nil)
552561
# -:3:0-3:11
553-
::Baz = Bar
562+
::Baz = T.unsafe(nil)
554563
# -:4:0-4:13
555-
A::B::C = Foo
564+
A::B::C = T.unsafe(nil)
556565
RBI
557566
end
558567

@@ -889,7 +898,7 @@ def c(a); end
889898
attr_reader :a
890899
891900
# E comment
892-
E = _
901+
E = T.unsafe(nil)
893902
end
894903
end
895904
RBI

test/rbi/printer_test.rb

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -96,14 +96,14 @@ def baz_class_method; end
9696

9797
def test_print_constants
9898
rbi = Tree.new
99-
rbi << Const.new("Foo", "42")
100-
rbi << Const.new("Bar", "'foo'")
101-
rbi << Const.new("Baz", "Bar")
99+
rbi << Const.new("Foo", type: "Integer")
100+
rbi << Const.new("Bar", type: Type.boolean)
101+
rbi << Const.new("Baz")
102102

103103
assert_equal(<<~RBI, rbi.string)
104-
Foo = 42
105-
Bar = 'foo'
106-
Baz = Bar
104+
Foo = T.let(T.unsafe(nil), Integer)
105+
Bar = T.let(T.unsafe(nil), T::Boolean)
106+
Baz = T.unsafe(nil)
107107
RBI
108108
end
109109

@@ -300,9 +300,9 @@ def foo; end
300300
def test_print_t_enums
301301
rbi = TEnum.new("Foo")
302302
block = TEnumBlock.new
303-
block << Const.new("A", "new")
304-
block << Const.new("B", "new")
305-
block << Const.new("C", "new")
303+
block << Const.new("A")
304+
block << Const.new("B")
305+
block << Const.new("C", type: "Integer")
306306
block << Method.new("bar")
307307
rbi << block
308308
rbi << Method.new("baz")
@@ -312,7 +312,7 @@ class Foo < T::Enum
312312
enums do
313313
A = new
314314
B = new
315-
C = new
315+
C = T.let(T.unsafe(nil), Integer)
316316
def bar; end
317317
end
318318
@@ -401,7 +401,7 @@ def test_print_nodes_with_comments
401401
rbi << Module.new("Foo", comments: comments_single)
402402
rbi << Class.new("Bar", comments: comments_multi)
403403
rbi << SingletonClass.new(comments: comments_single)
404-
rbi << Const.new("Foo", "42", comments: comments_multi)
404+
rbi << Const.new("Foo", comments: comments_multi)
405405
rbi << Include.new("A", comments: comments_single)
406406
rbi << Extend.new("A", comments: comments_multi)
407407

@@ -418,8 +418,8 @@ def test_print_nodes_with_comments
418418

419419
enum = TEnum.new("Foo", comments: comments_multi)
420420
enum << TEnumBlock.new(comments: comments_single) do |block|
421-
block << Const.new("A", "new")
422-
block << Const.new("B", "new")
421+
block << Const.new("A")
422+
block << Const.new("B")
423423
end
424424

425425
rbi << enum
@@ -442,7 +442,7 @@ class << self; end
442442
443443
# This is a
444444
# Multiline Comment
445-
Foo = 42
445+
Foo = T.unsafe(nil)
446446
447447
# This is a single line comment
448448
include A
@@ -1092,7 +1092,7 @@ def test_print_nodes_locations
10921092
rbi << SingletonClass.new(loc: loc)
10931093
rbi << TEnum.new("TE", loc: loc)
10941094
rbi << TStruct.new("TS", loc: loc)
1095-
rbi << Const.new("C", "42", loc: loc)
1095+
rbi << Const.new("C", loc: loc)
10961096
rbi << Extend.new("E", loc: loc)
10971097
rbi << Include.new("I", loc: loc)
10981098
rbi << Send.new("foo", loc: loc)
@@ -1114,7 +1114,7 @@ class TE < T::Enum; end
11141114
# file.rbi:1:3-2:4
11151115
class TS < T::Struct; end
11161116
# file.rbi:1:3-2:4
1117-
C = 42
1117+
C = T.unsafe(nil)
11181118
# file.rbi:1:3-2:4
11191119
extend E
11201120
# file.rbi:1:3-2:4

test/rbi/rbs_printer_test.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -709,8 +709,8 @@ def test_print_t_enums
709709
class Foo < T::Enum
710710
enums do
711711
A = new
712-
B = new
713-
C = new
712+
B = 42
713+
C = T.let(nil, T.nilable(Foo))
714714
end
715715
716716
def baz; end
@@ -720,8 +720,8 @@ def baz; end
720720
assert_equal(<<~RBI, rbi.rbs_string)
721721
class Foo
722722
A: Foo
723-
B: Foo
724-
C: Foo
723+
B: unsafe
724+
C: Foo?
725725
def baz: -> untyped
726726
end
727727
RBI

0 commit comments

Comments
 (0)