typeprof 0.21.11 → 0.30.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) 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 +180 -0
  7. data/lib/typeprof/cli.rb +2 -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 +251 -0
  11. data/lib/typeprof/core/ast/const.rb +126 -0
  12. data/lib/typeprof/core/ast/control.rb +432 -0
  13. data/lib/typeprof/core/ast/meta.rb +150 -0
  14. data/lib/typeprof/core/ast/method.rb +335 -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 +360 -0
  31. data/lib/typeprof/core/graph/box.rb +991 -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 +222 -0
  35. data/lib/typeprof/core/graph.rb +3 -0
  36. data/lib/typeprof/core/service.rb +522 -0
  37. data/lib/typeprof/core/type.rb +348 -0
  38. data/lib/typeprof/core/util.rb +81 -0
  39. data/lib/typeprof/core.rb +32 -0
  40. data/lib/typeprof/diagnostic.rb +35 -0
  41. data/lib/typeprof/lsp/messages.rb +430 -0
  42. data/lib/typeprof/lsp/server.rb +177 -0
  43. data/lib/typeprof/lsp/text.rb +69 -0
  44. data/lib/typeprof/lsp/util.rb +61 -0
  45. data/lib/typeprof/lsp.rb +4 -907
  46. data/lib/typeprof/version.rb +1 -1
  47. data/lib/typeprof.rb +4 -18
  48. data/typeprof.gemspec +5 -7
  49. metadata +48 -35
  50. data/.github/dependabot.yml +0 -6
  51. data/.github/workflows/main.yml +0 -39
  52. data/.gitignore +0 -9
  53. data/Gemfile +0 -17
  54. data/Gemfile.lock +0 -41
  55. data/Rakefile +0 -10
  56. data/exe/typeprof +0 -10
  57. data/lib/typeprof/analyzer.rb +0 -2598
  58. data/lib/typeprof/arguments.rb +0 -414
  59. data/lib/typeprof/block.rb +0 -176
  60. data/lib/typeprof/builtin.rb +0 -893
  61. data/lib/typeprof/code-range.rb +0 -177
  62. data/lib/typeprof/config.rb +0 -158
  63. data/lib/typeprof/container-type.rb +0 -912
  64. data/lib/typeprof/export.rb +0 -589
  65. data/lib/typeprof/import.rb +0 -852
  66. data/lib/typeprof/insns-def.rb +0 -65
  67. data/lib/typeprof/iseq.rb +0 -864
  68. data/lib/typeprof/method.rb +0 -355
  69. data/lib/typeprof/type.rb +0 -1140
  70. data/lib/typeprof/utils.rb +0 -212
  71. data/tools/coverage.rb +0 -14
  72. data/tools/setup-insns-def.rb +0 -30
  73. data/typeprof-lsp +0 -3
