typeprof 0.21.11 → 0.30.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +15 -31
- data/bin/typeprof +5 -0
- data/doc/doc.ja.md +134 -0
- data/doc/doc.md +136 -0
- data/lib/typeprof/cli/cli.rb +180 -0
- data/lib/typeprof/cli.rb +2 -133
- data/lib/typeprof/code_range.rb +112 -0
- data/lib/typeprof/core/ast/base.rb +263 -0
- data/lib/typeprof/core/ast/call.rb +251 -0
- data/lib/typeprof/core/ast/const.rb +126 -0
- data/lib/typeprof/core/ast/control.rb +432 -0
- data/lib/typeprof/core/ast/meta.rb +150 -0
- data/lib/typeprof/core/ast/method.rb +335 -0
- data/lib/typeprof/core/ast/misc.rb +263 -0
- data/lib/typeprof/core/ast/module.rb +123 -0
- data/lib/typeprof/core/ast/pattern.rb +140 -0
- data/lib/typeprof/core/ast/sig_decl.rb +471 -0
- data/lib/typeprof/core/ast/sig_type.rb +663 -0
- data/lib/typeprof/core/ast/value.rb +319 -0
- data/lib/typeprof/core/ast/variable.rb +315 -0
- data/lib/typeprof/core/ast.rb +472 -0
- data/lib/typeprof/core/builtin.rb +146 -0
- data/lib/typeprof/core/env/method.rb +137 -0
- data/lib/typeprof/core/env/method_entity.rb +55 -0
- data/lib/typeprof/core/env/module_entity.rb +408 -0
- data/lib/typeprof/core/env/static_read.rb +155 -0
- data/lib/typeprof/core/env/type_alias_entity.rb +27 -0
- data/lib/typeprof/core/env/value_entity.rb +32 -0
- data/lib/typeprof/core/env.rb +360 -0
- data/lib/typeprof/core/graph/box.rb +991 -0
- data/lib/typeprof/core/graph/change_set.rb +224 -0
- data/lib/typeprof/core/graph/filter.rb +155 -0
- data/lib/typeprof/core/graph/vertex.rb +222 -0
- data/lib/typeprof/core/graph.rb +3 -0
- data/lib/typeprof/core/service.rb +522 -0
- data/lib/typeprof/core/type.rb +348 -0
- data/lib/typeprof/core/util.rb +81 -0
- data/lib/typeprof/core.rb +32 -0
- data/lib/typeprof/diagnostic.rb +35 -0
- data/lib/typeprof/lsp/messages.rb +430 -0
- data/lib/typeprof/lsp/server.rb +177 -0
- data/lib/typeprof/lsp/text.rb +69 -0
- data/lib/typeprof/lsp/util.rb +61 -0
- data/lib/typeprof/lsp.rb +4 -907
- data/lib/typeprof/version.rb +1 -1
- data/lib/typeprof.rb +4 -18
- data/typeprof.gemspec +5 -7
- metadata +48 -35
- data/.github/dependabot.yml +0 -6
- data/.github/workflows/main.yml +0 -39
- data/.gitignore +0 -9
- data/Gemfile +0 -17
- data/Gemfile.lock +0 -41
- data/Rakefile +0 -10
- data/exe/typeprof +0 -10
- data/lib/typeprof/analyzer.rb +0 -2598
- data/lib/typeprof/arguments.rb +0 -414
- data/lib/typeprof/block.rb +0 -176
- data/lib/typeprof/builtin.rb +0 -893
- data/lib/typeprof/code-range.rb +0 -177
- data/lib/typeprof/config.rb +0 -158
- data/lib/typeprof/container-type.rb +0 -912
- data/lib/typeprof/export.rb +0 -589
- data/lib/typeprof/import.rb +0 -852
- data/lib/typeprof/insns-def.rb +0 -65
- data/lib/typeprof/iseq.rb +0 -864
- data/lib/typeprof/method.rb +0 -355
- data/lib/typeprof/type.rb +0 -1140
- data/lib/typeprof/utils.rb +0 -212
- data/tools/coverage.rb +0 -14
- data/tools/setup-insns-def.rb +0 -30
- data/typeprof-lsp +0 -3
@@ -0,0 +1,348 @@
|
|
1
|
+
module TypeProf::Core
|
2
|
+
class Type
|
3
|
+
# This new method does memoize creation of types
|
4
|
+
#: (GlobalEnv, *untyped) -> instance
|
5
|
+
def self.new(genv, *args)
|
6
|
+
genv.type_table[[self] + args] ||= super(genv, *args)
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.strip_parens(s)
|
10
|
+
#s =~ /\A\((.*)\)\z/ ? $1 : s
|
11
|
+
s.start_with?("(") && s.end_with?(")") ? s[1..-2] || raise : s
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.default_param_map(genv, ty)
|
15
|
+
ty = ty.base_type(genv)
|
16
|
+
instance_ty = ty.is_a?(Type::Instance) ? ty : Type::Instance.new(genv, ty.mod, []) # TODO: type params
|
17
|
+
singleton_ty = ty.is_a?(Type::Instance) ? Type::Singleton.new(genv, ty.mod) : ty
|
18
|
+
{
|
19
|
+
"*self": Source.new(ty),
|
20
|
+
"*instance": Source.new(instance_ty),
|
21
|
+
"*class": Source.new(singleton_ty),
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
class Singleton < Type
|
26
|
+
#: (GlobalEnv, ModuleEntity) -> void
|
27
|
+
def initialize(genv, mod)
|
28
|
+
raise unless mod.is_a?(ModuleEntity)
|
29
|
+
# TODO: type_param
|
30
|
+
@mod = mod
|
31
|
+
end
|
32
|
+
|
33
|
+
attr_reader :mod
|
34
|
+
|
35
|
+
def base_type(_)
|
36
|
+
self
|
37
|
+
end
|
38
|
+
|
39
|
+
def check_match(genv, changes, vtx)
|
40
|
+
vtx.each_type do |other_ty|
|
41
|
+
case other_ty
|
42
|
+
when Singleton
|
43
|
+
other_mod = other_ty.mod
|
44
|
+
if other_mod.module?
|
45
|
+
# TODO: implement
|
46
|
+
else
|
47
|
+
mod = @mod
|
48
|
+
while mod
|
49
|
+
return true if mod == other_mod
|
50
|
+
changes.add_depended_superclass(mod)
|
51
|
+
mod = mod.superclass
|
52
|
+
end
|
53
|
+
end
|
54
|
+
when Instance
|
55
|
+
base_ty = @mod.module? ? genv.mod_type : genv.cls_type
|
56
|
+
return true if base_ty.check_match(genv, changes, Source.new(other_ty))
|
57
|
+
end
|
58
|
+
end
|
59
|
+
return false
|
60
|
+
end
|
61
|
+
|
62
|
+
def show
|
63
|
+
"singleton(#{ @mod.show_cpath })"
|
64
|
+
end
|
65
|
+
|
66
|
+
def get_instance_type(genv)
|
67
|
+
params = @mod.type_params
|
68
|
+
Instance.new(genv, @mod, params ? params.map { Source.new } : [])
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
class Instance < Type
|
73
|
+
#: (GlobalEnv, ModuleEntity, ::Array[Vertex]) -> void
|
74
|
+
def initialize(genv, mod, args)
|
75
|
+
raise mod.class.to_s unless mod.is_a?(ModuleEntity)
|
76
|
+
@mod = mod
|
77
|
+
@args = args
|
78
|
+
raise unless @args.is_a?(::Array)
|
79
|
+
end
|
80
|
+
|
81
|
+
attr_reader :mod, :args
|
82
|
+
|
83
|
+
def base_type(_)
|
84
|
+
self
|
85
|
+
end
|
86
|
+
|
87
|
+
def check_match(genv, changes, vtx)
|
88
|
+
vtx.each_type do |other_ty|
|
89
|
+
case other_ty
|
90
|
+
when Instance
|
91
|
+
ty = self
|
92
|
+
while ty
|
93
|
+
if ty.mod == other_ty.mod
|
94
|
+
args_all_match = true
|
95
|
+
ty.args.zip(other_ty.args) do |arg, other_arg|
|
96
|
+
unless arg.check_match(genv, changes, other_arg)
|
97
|
+
args_all_match = false
|
98
|
+
break
|
99
|
+
end
|
100
|
+
end
|
101
|
+
return true if args_all_match
|
102
|
+
end
|
103
|
+
changes.add_depended_superclass(ty.mod)
|
104
|
+
|
105
|
+
if other_ty.mod.module?
|
106
|
+
return true if check_match_included_modules(genv, changes, ty, other_ty)
|
107
|
+
end
|
108
|
+
|
109
|
+
ty = genv.get_superclass_type(ty, changes, {})
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
return false
|
114
|
+
end
|
115
|
+
|
116
|
+
def check_match_included_modules(genv, changes, ty, other_ty)
|
117
|
+
ty.mod.included_modules.each do |inc_decl, inc_mod|
|
118
|
+
if inc_decl.is_a?(AST::SigIncludeNode) && inc_mod.type_params
|
119
|
+
inc_ty = genv.get_instance_type(inc_mod, inc_decl.args, changes, {}, ty)
|
120
|
+
else
|
121
|
+
type_params = inc_mod.type_params.map {|ty_param| Source.new() } # TODO: better support
|
122
|
+
inc_ty = Type::Instance.new(genv, inc_mod, type_params)
|
123
|
+
end
|
124
|
+
if inc_ty.mod == other_ty.mod
|
125
|
+
args_all_match = true
|
126
|
+
inc_ty.args.zip(other_ty.args) do |arg, other_arg|
|
127
|
+
if other_arg && !arg.check_match(genv, changes, other_arg)
|
128
|
+
args_all_match = false
|
129
|
+
break
|
130
|
+
end
|
131
|
+
end
|
132
|
+
return true if args_all_match
|
133
|
+
end
|
134
|
+
changes.add_depended_superclass(inc_ty.mod)
|
135
|
+
|
136
|
+
return true if check_match_included_modules(genv, changes, inc_ty, other_ty)
|
137
|
+
end
|
138
|
+
return false
|
139
|
+
end
|
140
|
+
|
141
|
+
def show
|
142
|
+
case @mod.cpath
|
143
|
+
when [:NilClass] then "nil"
|
144
|
+
when [:TrueClass] then "true"
|
145
|
+
when [:FalseClass] then "false"
|
146
|
+
else
|
147
|
+
"#{ @mod.show_cpath }#{ @args.empty? ? "" : "[#{ @args.map {|arg| Type.strip_parens(arg.show) }.join(", ") }]" }"
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
class Array < Type
|
153
|
+
#: (GlobalEnv, ::Array[Vertex], Instance) -> void
|
154
|
+
def initialize(genv, elems, base_type)
|
155
|
+
@elems = elems
|
156
|
+
@base_type = base_type
|
157
|
+
raise unless base_type.is_a?(Instance)
|
158
|
+
end
|
159
|
+
|
160
|
+
attr_reader :elems
|
161
|
+
|
162
|
+
def get_elem(genv, idx = nil)
|
163
|
+
if idx && @elems
|
164
|
+
@elems[idx] || Source.new(genv.nil_type)
|
165
|
+
else
|
166
|
+
@base_type.args.first
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def splat_assign(genv, lefts, rest_elem, rights)
|
171
|
+
edges = []
|
172
|
+
state = :left
|
173
|
+
j = nil
|
174
|
+
@elems.each_with_index do |elem, i|
|
175
|
+
case state
|
176
|
+
when :left
|
177
|
+
if i < lefts.size
|
178
|
+
edges << [elem, lefts[i]]
|
179
|
+
else
|
180
|
+
break unless rest_elem
|
181
|
+
state = :rest
|
182
|
+
redo
|
183
|
+
end
|
184
|
+
when :rest
|
185
|
+
if @elems.size - i > rights.size
|
186
|
+
edges << [elem, rest_elem]
|
187
|
+
else
|
188
|
+
state = :right
|
189
|
+
j = i
|
190
|
+
redo
|
191
|
+
end
|
192
|
+
when :right
|
193
|
+
edges << [elem, rights[i - j]]
|
194
|
+
end
|
195
|
+
end
|
196
|
+
edges
|
197
|
+
end
|
198
|
+
|
199
|
+
def base_type(genv)
|
200
|
+
@base_type
|
201
|
+
end
|
202
|
+
|
203
|
+
def check_match(genv, changes, vtx)
|
204
|
+
vtx.each_type do |other_ty|
|
205
|
+
if other_ty.is_a?(Array)
|
206
|
+
if @elems.size == other_ty.elems.size
|
207
|
+
match = true
|
208
|
+
@elems.zip(other_ty.elems) do |elem, other_elem|
|
209
|
+
unless elem.check_match(genv, changes, other_elem)
|
210
|
+
match = false
|
211
|
+
break
|
212
|
+
end
|
213
|
+
end
|
214
|
+
return true if match
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
@base_type.check_match(genv, changes, vtx)
|
219
|
+
end
|
220
|
+
|
221
|
+
def show
|
222
|
+
if @elems
|
223
|
+
"[#{ @elems.map {|e| Type.strip_parens(e.show) }.join(", ") }]"
|
224
|
+
else
|
225
|
+
"#{ @base_type.mod.show_cpath }[#{ Type.strip_parens(@unified_elem.show) }]"
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
class Hash < Type
|
231
|
+
#: (GlobalEnv, ::Array[Vertex], Instance) -> void
|
232
|
+
def initialize(genv, literal_pairs, base_type)
|
233
|
+
@literal_pairs = literal_pairs
|
234
|
+
@base_type = base_type
|
235
|
+
raise unless base_type.is_a?(Instance)
|
236
|
+
end
|
237
|
+
|
238
|
+
def get_key
|
239
|
+
@base_type.args[0]
|
240
|
+
end
|
241
|
+
|
242
|
+
def get_value(key = nil)
|
243
|
+
@literal_pairs[key] || @base_type.args[1]
|
244
|
+
end
|
245
|
+
|
246
|
+
def base_type(genv)
|
247
|
+
@base_type
|
248
|
+
end
|
249
|
+
|
250
|
+
def check_match(genv, changes, vtx)
|
251
|
+
# TODO: implement
|
252
|
+
@base_type.check_match(genv, changes, vtx)
|
253
|
+
end
|
254
|
+
|
255
|
+
def show
|
256
|
+
@base_type.show
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
class Proc < Type
|
261
|
+
def initialize(genv, block)
|
262
|
+
@block = block
|
263
|
+
end
|
264
|
+
|
265
|
+
attr_reader :block
|
266
|
+
|
267
|
+
def base_type(genv)
|
268
|
+
genv.proc_type
|
269
|
+
end
|
270
|
+
|
271
|
+
def check_match(genv, changes, vtx)
|
272
|
+
genv.proc_type.check_match(genv, changes, vtx)
|
273
|
+
end
|
274
|
+
|
275
|
+
def show
|
276
|
+
"<Proc>"
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
class Symbol < Type
|
281
|
+
#: (GlobalEnv, ::Symbol) -> void
|
282
|
+
def initialize(genv, sym)
|
283
|
+
@sym = sym
|
284
|
+
end
|
285
|
+
|
286
|
+
attr_reader :sym
|
287
|
+
|
288
|
+
def base_type(genv)
|
289
|
+
genv.symbol_type
|
290
|
+
end
|
291
|
+
|
292
|
+
def check_match(genv, changes, vtx)
|
293
|
+
vtx.each_type do |other_ty|
|
294
|
+
case other_ty
|
295
|
+
when Symbol
|
296
|
+
return true if @sym == other_ty.sym
|
297
|
+
when Instance
|
298
|
+
return true if genv.symbol_type.check_match(genv, changes, Source.new(other_ty))
|
299
|
+
end
|
300
|
+
end
|
301
|
+
return false
|
302
|
+
end
|
303
|
+
|
304
|
+
def show
|
305
|
+
@sym.inspect
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
class Bot < Type
|
310
|
+
def initialize(genv)
|
311
|
+
end
|
312
|
+
|
313
|
+
def base_type(genv)
|
314
|
+
genv.obj_type
|
315
|
+
end
|
316
|
+
|
317
|
+
def check_match(genv, changes, vtx)
|
318
|
+
return true
|
319
|
+
end
|
320
|
+
|
321
|
+
def show
|
322
|
+
"bot"
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
class Var < Type
|
327
|
+
#: (GlobalEnv, ::Symbol, Vertex) -> void
|
328
|
+
def initialize(genv, name, vtx)
|
329
|
+
@name = name
|
330
|
+
@vtx = vtx
|
331
|
+
end
|
332
|
+
|
333
|
+
attr_reader :name, :vtx
|
334
|
+
|
335
|
+
def base_type(genv)
|
336
|
+
genv.obj_type # Is this ok?
|
337
|
+
end
|
338
|
+
|
339
|
+
def check_match(genv, changes, vtx)
|
340
|
+
true # should implement a better support...
|
341
|
+
end
|
342
|
+
|
343
|
+
def show
|
344
|
+
"var[#{ @name }]"
|
345
|
+
end
|
346
|
+
end
|
347
|
+
end
|
348
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module TypeProf::Core
|
2
|
+
class Set
|
3
|
+
def self.[](*elems)
|
4
|
+
h = Hash.new(false)
|
5
|
+
elems.each {|elem| h[elem] = true }
|
6
|
+
new(h)
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(hash)
|
10
|
+
@hash = hash
|
11
|
+
end
|
12
|
+
|
13
|
+
def internal_hash = @hash
|
14
|
+
|
15
|
+
def dup
|
16
|
+
Set.new(@hash.dup)
|
17
|
+
end
|
18
|
+
|
19
|
+
def <<(elem)
|
20
|
+
raise if @hash.include?(elem)
|
21
|
+
@hash[elem] = true
|
22
|
+
self
|
23
|
+
end
|
24
|
+
|
25
|
+
def include?(elem)
|
26
|
+
@hash[elem]
|
27
|
+
end
|
28
|
+
|
29
|
+
def merge(set)
|
30
|
+
raise NotImplementedError
|
31
|
+
end
|
32
|
+
|
33
|
+
def each(&blk)
|
34
|
+
@hash.each_key(&blk)
|
35
|
+
end
|
36
|
+
|
37
|
+
def empty?
|
38
|
+
@hash.empty?
|
39
|
+
end
|
40
|
+
|
41
|
+
def delete(elem)
|
42
|
+
raise unless @hash.include?(elem)
|
43
|
+
@hash.delete(elem)
|
44
|
+
end
|
45
|
+
|
46
|
+
def clear
|
47
|
+
@hash.clear
|
48
|
+
end
|
49
|
+
|
50
|
+
def to_a
|
51
|
+
@hash.keys
|
52
|
+
end
|
53
|
+
|
54
|
+
def size
|
55
|
+
@hash.size
|
56
|
+
end
|
57
|
+
|
58
|
+
def -(other)
|
59
|
+
h = @hash.dup
|
60
|
+
other.each do |elem|
|
61
|
+
h.delete(elem)
|
62
|
+
end
|
63
|
+
Set.new(h)
|
64
|
+
end
|
65
|
+
|
66
|
+
def pretty_print(q)
|
67
|
+
q.text "Set["
|
68
|
+
q.group do
|
69
|
+
q.nest(1) do
|
70
|
+
@hash.each_key do |elem|
|
71
|
+
q.breakable ""
|
72
|
+
q.pp elem
|
73
|
+
q.text ","
|
74
|
+
end
|
75
|
+
end
|
76
|
+
q.breakable ""
|
77
|
+
end
|
78
|
+
q.text "]"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require "rbs"
|
2
|
+
require "prism"
|
3
|
+
require_relative "core/util"
|
4
|
+
require_relative "core/ast"
|
5
|
+
require_relative "core/ast/base"
|
6
|
+
require_relative "core/ast/module"
|
7
|
+
require_relative "core/ast/method"
|
8
|
+
require_relative "core/ast/call"
|
9
|
+
require_relative "core/ast/control"
|
10
|
+
require_relative "core/ast/const"
|
11
|
+
require_relative "core/ast/variable"
|
12
|
+
require_relative "core/ast/value"
|
13
|
+
require_relative "core/ast/misc"
|
14
|
+
require_relative "core/ast/meta"
|
15
|
+
require_relative "core/ast/pattern"
|
16
|
+
require_relative "core/ast/sig_decl"
|
17
|
+
require_relative "core/ast/sig_type"
|
18
|
+
require_relative "core/type"
|
19
|
+
require_relative "core/env"
|
20
|
+
require_relative "core/env/method_entity"
|
21
|
+
require_relative "core/env/module_entity"
|
22
|
+
require_relative "core/env/type_alias_entity"
|
23
|
+
require_relative "core/env/value_entity"
|
24
|
+
require_relative "core/env/method"
|
25
|
+
require_relative "core/env/static_read"
|
26
|
+
require_relative "core/graph"
|
27
|
+
require_relative "core/graph/change_set"
|
28
|
+
require_relative "core/graph/vertex"
|
29
|
+
require_relative "core/graph/filter"
|
30
|
+
require_relative "core/graph/box"
|
31
|
+
require_relative "core/builtin"
|
32
|
+
require_relative "core/service"
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module TypeProf
|
2
|
+
class Diagnostic
|
3
|
+
def initialize(node, meth, msg)
|
4
|
+
@node = node
|
5
|
+
@meth = meth
|
6
|
+
@msg = msg
|
7
|
+
@severity = :error # TODO: keyword argument
|
8
|
+
@tags = nil # TODO: keyword argument
|
9
|
+
end
|
10
|
+
|
11
|
+
def reuse(new_node)
|
12
|
+
@node = new_node
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_reader :msg, :severity
|
16
|
+
|
17
|
+
def code_range
|
18
|
+
@node.send(@meth)
|
19
|
+
end
|
20
|
+
|
21
|
+
SEVERITY = { error: 1, warning: 2, info: 3, hint: 4 }
|
22
|
+
TAG = { unnecessary: 1, deprecated: 2 }
|
23
|
+
|
24
|
+
def to_lsp
|
25
|
+
json = {
|
26
|
+
range: code_range.to_lsp,
|
27
|
+
source: "TypeProf",
|
28
|
+
message: @msg,
|
29
|
+
}
|
30
|
+
json[:severity] = SEVERITY[@severity] if @severity
|
31
|
+
json[:tags] = @tags.map {|tag| TAG[tag] } if @tags
|
32
|
+
json
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|