typeprof 0.21.11 → 0.30.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +15 -31
  3. data/bin/typeprof +5 -0
  4. data/doc/doc.ja.md +134 -0
  5. data/doc/doc.md +136 -0
  6. data/lib/typeprof/cli/cli.rb +178 -0
  7. data/lib/typeprof/cli.rb +3 -133
  8. data/lib/typeprof/code_range.rb +112 -0
  9. data/lib/typeprof/core/ast/base.rb +263 -0
  10. data/lib/typeprof/core/ast/call.rb +259 -0
  11. data/lib/typeprof/core/ast/const.rb +126 -0
  12. data/lib/typeprof/core/ast/control.rb +433 -0
  13. data/lib/typeprof/core/ast/meta.rb +150 -0
  14. data/lib/typeprof/core/ast/method.rb +339 -0
  15. data/lib/typeprof/core/ast/misc.rb +263 -0
  16. data/lib/typeprof/core/ast/module.rb +123 -0
  17. data/lib/typeprof/core/ast/pattern.rb +140 -0
  18. data/lib/typeprof/core/ast/sig_decl.rb +471 -0
  19. data/lib/typeprof/core/ast/sig_type.rb +663 -0
  20. data/lib/typeprof/core/ast/value.rb +319 -0
  21. data/lib/typeprof/core/ast/variable.rb +315 -0
  22. data/lib/typeprof/core/ast.rb +472 -0
  23. data/lib/typeprof/core/builtin.rb +146 -0
  24. data/lib/typeprof/core/env/method.rb +137 -0
  25. data/lib/typeprof/core/env/method_entity.rb +55 -0
  26. data/lib/typeprof/core/env/module_entity.rb +408 -0
  27. data/lib/typeprof/core/env/static_read.rb +155 -0
  28. data/lib/typeprof/core/env/type_alias_entity.rb +27 -0
  29. data/lib/typeprof/core/env/value_entity.rb +32 -0
  30. data/lib/typeprof/core/env.rb +366 -0
  31. data/lib/typeprof/core/graph/box.rb +998 -0
  32. data/lib/typeprof/core/graph/change_set.rb +224 -0
  33. data/lib/typeprof/core/graph/filter.rb +155 -0
  34. data/lib/typeprof/core/graph/vertex.rb +225 -0
  35. data/lib/typeprof/core/service.rb +514 -0
  36. data/lib/typeprof/core/type.rb +352 -0
  37. data/lib/typeprof/core/util.rb +81 -0
  38. data/lib/typeprof/core.rb +31 -0
  39. data/lib/typeprof/diagnostic.rb +35 -0
  40. data/lib/typeprof/lsp/messages.rb +415 -0
  41. data/lib/typeprof/lsp/server.rb +203 -0
  42. data/lib/typeprof/lsp/text.rb +69 -0
  43. data/lib/typeprof/lsp/util.rb +51 -0
  44. data/lib/typeprof/lsp.rb +4 -907
  45. data/lib/typeprof/version.rb +1 -1
  46. data/lib/typeprof.rb +4 -18
  47. data/typeprof.gemspec +5 -7
  48. metadata +47 -33
  49. data/.github/dependabot.yml +0 -6
  50. data/.github/workflows/main.yml +0 -39
  51. data/.gitignore +0 -9
  52. data/Gemfile +0 -17
  53. data/Gemfile.lock +0 -41
  54. data/Rakefile +0 -10
  55. data/exe/typeprof +0 -10
  56. data/lib/typeprof/analyzer.rb +0 -2598
  57. data/lib/typeprof/arguments.rb +0 -414
  58. data/lib/typeprof/block.rb +0 -176
  59. data/lib/typeprof/builtin.rb +0 -893
  60. data/lib/typeprof/code-range.rb +0 -177
  61. data/lib/typeprof/config.rb +0 -158
  62. data/lib/typeprof/container-type.rb +0 -912
  63. data/lib/typeprof/export.rb +0 -589
  64. data/lib/typeprof/import.rb +0 -852
  65. data/lib/typeprof/insns-def.rb +0 -65
  66. data/lib/typeprof/iseq.rb +0 -864
  67. data/lib/typeprof/method.rb +0 -355
  68. data/lib/typeprof/type.rb +0 -1140
  69. data/lib/typeprof/utils.rb +0 -212
  70. data/tools/coverage.rb +0 -14
  71. data/tools/setup-insns-def.rb +0 -30
  72. data/typeprof-lsp +0 -3
