typeprof 0.21.11 → 0.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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