@@ -0,0 +1,335 @@
1
+ module TypeProf::Core
2
+ class AST
3
+ def self.get_rbs_comment_before(raw_node, lenv)
4
+ comments = Fiber[:comments]
5
+ i = comments.bsearch_index {|comment| comment.location.start_line >= raw_node.location.start_line } || comments.size
6
+ lineno = raw_node.location.start_line
7
+ rbs_comments = []
8
+ while i > 0
9
+ i -= 1
10
+ lineno -= 1
11
+ comment = comments[i]
12
+ comment_loc = comment.location
13
+ comment_text = comment_loc.slice
14
+ if comment_loc.start_line == lineno && comment_text.start_with?("#:")
15
+ rbs_comments[comment_loc.start_line] = " " * (comment_loc.start_column + 2) + comment_text[2..]
16
+ else
17
+ break
18
+ end
19
+ end
20
+ return nil if rbs_comments.empty?
21
+ rbs_comments = rbs_comments.map {|line| line || "" }.join("\n")
22
+ method_type = RBS::Parser.parse_method_type(rbs_comments)
23
+ if method_type
24
+ AST.create_rbs_func_type(method_type, method_type.type_params, method_type.block, lenv)
25
+ else
26
+ nil
27
+ end
28
+ rescue RBS::ParsingError
29
+ # TODO: report the error
30
+ nil
31
+ end
32
+
33
+ def self.parse_params(tbl, raw_args, lenv)
34
+ unless raw_args
35
+ return {
36
+ req_positionals: [],
37
+ opt_positionals: [],
38
+ opt_positional_defaults: [],
39
+ rest_positionals: nil,
40
+ post_positionals: [],
41
+ req_keywords: [],
42
+ opt_keywords: [],
43
+ opt_keyword_defaults: [],
44
+ rest_keywords: nil,
45
+ block: nil,
46
+ }
47
+ end
48
+
49
+ args_code_ranges = []
50
+ req_positionals = []
51
+ raw_args.requireds.each do |n|
52
+ args_code_ranges << TypeProf::CodeRange.from_node(n.location)
53
+ req_positionals << (n.is_a?(Prism::MultiTargetNode) ? nil : n.name)
54
+ end
55
+
56
+ # pre_init = args[1]
57
+
58
+ opt_positionals = []
59
+ opt_positional_defaults = []
60
+ raw_args.optionals.each do |n|
61
+ opt_positionals << n.name
62
+ opt_positional_defaults << AST.create_node(n.value, lenv)
63
+ end
64
+
65
+ post_positionals = raw_args.posts.map {|n| (n.is_a?(Prism::MultiTargetNode) ? nil : n.name) }
66
+
67
+ rest_positionals = raw_args.rest&.name
68
+
69
+ req_keywords = []
70
+ opt_keywords = []
71
+ opt_keyword_defaults = []
72
+
73
+ raw_args.keywords.each do |kw|
74
+ case kw.type
75
+ when :required_keyword_parameter_node
76
+ req_keywords << kw.name
77
+ when :optional_keyword_parameter_node
78
+ opt_keywords << kw.name
79
+ opt_keyword_defaults << AST.create_node(kw.value, lenv)
80
+ end
81
+ end
82
+
83
+ case raw_args.keyword_rest
84
+ when Prism::KeywordRestParameterNode
85
+ rest_keywords = raw_args.keyword_rest.name if raw_args.keyword_rest
86
+ when Prism::NoKeywordsParameterNode
87
+ # what to do?
88
+ when nil
89
+ # nothing to do
90
+ else
91
+ raise "unexpected keyword rest: #{ raw_args.keyword_rest.class }"
92
+ end
93
+
94
+ block = raw_args.block.name if raw_args.block
95
+
96
+ {
97
+ req_positionals:,
98
+ opt_positionals:,
99
+ opt_positional_defaults:,
100
+ rest_positionals:,
101
+ post_positionals:,
102
+ req_keywords:,
103
+ opt_keywords:,
104
+ opt_keyword_defaults:,
105
+ rest_keywords:,
106
+ block:,
107
+ args_code_ranges:
108
+ }
109
+ end
110
+
111
+ class DefNode < Node
112
+ def initialize(raw_node, lenv, use_result)
113
+ super(raw_node, lenv)
114
+ # TODO: warn "def self.foo" in a metaclass
115
+ singleton = !!raw_node.receiver || lenv.cref.scope_level == :metaclass
116
+ mid = raw_node.name
117
+ mid_code_range = TypeProf::CodeRange.from_node(raw_node.name_loc)
118
+ @tbl = raw_node.locals
119
+ raw_args = raw_node.parameters
120
+ raw_body = raw_node.body
121
+
122
+ @rbs_method_type = AST.get_rbs_comment_before(raw_node, lenv)
123
+
124
+ @singleton = singleton
125
+ @mid = mid
126
+ @mid_code_range = mid_code_range
127
+
128
+ ncref = CRef.new(lenv.cref.cpath, @singleton ? :class : :instance, @mid, lenv.cref)
129
+ nlenv = LocalEnv.new(@lenv.path, ncref, {}, [])
130
+ if raw_body
131
+ @body = AST.create_node(raw_body, nlenv)
132
+ else
133
+ pos = code_range.last.left.left.left # before "end"
134
+ cr = TypeProf::CodeRange.new(pos, pos)
135
+ @body = DummyNilNode.new(cr, nlenv)
136
+ end
137
+
138
+ h = AST.parse_params(@tbl, raw_args, nlenv)
139
+ @req_positionals = h[:req_positionals]
140
+ @opt_positionals = h[:opt_positionals]
141
+ @opt_positional_defaults = h[:opt_positional_defaults]
142
+ @rest_positionals = h[:rest_positionals]
143
+ @post_positionals = h[:post_positionals]
144
+ @req_keywords = h[:req_keywords]
145
+ @opt_keywords = h[:opt_keywords]
146
+ @opt_keyword_defaults = h[:opt_keyword_defaults]
147
+ @rest_keywords = h[:rest_keywords]
148
+ @block = h[:block]
149
+ @args_code_ranges = h[:args_code_ranges] || []
150
+
151
+ # If the result of `def` statement, stop reusing this node
152
+ # TODO: `private def ...` should be handled well
153
+ @reusable = !use_result
154
+ end
155
+
156
+ attr_reader :singleton, :mid, :mid_code_range
157
+ attr_reader :tbl
158
+ attr_reader :req_positionals
159
+ attr_reader :opt_positionals
160
+ attr_reader :opt_positional_defaults
161
+ attr_reader :rest_positionals
162
+ attr_reader :post_positionals
163
+ attr_reader :req_keywords
164
+ attr_reader :opt_keywords
165
+ attr_reader :opt_keyword_defaults
166
+ attr_reader :rest_keywords
167
+ attr_reader :block
168
+ attr_reader :body
169
+ attr_reader :rbs_method_type
170
+ attr_reader :reusable
171
+
172
+ def subnodes = {
173
+ body:,
174
+ opt_positional_defaults:,
175
+ opt_keyword_defaults:,
176
+ rbs_method_type:,
177
+ }
178
+ def attrs = {
179
+ singleton:,
180
+ mid:,
181
+ mid_code_range:,
182
+ tbl:,
183
+ req_positionals:,
184
+ opt_positionals:,
185
+ rest_positionals:,
186
+ post_positionals:,
187
+ req_keywords:,
188
+ opt_keywords:,
189
+ rest_keywords:,
190
+ block:,
191
+ reusable:,
192
+ }
193
+
194
+ def mname_code_range(_name) = @mid_code_range
195
+
196
+ def define(genv) # NOT define0
197
+ return define_copy(genv) if @prev_node && @reusable
198
+ super(genv)
199
+ end
200
+
201
+ def install(genv) # NOT install0
202
+ return install_copy(genv) if @prev_node && @reusable
203
+ super(genv)
204
+ end
205
+
206
+ def install0(genv)
207
+ if @rbs_method_type
208
+ @changes.add_method_decl_box(genv, @lenv.cref.cpath, @singleton, @mid, [@rbs_method_type], false)
209
+ end
210
+
211
+ @tbl.each {|var| @body.lenv.locals[var] = Source.new(genv.nil_type) }
212
+ @body.lenv.locals[:"*self"] = @body.lenv.cref.get_self(genv)
213
+
214
+ req_positionals = @req_positionals.map {|var| @body.lenv.new_var(var, self) }
215
+ opt_positionals = @opt_positionals.map {|var| @body.lenv.new_var(var, self) }
216
+ rest_positionals = @rest_positionals ? @body.lenv.new_var(@rest_positionals, self) : nil
217
+ post_positionals = @post_positionals.map {|var| @body.lenv.new_var(var, self) }
218
+ req_keywords = @req_keywords.map {|var| @body.lenv.new_var(var, self) }
219
+ opt_keywords = @opt_keywords.map {|var| @body.lenv.new_var(var, self) }
220
+ rest_keywords = @rest_keywords ? @body.lenv.new_var(@rest_keywords, self) : nil
221
+ block = @block ? @body.lenv.new_var(@block, self) : nil
222
+
223
+ @opt_positional_defaults.zip(opt_positionals) do |expr, vtx|
224
+ @changes.add_edge(genv, expr.install(genv), vtx)
225
+ end
226
+ @opt_keyword_defaults.zip(opt_keywords) do |expr, vtx|
227
+ @changes.add_edge(genv, expr.install(genv), vtx)
228
+ end
229
+
230
+ if block
231
+ block = @body.lenv.set_var(:"*given_block", block)
232
+ else
233
+ block = @body.lenv.new_var(:"*given_block", self)
234
+ end
235
+
236
+ if @body
237
+ e_ret = @body.lenv.locals[:"*expected_method_ret"] = Vertex.new(self)
238
+ @body.install(genv)
239
+ @body.lenv.add_return_box(@changes.add_escape_box(genv, @body.ret, e_ret))
240
+ end
241
+
242
+ f_args = FormalArguments.new(
243
+ req_positionals,
244
+ opt_positionals,
245
+ rest_positionals,
246
+ post_positionals,
247
+ req_keywords,
248
+ opt_keywords,
249
+ rest_keywords,
250
+ block,
251
+ )
252
+
253
+ @changes.add_method_def_box(genv, @lenv.cref.cpath, @singleton, @mid, f_args, @body.lenv.return_boxes)
254
+
255
+ Source.new(Type::Symbol.new(genv, @mid))
256
+ end
257
+
258
+ def last_stmt_code_range
259
+ if @body
260
+ if @body.is_a?(AST::StatementsNode)
261
+ @body.stmts.last.code_range
262
+ else
263
+ @body.code_range
264
+ end
265
+ else
266
+ nil
267
+ end
268
+ end
269
+
270
+ def retrieve_at(pos, &blk)
271
+ if @rbs_method_type
272
+ if @rbs_method_type.code_range.include?(pos) # annotation
273
+ @rbs_method_type.retrieve_at(pos, &blk)
274
+ end
275
+ end
276
+ @args_code_ranges.each_with_index do |cr, i|
277
+ if cr.include?(pos)
278
+ yield DummySymbolNode.new(@tbl[i], cr, @body.lenv.get_var(@tbl[i]))
279
+ break
280
+ end
281
+ end
282
+ super(pos, &blk)
283
+ end
284
+
285
+ def modified_vars(tbl, vars)
286
+ # skip
287
+ end
288
+ end
289
+
290
+ class AliasNode < Node
291
+ def initialize(raw_node, lenv)
292
+ super(raw_node, lenv)
293
+ @new_mid = AST.create_node(raw_node.new_name, lenv)
294
+ @old_mid = AST.create_node(raw_node.old_name, lenv)
295
+ end
296
+
297
+ attr_reader :new_mid, :old_mid
298
+
299
+ def subnodes = { new_mid:, old_mid: }
300
+
301
+ def install0(genv)
302
+ @new_mid.install(genv)
303
+ @old_mid.install(genv)
304
+ if @new_mid.is_a?(SymbolNode) && @old_mid.is_a?(SymbolNode)
305
+ new_mid = @new_mid.lit
306
+ old_mid = @old_mid.lit
307
+ box = @changes.add_method_alias_box(genv, @lenv.cref.cpath, false, new_mid, old_mid)
308
+ box.ret
309
+ else
310
+ Source.new(genv.nil_type)
311
+ end
312
+ end
313
+ end
314
+
315
+ class UndefNode < Node
316
+ def initialize(raw_node, lenv)
317
+ super(raw_node, lenv)
318
+ @names = raw_node.names.map do |raw_name|
319
+ AST.create_node(raw_name, lenv)
320
+ end
321
+ end
322
+
323
+ attr_reader :names
324
+
325
+ def subnodes = { names: }
326
+
327
+ def install0(genv)
328
+ @names.each do |name|
329
+ name.install(genv)
330
+ end
331
+ Source.new(genv.nil_type)
332
+ end
333
+ end
334
+ end
335
+ end
@@ -0,0 +1,263 @@
1
+ module TypeProf::Core
2
+ class AST
3
+ class StatementsNode < Node
4
+ def initialize(raw_node, lenv, use_result)
5
+ super(raw_node, lenv)
6
+ stmts = raw_node.body
7
+ @stmts = stmts.map.with_index do |n, i|
8
+ if n
9
+ AST.create_node(n, lenv, i == stmts.length - 1 ? use_result : false)
10
+ else
11
+ last = code_range.last
12
+ DummyNilNode.new(TypeProf::CodeRange.new(last, last), lenv)
13
+ end
14
+ end
15
+ end
16
+
17
+ attr_reader :stmts
18
+
19
+ def subnodes = { stmts: }
20
+
21
+ def install0(genv)
22
+ ret = nil
23
+ @stmts.each do |stmt|
24
+ ret = stmt ? stmt.install(genv) : nil
25
+ end
26
+ if ret
27
+ ret2 = Vertex.new(self)
28
+ @changes.add_edge(genv, ret, ret2)
29
+ ret2
30
+ else
31
+ Source.new(genv.nil_type)
32
+ end
33
+ end
34
+
35
+ def diff(prev_node)
36
+ if prev_node.is_a?(StatementsNode)
37
+ i = 0
38
+ while i < @stmts.size
39
+ @stmts[i].diff(prev_node.stmts[i])
40
+ if !@stmts[i].prev_node
41
+ j1 = @stmts.size - 1
42
+ j2 = prev_node.stmts.size - 1
43
+ while j1 >= i && j2 >= i
44
+ @stmts[j1].diff(prev_node.stmts[j2])
45
+ if !@stmts[j1].prev_node
46
+ return
47
+ end
48
+ j1 -= 1
49
+ j2 -= 1
50
+ end
51
+ return
52
+ end
53
+ i += 1
54
+ end
55
+ @prev_node = prev_node if i == prev_node.stmts.size
56
+ end
57
+ end
58
+ end
59
+
60
+ class MultiWriteNode < Node
61
+ def initialize(raw_node, lenv)
62
+ super(raw_node, lenv)
63
+ @value = AST.create_node(raw_node.value, lenv)
64
+ @lefts = raw_node.lefts.map do |raw_lhs|
65
+ AST.create_target_node(raw_lhs, lenv)
66
+ end
67
+ if raw_node.rest
68
+ # TODO: need more complex case handling
69
+ @rest_exist = true
70
+ case raw_node.rest.type
71
+ when :splat_node
72
+ if raw_node.rest.expression
73
+ @rest = AST.create_target_node(raw_node.rest.expression, lenv)
74
+ end
75
+ when :implicit_rest_node
76
+ else
77
+ raise "unexpected rest node: #{raw_node.rest.type}"
78
+ end
79
+ end
80
+ @rights = raw_node.rights.map do |raw_lhs|
81
+ AST.create_target_node(raw_lhs, lenv)
82
+ end
83
+ # TODO: raw_node.rest, raw_node.rights
84
+ end
85
+
86
+ attr_reader :value, :lefts, :rest, :rest_exist, :rights
87
+
88
+ def subnodes = { value:, lefts:, rest:, rights: }
89
+ def attrs = { rest_exist: }
90
+
91
+ def install0(genv)
92
+ value = @value.install(genv)
93
+
94
+ @lefts.each {|lhs| lhs.install(genv) }
95
+ @lefts.each {|lhs| lhs.rhs.ret || raise(lhs.rhs.inspect) }
96
+ lefts = @lefts.map {|lhs| lhs.rhs.ret }
97
+
98
+ if @rest_exist
99
+ rest_elem = Vertex.new(self)
100
+ if @rest
101
+ @rest.install(genv)
102
+ @rest.rhs.ret || raise(@rest.rhs.inspect)
103
+ @changes.add_edge(genv, Source.new(Type::Instance.new(genv, genv.mod_ary, [rest_elem])), @rest.rhs.ret)
104
+ end
105
+ end
106
+
107
+ if @rights
108
+ @rights.each {|lhs| lhs.install(genv) }
109
+ @rights.each {|lhs| lhs.rhs.ret || raise(lhs.rhs.inspect) }
110
+ rights = @rights.map {|rhs| rhs.ret }
111
+ end
112
+
113
+ box = @changes.add_masgn_box(genv, value, lefts, rest_elem, rights)
114
+ box.ret
115
+ end
116
+
117
+ def retrieve_at(pos, &blk)
118
+ yield self if @var_code_range && @var_code_range.include?(pos)
119
+ super(pos, &blk)
120
+ end
121
+ end
122
+
123
+ class MatchWriteNode < Node
124
+ def initialize(raw_node, lenv)
125
+ super(raw_node, lenv)
126
+ @call = AST.create_node(raw_node.call, lenv)
127
+ @targets = raw_node.targets.map do |raw_lhs|
128
+ AST.create_target_node(raw_lhs, lenv)
129
+ end
130
+ end
131
+
132
+ attr_reader :call, :targets
133
+ def subnodes = { call:, targets: }
134
+
135
+ def install0(genv)
136
+ ret = @call.install(genv)
137
+ @targets.each do |target|
138
+ target.install(genv)
139
+ target.rhs.ret || raise(target.rhs.inspect)
140
+ @changes.add_edge(genv, Source.new(Type::Instance.new(genv, genv.mod_str, [])), target.rhs.ret)
141
+ end
142
+ ret
143
+ end
144
+ end
145
+
146
+ class DefinedNode < Node
147
+ def initialize(raw_node, lenv)
148
+ super(raw_node, lenv)
149
+ @arg = AST.create_node(raw_node.value, lenv)
150
+ end
151
+
152
+ attr_reader :arg
153
+
154
+ def subnodes = {} # no arg!
155
+
156
+ def install0(genv)
157
+ Source.new(genv.true_type, genv.false_type)
158
+ end
159
+ end
160
+
161
+ class SourceEncodingNode < Node
162
+ def install0(genv)
163
+ Source.new(Type::Instance.new(genv, genv.resolve_cpath([:Encoding]), []))
164
+ end
165
+ end
166
+
167
+ class SplatNode < Node
168
+ def initialize(raw_node, lenv)
169
+ super(raw_node, lenv)
170
+ @expr = AST.create_node(raw_node.expression, lenv)
171
+ end
172
+
173
+ attr_reader :expr
174
+
175
+ def subnodes = { expr: }
176
+
177
+ def mid_code_range = nil
178
+
179
+ def install0(genv)
180
+ vtx = @expr.install(genv)
181
+
182
+ a_args = ActualArguments.new([], [], nil, nil)
183
+ vtx = @changes.add_method_call_box(genv, vtx, :to_a, a_args, false).ret
184
+
185
+ @changes.add_splat_box(genv, vtx).ret
186
+ end
187
+ end
188
+
189
+ class ForNode < Node
190
+ def initialize(raw_node, lenv)
191
+ super(raw_node, lenv)
192
+ # XXX: tentative implementation
193
+ # raw_node.index
194
+ @expr = AST.create_node(raw_node.collection, lenv)
195
+ @body = raw_node.statements ? AST.create_node(raw_node.statements, lenv) : DummyNilNode.new(TypeProf::CodeRange.new(code_range.last, code_range.last), lenv)
196
+ end
197
+
198
+ attr_reader :expr, :body
199
+
200
+ def subnodes = { expr:, body: }
201
+
202
+ def install0(genv)
203
+ @expr.install(genv)
204
+ @body.install(genv)
205
+ Source.new(genv.nil_type)
206
+ end
207
+ end
208
+
209
+ class FlipFlopNode < Node
210
+ def initialize(raw_node, lenv)
211
+ super(raw_node, lenv)
212
+ @e1 = AST.create_node(raw_node.left, lenv)
213
+ @e2 = AST.create_node(raw_node.right, lenv)
214
+ end
215
+
216
+ attr_reader :e1, :e2
217
+
218
+ def subnodes = { e1:, e2: }
219
+
220
+ def install0(genv)
221
+ @e1.install(genv)
222
+ @e2.install(genv)
223
+ Source.new(genv.true_type, genv.false_type)
224
+ end
225
+ end
226
+
227
+ class MatchRequiredNode < Node
228
+ def initialize(raw_node, lenv)
229
+ super(raw_node, lenv)
230
+ @value = AST.create_node(raw_node.value, lenv)
231
+ @pat = AST.create_pattern_node(raw_node.pattern, lenv)
232
+ end
233
+
234
+ attr_reader :value, :pat
235
+
236
+ def subnodes = { value:, pat: }
237
+
238
+ def install0(genv)
239
+ @value.install(genv)
240
+ @pat.install(genv)
241
+ Source.new(genv.nil_type)
242
+ end
243
+ end
244
+
245
+ class MatchPreidcateNode < Node
246
+ def initialize(raw_node, lenv)
247
+ super(raw_node, lenv)
248
+ @value = AST.create_node(raw_node.value, lenv)
249
+ @pat = AST.create_pattern_node(raw_node.pattern, lenv)
250
+ end
251
+
252
+ attr_reader :value, :pat
253
+
254
+ def subnodes = { value:, pat: }
255
+
256
+ def install0(genv)
257
+ @value.install(genv)
258
+ @pat.install(genv)
259
+ Source.new(genv.true_type, genv.false_type)
260
+ end
261
+ end
262
+ end
263
+ end
@@ -0,0 +1,123 @@
1
+ module TypeProf::Core
2
+ class AST
3
+ class ModuleBaseNode < Node
4
+ def initialize(raw_node, lenv, raw_cpath, meta, raw_scope, use_result)
5
+ super(raw_node, lenv)
6
+
7
+ @cpath = AST.create_node(raw_cpath, lenv)
8
+ @static_cpath = AST.parse_cpath(raw_cpath, lenv.cref)
9
+ @tbl = raw_node.locals
10
+
11
+ # TODO: class Foo < Struct.new(:foo, :bar)
12
+
13
+ if @static_cpath
14
+ ncref = CRef.new(@static_cpath, meta ? :metaclass : :class, nil, lenv.cref)
15
+ nlenv = LocalEnv.new(@lenv.path, ncref, {}, [])
16
+ @body = raw_scope ? AST.create_node(raw_scope, nlenv, use_result) : DummyNilNode.new(code_range, lenv)
17
+ else
18
+ @body = nil
19
+ end
20
+
21
+ @cname_code_range = meta ? nil : TypeProf::CodeRange.from_node(raw_node.constant_path)
22
+ end
23
+
24
+ attr_reader :tbl, :cpath, :static_cpath, :cname_code_range, :body
25
+
26
+ def subnodes = { cpath:, body: }
27
+ def attrs = { static_cpath:, tbl: }
28
+
29
+ def define0(genv)
30
+ @cpath.define(genv)
31
+ if @static_cpath
32
+ @body.define(genv)
33
+ @mod = genv.resolve_cpath(@static_cpath)
34
+ @mod_cdef = @mod.add_module_def(genv, self)
35
+ else
36
+ kind = self.is_a?(ModuleNode) ? "module" : "class"
37
+ @changes.add_diagnostic(:code_range, "TypeProf cannot analyze a non-static #{ kind }") # warning
38
+ nil
39
+ end
40
+ end
41
+
42
+ def define_copy(genv)
43
+ if @static_cpath
44
+ @mod_cdef.add_def(self)
45
+ @mod_cdef.remove_def(@prev_node)
46
+ end
47
+ super(genv)
48
+ end
49
+
50
+ def undefine0(genv)
51
+ if @static_cpath
52
+ @mod.remove_module_def(genv, self)
53
+ @body.undefine(genv)
54
+ end
55
+ @cpath.undefine(genv)
56
+ end
57
+
58
+ def install0(genv)
59
+ @cpath.install(genv)
60
+ if @static_cpath
61
+ @tbl.each {|var| @body.lenv.locals[var] = Source.new(genv.nil_type) }
62
+ @body.lenv.locals[:"*self"] = @body.lenv.cref.get_self(genv)
63
+
64
+ @mod_val = Source.new(Type::Singleton.new(genv, genv.resolve_cpath(@static_cpath)))
65
+ @changes.add_edge(genv, @mod_val, @mod_cdef.vtx)
66
+ ret = Vertex.new(self)
67
+ @changes.add_edge(genv, @body.install(genv), ret)
68
+ ret
69
+ else
70
+ Source.new
71
+ end
72
+ end
73
+
74
+ def modified_vars(tbl, vars)
75
+ # skip
76
+ end
77
+ end
78
+
79
+ class ModuleNode < ModuleBaseNode
80
+ def initialize(raw_node, lenv, use_result)
81
+ super(raw_node, lenv, raw_node.constant_path, false, raw_node.body, use_result)
82
+ end
83
+ end
84
+
85
+ class ClassNode < ModuleBaseNode
86
+ def initialize(raw_node, lenv, use_result)
87
+ super(raw_node, lenv, raw_node.constant_path, false, raw_node.body, use_result)
88
+ raw_superclass = raw_node.superclass
89
+ @superclass_cpath = raw_superclass ? AST.create_node(raw_superclass, lenv) : nil
90
+ end
91
+
92
+ attr_reader :superclass_cpath
93
+
94
+ def subnodes
95
+ super.merge!({ superclass_cpath: })
96
+ end
97
+
98
+ def define0(genv)
99
+ if @static_cpath && @superclass_cpath
100
+ const = @superclass_cpath.define(genv)
101
+ const.followers << genv.resolve_cpath(@static_cpath) if const
102
+ end
103
+ super(genv)
104
+ end
105
+
106
+ def undefine0(genv)
107
+ super(genv)
108
+ @superclass_cpath.undefine(genv) if @superclass_cpath
109
+ end
110
+
111
+ def install0(genv)
112
+ @superclass_cpath.install(genv) if @superclass_cpath
113
+ super(genv)
114
+ end
115
+ end
116
+
117
+ class SingletonClassNode < ModuleBaseNode
118
+ def initialize(raw_node, lenv, use_result)
119
+ super(raw_node, lenv, raw_node.expression, true, raw_node.body, use_result)
120
+ end
121
+ end
122
+ end
123
+ end