@@ -0,0 +1,112 @@
1
+ module TypeProf
2
+ class CodePosition
3
+ def initialize(lineno, column)
4
+ @lineno = lineno
5
+ @column = column
6
+ end
7
+
8
+ def self.from_lsp(pos)
9
+ new(pos[:line] + 1, pos[:character])
10
+ end
11
+
12
+ def to_lsp
13
+ { line: @lineno - 1, character: @column }
14
+ end
15
+
16
+ attr_reader :lineno, :column
17
+
18
+ def <=>(other)
19
+ cmp = @lineno <=> other.lineno
20
+ cmp == 0 ? @column <=> other.column : cmp
21
+ end
22
+
23
+ include Comparable
24
+
25
+ def ==(other)
26
+ @lineno == other.lineno && @column == other.column
27
+ end
28
+
29
+ alias eql? ==
30
+
31
+ def hash
32
+ [@lineno, @column].hash
33
+ end
34
+
35
+ def to_s
36
+ "(%d,%d)" % [@lineno, @column]
37
+ end
38
+
39
+ alias inspect to_s
40
+
41
+ def left
42
+ raise if @column == 0
43
+ CodePosition.new(@lineno, @column - 1)
44
+ end
45
+
46
+ def right
47
+ CodePosition.new(@lineno, @column + 1)
48
+ end
49
+ end
50
+
51
+ class CodeRange
52
+ def initialize(first, last)
53
+ @first = first
54
+ @last = last
55
+ raise unless first
56
+ end
57
+
58
+ def self.from_node(node, encoding = Encoding::UTF_16LE)
59
+ node = node.location if node.is_a?(Prism::Node)
60
+ if node.is_a?(Prism::Location)
61
+ pos1 = CodePosition.new(node.start_line, node.start_code_units_column(encoding))
62
+ pos2 = CodePosition.new(node.end_line, node.end_code_units_column(encoding))
63
+ elsif node.respond_to?(:location)
64
+ loc = node.location
65
+ row, col = loc.start_loc
66
+ pos1 = CodePosition.new(row, col) # TODO: use SPLAT
67
+ row, col = loc.end_loc
68
+ pos2 = CodePosition.new(row, col)
69
+ else
70
+ p node.class.ancestors
71
+ raise "unknown type: #{ node.class }"
72
+ end
73
+ new(pos1, pos2)
74
+ end
75
+
76
+ def self.[](a, b, c, d)
77
+ pos1 = CodePosition.new(a, b)
78
+ pos2 = CodePosition.new(c, d)
79
+ new(pos1, pos2)
80
+ end
81
+
82
+ def to_lsp
83
+ { start: @first.to_lsp, end: @last.to_lsp }
84
+ end
85
+
86
+ attr_reader :first, :last
87
+
88
+ def include?(pos)
89
+ @first <= pos && pos < @last
90
+ end
91
+
92
+ def ==(other)
93
+ @first == other.first && @last == other.last
94
+ end
95
+
96
+ alias eql? ==
97
+
98
+ def hash
99
+ [@first, @last].hash
100
+ end
101
+
102
+ def to_s
103
+ "%p-%p" % [@first, @last]
104
+ end
105
+
106
+ alias inspect to_s
107
+
108
+ def ==(other)
109
+ @first == other.first && @last == other.last
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,263 @@
1
+ module TypeProf::Core
2
+ class AST
3
+ class Node
4
+ def initialize(raw_node, lenv)
5
+ @raw_node = raw_node
6
+ @lenv = lenv
7
+ @prev_node = nil
8
+ @static_ret = nil
9
+ @ret = nil
10
+
11
+ @changes = ChangeSet.new(self, nil)
12
+ end
13
+
14
+ attr_reader :lenv
15
+ attr_reader :prev_node
16
+ attr_reader :static_ret
17
+ attr_reader :ret
18
+ attr_reader :changes
19
+
20
+ def subnodes = {}
21
+ def attrs = {}
22
+
23
+ #: { (TypeProf::Core::AST::Node) -> void } -> nil
24
+ def each_subnode
25
+ queue = subnodes.values
26
+
27
+ until queue.empty?
28
+ subnode = queue.shift
29
+ next unless subnode
30
+
31
+ case subnode
32
+ when AST::Node
33
+ yield subnode
34
+ when Array
35
+ queue.unshift(*subnode)
36
+ when Hash
37
+ queue.unshift(*subnode.values)
38
+ else
39
+ raise subnode.class.to_s
40
+ end
41
+ end
42
+ end
43
+
44
+ def traverse(&blk)
45
+ yield :enter, self
46
+ each_subnode do |subnode|
47
+ subnode.traverse(&blk)
48
+ end
49
+ yield :leave, self
50
+ end
51
+
52
+ def code_range
53
+ if @raw_node
54
+ TypeProf::CodeRange.from_node(@raw_node)
55
+ else
56
+ pp self
57
+ raise
58
+ end
59
+ end
60
+
61
+ def define(genv)
62
+ @static_ret = define0(genv)
63
+ end
64
+
65
+ def define_copy(genv)
66
+ @lenv = @prev_node.lenv
67
+ each_subnode do |subnode|
68
+ subnode.define_copy(genv)
69
+ end
70
+ @prev_node.instance_variable_set(:@reused, true)
71
+ @static_ret = @prev_node.static_ret
72
+ end
73
+
74
+ def define0(genv)
75
+ each_subnode do |subnode|
76
+ subnode.define(genv)
77
+ end
78
+ return nil
79
+ end
80
+
81
+ def undefine(genv)
82
+ unless @reused
83
+ undefine0(genv)
84
+ end
85
+ end
86
+
87
+ def undefine0(genv)
88
+ each_subnode do |subnode|
89
+ subnode.undefine(genv)
90
+ end
91
+ end
92
+
93
+ def install(genv)
94
+ @ret = install0(genv)
95
+ @changes.reinstall(genv)
96
+ @ret
97
+ end
98
+
99
+ def install_copy(genv)
100
+ @changes.copy_from(@prev_node.changes)
101
+ @changes.reuse(self)
102
+ each_subnode do |subnode|
103
+ subnode.install_copy(genv)
104
+ end
105
+ @ret = @prev_node.ret
106
+ end
107
+
108
+ def install0(_)
109
+ raise "should override"
110
+ end
111
+
112
+ def uninstall(genv)
113
+ @changes.reinstall(genv)
114
+ each_subnode do |subnode|
115
+ subnode.uninstall(genv)
116
+ end
117
+ end
118
+
119
+ def diff(prev_node)
120
+ if prev_node.is_a?(self.class) && attrs.all? {|key, attr| attr == prev_node.send(key) }
121
+ raise unless prev_node # annotation
122
+ s1 = subnodes
123
+ s2 = prev_node.subnodes
124
+ return if s1.keys != s2.keys
125
+ s1.each do |key, subnode|
126
+ prev_subnode = s2[key]
127
+ if subnode && prev_subnode
128
+ subnode = [subnode] if subnode.is_a?(AST::Node)
129
+ prev_subnode = [prev_subnode] if prev_subnode.is_a?(AST::Node)
130
+ subnode.zip(prev_subnode) do |subnode0, prev_subnode0|
131
+ next if subnode0 == nil && prev_subnode0 == nil
132
+ subnode0.diff(prev_subnode0)
133
+ return unless subnode0.prev_node
134
+ end
135
+ else
136
+ return if subnode != prev_subnode
137
+ end
138
+ end
139
+ @prev_node = prev_node
140
+ end
141
+ end
142
+
143
+ def retrieve_at(pos, &blk)
144
+ if code_range.include?(pos)
145
+ each_subnode do |subnode|
146
+ subnode.retrieve_at(pos, &blk)
147
+ end
148
+ yield self
149
+ end
150
+ end
151
+
152
+ def boxes(key)
153
+ @changes.boxes.each do |(k, *), box|
154
+ # TODO: make it recursive
155
+ box.changes.boxes.each do |(k, *), box|
156
+ yield box if k == key
157
+ end
158
+ yield box if k == key
159
+ end
160
+ end
161
+
162
+ def diagnostics(genv, &blk)
163
+ @changes.diagnostics.each(&blk)
164
+ @changes.boxes.each_value do |box|
165
+ box.diagnostics(genv, &blk)
166
+ end
167
+ each_subnode do |subnode|
168
+ subnode.diagnostics(genv, &blk)
169
+ end
170
+ end
171
+
172
+ def get_vertexes(vtxs)
173
+ return if @reused
174
+ @changes.boxes.each_value do |box|
175
+ vtxs << box.ret
176
+ end
177
+ vtxs << @ret
178
+ each_subnode do |subnode|
179
+ subnode.get_vertexes(vtxs)
180
+ end
181
+ end
182
+
183
+ def modified_vars(tbl, vars)
184
+ each_subnode do |subnode|
185
+ subnode.modified_vars(tbl, vars)
186
+ end
187
+ end
188
+
189
+ def pretty_print_instance_variables
190
+ super() - [:@raw_node, :@lenv, :@prev_node, :@static_ret, :@changes]
191
+ end
192
+ end
193
+
194
+ class ProgramNode < Node
195
+ def initialize(raw_node, lenv)
196
+ super(raw_node, lenv)
197
+
198
+ @tbl = raw_node.locals
199
+ raw_body = raw_node.statements
200
+
201
+ @body = AST.create_node(raw_body, lenv, false)
202
+ end
203
+
204
+ attr_reader :tbl, :body
205
+
206
+ def subnodes = { body: }
207
+ def attrs = { tbl: }
208
+
209
+ def install0(genv)
210
+ @tbl.each {|var| @lenv.locals[var] = Source.new(genv.nil_type) }
211
+ @lenv.locals[:"*self"] = lenv.cref.get_self(genv)
212
+
213
+ # for toplevel return
214
+ @body.lenv.locals[:"*expected_method_ret"] = Vertex.new(self)
215
+ @body.install(genv)
216
+ end
217
+ end
218
+
219
+ class DummyNilNode < Node
220
+ def initialize(code_range, lenv)
221
+ @code_range = code_range
222
+ super(nil, lenv)
223
+ end
224
+
225
+ def code_range
226
+ @code_range
227
+ end
228
+
229
+ def install0(genv)
230
+ Source.new(genv.nil_type)
231
+ end
232
+ end
233
+
234
+ class DummyRHSNode < Node
235
+ def initialize(code_range, lenv)
236
+ @code_range = code_range
237
+ super(nil, lenv)
238
+ end
239
+
240
+ def code_range
241
+ @code_range
242
+ end
243
+
244
+ def install0(_)
245
+ Vertex.new(self)
246
+ end
247
+ end
248
+
249
+ class DummySymbolNode
250
+ def initialize(sym, code_range, ret)
251
+ @sym = sym
252
+ @code_range = code_range
253
+ @ret = ret
254
+ end
255
+
256
+ attr_reader :lenv, :prev_node, :ret
257
+
258
+ def boxes(_)
259
+ []
260
+ end
261
+ end
262
+ end
263
+ end
@@ -0,0 +1,259 @@
1
+ module TypeProf::Core
2
+ class AST
3
+ class CallBaseNode < Node
4
+ def initialize(raw_node, recv, mid, mid_code_range, raw_args, last_arg, raw_block, lenv)
5
+ super(raw_node, lenv)
6
+
7
+ @recv = recv
8
+ @mid = mid
9
+ @mid_code_range = mid_code_range
10
+
11
+ # args
12
+ @positional_args = []
13
+ @splat_flags = []
14
+ @keyword_args = nil
15
+
16
+ @block_pass = nil
17
+ @block_tbl = nil
18
+ @block_f_args = nil
19
+ @block_body = nil
20
+
21
+ if raw_args
22
+ args = []
23
+ @splat_flags = []
24
+ raw_args.arguments.each do |raw_arg|
25
+ if raw_arg.is_a?(Prism::SplatNode)
26
+ args << raw_arg.expression
27
+ @splat_flags << true
28
+ else
29
+ args << raw_arg
30
+ @splat_flags << false
31
+ end
32
+ end
33
+ @positional_args = args.map {|arg| AST.create_node(arg, lenv) }
34
+
35
+ if @positional_args.last.is_a?(TypeProf::Core::AST::HashNode) && @positional_args.last.keywords
36
+ @keyword_args = @positional_args.pop
37
+ end
38
+ end
39
+
40
+ @positional_args << last_arg if last_arg
41
+
42
+ if raw_block
43
+ if raw_block.type == :block_argument_node
44
+ @block_pass = AST.create_node(raw_block.expression, lenv)
45
+ else
46
+ @block_pass = nil
47
+ @block_tbl = raw_block.locals
48
+ # TODO: optional args, etc.
49
+ @block_f_args = case raw_block.parameters
50
+ when Prism::BlockParametersNode
51
+ raw_block.parameters.parameters.requireds.map {|n| n.is_a?(Prism::MultiTargetNode) ? nil : n.name }
52
+ when Prism::NumberedParametersNode
53
+ 1.upto(raw_block.parameters.maximum).map { |n| :"_#{n}" }
54
+ when nil
55
+ []
56
+ else
57
+ raise "not supported yet: #{ raw_block.parameters.class }"
58
+ end
59
+ ncref = CRef.new(lenv.cref.cpath, :instance, @mid, lenv.cref)
60
+ nlenv = LocalEnv.new(@lenv.path, ncref, {}, @lenv.return_boxes)
61
+ @block_body = raw_block.body ? AST.create_node(raw_block.body, nlenv) : DummyNilNode.new(code_range, lenv)
62
+ end
63
+ end
64
+
65
+ @yield = raw_node.type == :yield_node
66
+ end
67
+
68
+ attr_reader :recv, :mid, :mid_code_range, :yield
69
+ attr_reader :positional_args, :splat_flags, :keyword_args
70
+ attr_reader :block_tbl, :block_f_args, :block_body, :block_pass
71
+
72
+ def subnodes = { recv:, positional_args:, keyword_args:, block_body:, block_pass: }
73
+ def attrs = { mid:, splat_flags:, block_tbl:, block_f_args:, yield: }
74
+
75
+ def install0(genv)
76
+ recv = @recv ? @recv.install(genv) : @yield ? @lenv.get_var(:"*given_block") : @lenv.get_var(:"*self")
77
+
78
+ positional_args = @positional_args.map do |arg|
79
+ arg.install(genv)
80
+ end
81
+
82
+ keyword_args = @keyword_args ? @keyword_args.install(genv) : nil
83
+
84
+ if @block_body
85
+ @lenv.locals.each {|var, vtx| @block_body.lenv.locals[var] = vtx }
86
+ @block_tbl.each {|var| @block_body.lenv.locals[var] = Source.new(genv.nil_type) }
87
+ @block_body.lenv.locals[:"*self"] = @block_body.lenv.cref.get_self(genv)
88
+
89
+ blk_f_args = []
90
+ if @block_f_args
91
+ @block_f_args.each do |arg|
92
+ blk_f_args << @block_body.lenv.new_var(arg, self)
93
+ end
94
+ end
95
+
96
+ @lenv.locals.each do |var, vtx|
97
+ @block_body.lenv.set_var(var, vtx)
98
+ end
99
+ vars = []
100
+ @block_body.modified_vars(@lenv.locals.keys - @block_tbl, vars)
101
+ vars.uniq!
102
+ vars.each do |var|
103
+ vtx = @lenv.get_var(var)
104
+ nvtx = vtx.new_vertex(genv, self)
105
+ @lenv.set_var(var, nvtx)
106
+ @block_body.lenv.set_var(var, nvtx)
107
+ end
108
+
109
+ e_ret = @block_body.lenv.locals[:"*expected_block_ret"] = Vertex.new(self)
110
+ @block_body.install(genv)
111
+ @block_body.lenv.add_next_box(@changes.add_escape_box(genv, @block_body.ret, e_ret))
112
+
113
+ vars.each do |var|
114
+ @changes.add_edge(genv, @block_body.lenv.get_var(var), @lenv.get_var(var))
115
+ end
116
+
117
+ blk_f_ary_arg = Vertex.new(self)
118
+ @changes.add_masgn_box(genv, blk_f_ary_arg, blk_f_args, nil, nil) # TODO: support splat "do |a, *b, c|"
119
+ block = Block.new(self, blk_f_ary_arg, blk_f_args, @block_body.lenv.next_boxes)
120
+ blk_ty = Source.new(Type::Proc.new(genv, block))
121
+ elsif @block_pass
122
+ blk_ty = @block_pass.install(genv)
123
+ end
124
+
125
+ a_args = ActualArguments.new(positional_args, @splat_flags, keyword_args, blk_ty)
126
+ box = @changes.add_method_call_box(genv, recv, @mid, a_args, !@recv)
127
+
128
+ if @block_body && @block_body.lenv.break_vtx
129
+ ret = Vertex.new(self)
130
+ @changes.add_edge(genv, box.ret, ret)
131
+ @changes.add_edge(genv, @block_body.lenv.break_vtx, ret)
132
+ ret
133
+ else
134
+ box.ret
135
+ end
136
+ end
137
+
138
+ def block_last_stmt_code_range
139
+ if @block_body
140
+ if @block_body.is_a?(AST::StatementsNode)
141
+ @block_body.stmts.last.code_range
142
+ else
143
+ @block_body.code_range
144
+ end
145
+ else
146
+ nil
147
+ end
148
+ end
149
+
150
+ def retrieve_at(pos, &blk)
151
+ yield self if @mid_code_range && @mid_code_range.include?(pos)
152
+ each_subnode do |subnode|
153
+ next unless subnode
154
+ subnode.retrieve_at(pos, &blk)
155
+ end
156
+ end
157
+
158
+ def modified_vars(tbl, vars)
159
+ subnodes.each do |key, subnode|
160
+ next unless subnode
161
+ if key == :block_body
162
+ subnode.modified_vars(tbl - self.block_tbl, vars)
163
+ elsif subnode.is_a?(AST::Node)
164
+ subnode.modified_vars(tbl, vars)
165
+ else
166
+ subnode.each {|n| n.modified_vars(tbl, vars) }
167
+ end
168
+ end
169
+ end
170
+ end
171
+
172
+ class CallNode < CallBaseNode
173
+ def initialize(raw_node, lenv)
174
+ recv = raw_node.receiver ? AST.create_node(raw_node.receiver, lenv) : nil
175
+ mid = raw_node.name
176
+ mid_code_range = TypeProf::CodeRange.from_node(raw_node.message_loc) if raw_node.message_loc
177
+ raw_args = raw_node.arguments
178
+ raw_block = raw_node.block
179
+ super(raw_node, recv, mid, mid_code_range, raw_args, nil, raw_block, lenv)
180
+ end
181
+ end
182
+
183
+ class SuperNode < CallBaseNode
184
+ def initialize(raw_node, lenv)
185
+ raw_args = raw_node.arguments
186
+ raw_block = raw_node.block
187
+ super(raw_node, nil, :"*super", nil, raw_args, nil, raw_block, lenv)
188
+ end
189
+ end
190
+
191
+ class ForwardingSuperNode < CallBaseNode
192
+ def initialize(raw_node, lenv)
193
+ raw_args = nil # TODO: forward args properly
194
+ raw_block = raw_node.block
195
+ super(raw_node, nil, :"*super", nil, raw_args, nil, raw_block, lenv)
196
+ end
197
+ end
198
+
199
+ class YieldNode < CallBaseNode
200
+ def initialize(raw_node, lenv)
201
+ raw_args = raw_node.arguments
202
+ super(raw_node, nil, :call, nil, raw_args, nil, nil, lenv)
203
+ end
204
+ end
205
+
206
+ class OperatorNode < CallBaseNode
207
+ def initialize(raw_node, recv, lenv)
208
+ mid = raw_node.binary_operator
209
+ mid_code_range = TypeProf::CodeRange.from_node(raw_node.binary_operator_loc)
210
+ last_arg = AST.create_node(raw_node.value, lenv)
211
+ super(raw_node, recv, mid, mid_code_range, nil, last_arg, nil, lenv)
212
+ end
213
+ end
214
+
215
+ class IndexReadNode < CallBaseNode
216
+ def initialize(raw_node, lenv)
217
+ recv = AST.create_node(raw_node.receiver, lenv)
218
+ mid = :[]
219
+ mid_code_range = nil
220
+ raw_args = raw_node.arguments
221
+ super(raw_node, recv, mid, mid_code_range, raw_args, nil, nil, lenv)
222
+ end
223
+ end
224
+
225
+ class IndexWriteNode < CallBaseNode
226
+ def initialize(raw_node, rhs, lenv)
227
+ recv = AST.create_node(raw_node.receiver, lenv)
228
+ mid = :[]=
229
+ mid_code_range = nil
230
+ raw_args = raw_node.arguments
231
+ @rhs = rhs
232
+ super(raw_node, recv, mid, mid_code_range, raw_args, rhs, nil, lenv)
233
+ end
234
+
235
+ attr_reader :rhs
236
+ end
237
+
238
+ class CallReadNode < CallBaseNode
239
+ def initialize(raw_node, lenv)
240
+ recv = AST.create_node(raw_node.receiver, lenv)
241
+ mid = raw_node.read_name
242
+ mid_code_range = TypeProf::CodeRange.from_node(raw_node.message_loc)
243
+ super(raw_node, recv, mid, mid_code_range, nil, nil, nil, lenv)
244
+ end
245
+ end
246
+
247
+ class CallWriteNode < CallBaseNode
248
+ def initialize(raw_node, rhs, lenv)
249
+ recv = AST.create_node(raw_node.receiver, lenv)
250
+ mid = raw_node.is_a?(Prism::CallTargetNode) ? raw_node.name : raw_node.write_name
251
+ mid_code_range = TypeProf::CodeRange.from_node(raw_node.message_loc)
252
+ @rhs = rhs
253
+ super(raw_node, recv, mid, mid_code_range, nil, rhs, nil, lenv)
254
+ end
255
+
256
+ attr_reader :rhs
257
+ end
258
+ end
259
+ end