typeprof 0.31.1 → 0.32.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.
- checksums.yaml +4 -4
- data/README.md +2 -1
- data/doc/report_guide.md +88 -0
- data/lib/typeprof/cli/cli.rb +9 -3
- data/lib/typeprof/code_range.rb +7 -5
- data/lib/typeprof/core/ast/base.rb +18 -6
- data/lib/typeprof/core/ast/call.rb +96 -32
- data/lib/typeprof/core/ast/const.rb +12 -9
- data/lib/typeprof/core/ast/control.rb +60 -30
- data/lib/typeprof/core/ast/meta.rb +194 -2
- data/lib/typeprof/core/ast/method.rb +74 -20
- data/lib/typeprof/core/ast/misc.rb +27 -7
- data/lib/typeprof/core/ast/module.rb +33 -3
- data/lib/typeprof/core/ast/sig_decl.rb +85 -24
- data/lib/typeprof/core/ast/sig_type.rb +77 -31
- data/lib/typeprof/core/ast/value.rb +14 -6
- data/lib/typeprof/core/ast/variable.rb +11 -4
- data/lib/typeprof/core/ast.rb +95 -14
- data/lib/typeprof/core/builtin.rb +184 -12
- data/lib/typeprof/core/env/method.rb +171 -6
- data/lib/typeprof/core/env/method_entity.rb +18 -15
- data/lib/typeprof/core/env/module_entity.rb +56 -18
- data/lib/typeprof/core/env/static_read.rb +4 -4
- data/lib/typeprof/core/env/type_alias_entity.rb +1 -1
- data/lib/typeprof/core/env/value_entity.rb +25 -3
- data/lib/typeprof/core/env.rb +79 -17
- data/lib/typeprof/core/graph/box.rb +379 -52
- data/lib/typeprof/core/graph/change_set.rb +59 -46
- data/lib/typeprof/core/graph/filter.rb +8 -5
- data/lib/typeprof/core/graph/vertex.rb +20 -19
- data/lib/typeprof/core/service.rb +317 -23
- data/lib/typeprof/core/type.rb +41 -7
- data/lib/typeprof/core/util.rb +6 -0
- data/lib/typeprof/lsp/messages.rb +5 -0
- data/lib/typeprof/lsp/server.rb +35 -4
- data/lib/typeprof/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 93757a88e1532a3e0d9faf5b3eb8690b7a61ced6027e28d49dfce43234557015
|
|
4
|
+
data.tar.gz: 8e41f82794582ea68445e0972a6cab30982fcac483a50c5032811e3a2fcb9a60
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f1020867309edd82548dd3bcfc84d22007324af9c6acd0e6c82bb002678dfef3bb7acc695f6cc19d243d24084871a3a7a0695b1d7f069122ab28a221fca06469
|
|
7
|
+
data.tar.gz: 17cf614ed4edd5e75c772750fe844db59d65dcf7dc129b22269e4a840dbf4a45c1136f7ed74ac780d37d183f08de24e2ca447cd1804ea39bc39e7876f393ede8
|
data/README.md
CHANGED
|
@@ -37,7 +37,8 @@ $ bundle exec rake test
|
|
|
37
37
|
|
|
38
38
|
## More details
|
|
39
39
|
|
|
40
|
-
https://speakerdeck.com/mame/good-first-issues-of-typeprof
|
|
40
|
+
- [Good first issues of TypeProf](https://speakerdeck.com/mame/good-first-issues-of-typeprof) (slides)
|
|
41
|
+
- [How to report bugs / propose features](doc/report_guide.md)
|
|
41
42
|
|
|
42
43
|
## LICENSE
|
|
43
44
|
|
data/doc/report_guide.md
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# How to Report Bugs and Propose Features
|
|
2
|
+
|
|
3
|
+
Thank you for your interest in improving TypeProf! When reporting a bug or proposing a feature, including a **scenario file** is very helpful (but not mandatory).
|
|
4
|
+
|
|
5
|
+
## What is a Scenario File?
|
|
6
|
+
|
|
7
|
+
A scenario file describes TypeProf's behavior — the input code and the expected type inference result. You can find many examples in the [`scenario/`](../scenario/) directory.
|
|
8
|
+
|
|
9
|
+
## Writing a Scenario File
|
|
10
|
+
|
|
11
|
+
### Basic pattern
|
|
12
|
+
|
|
13
|
+
A minimal scenario file has two sections: `## update` (input code) and `## assert` (expected type signatures in [RBS](https://github.com/ruby/rbs) syntax).
|
|
14
|
+
|
|
15
|
+
```ruby
|
|
16
|
+
## update
|
|
17
|
+
def foo(n)
|
|
18
|
+
n.to_s
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
foo(42)
|
|
22
|
+
|
|
23
|
+
## assert
|
|
24
|
+
class Object
|
|
25
|
+
def foo: (Integer) -> String
|
|
26
|
+
end
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Multiple updates
|
|
30
|
+
|
|
31
|
+
You can include multiple `## update` / `## assert` pairs to test how TypeProf handles code changes:
|
|
32
|
+
|
|
33
|
+
```ruby
|
|
34
|
+
## update
|
|
35
|
+
def foo = "symbol#{ 42 }"
|
|
36
|
+
|
|
37
|
+
## assert
|
|
38
|
+
class Object
|
|
39
|
+
def foo: -> String
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
## update
|
|
43
|
+
def foo = :"symbol#{ 42 }"
|
|
44
|
+
|
|
45
|
+
## assert
|
|
46
|
+
class Object
|
|
47
|
+
def foo: -> Symbol
|
|
48
|
+
end
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Diagnostics
|
|
52
|
+
|
|
53
|
+
Use `## diagnostics` to verify that TypeProf reports type errors at the expected locations:
|
|
54
|
+
|
|
55
|
+
```ruby
|
|
56
|
+
## update
|
|
57
|
+
def foo(x)
|
|
58
|
+
x
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
foo(1, 2)
|
|
62
|
+
|
|
63
|
+
## diagnostics
|
|
64
|
+
(5,0)-(5,3): wrong number of arguments (2 for 1)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Running a Scenario File
|
|
68
|
+
|
|
69
|
+
Run a single scenario file:
|
|
70
|
+
|
|
71
|
+
```sh
|
|
72
|
+
$ ruby tool/scenario_runner.rb path/to/your_scenario.rb
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Run all tests:
|
|
76
|
+
|
|
77
|
+
```sh
|
|
78
|
+
$ bundle exec rake test
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Reporting a Bug
|
|
82
|
+
|
|
83
|
+
1. Create a scenario file that reproduces the issue.
|
|
84
|
+
2. Run it with `ruby tool/scenario_runner.rb your_scenario.rb` to confirm the problem.
|
|
85
|
+
3. Open an issue and include:
|
|
86
|
+
- Your TypeProf version (`typeprof --version`)
|
|
87
|
+
- The scenario file content
|
|
88
|
+
- What you expected vs. what actually happened
|
data/lib/typeprof/cli/cli.rb
CHANGED
|
@@ -12,6 +12,7 @@ module TypeProf::CLI
|
|
|
12
12
|
output = nil
|
|
13
13
|
rbs_collection_path = nil
|
|
14
14
|
initialize_config_file = false
|
|
15
|
+
exclude_patterns = []
|
|
15
16
|
|
|
16
17
|
opt.separator ""
|
|
17
18
|
opt.separator "Options:"
|
|
@@ -25,6 +26,7 @@ module TypeProf::CLI
|
|
|
25
26
|
opt.on("--version", "Display typeprof version") { cli_options[:display_version] = true }
|
|
26
27
|
opt.on("--collection PATH", "File path of collection configuration") { |v| rbs_collection_path = v }
|
|
27
28
|
opt.on("--no-collection", "Ignore collection configuration") { rbs_collection_path = :no }
|
|
29
|
+
opt.on("--exclude PATTERN", "Exclude files matching glob PATTERN (can be specified multiple times)") { |v| exclude_patterns << v }
|
|
28
30
|
opt.on("--lsp", "LSP server mode") do |v|
|
|
29
31
|
core_options[:display_indicator] = false
|
|
30
32
|
cli_options[:lsp] = true
|
|
@@ -36,6 +38,7 @@ module TypeProf::CLI
|
|
|
36
38
|
opt.on("--[no-]show-errors", "Display possible errors found during the analysis") {|v| core_options[:output_diagnostics] = v }
|
|
37
39
|
opt.on("--[no-]show-parameter-names", "Display parameter names for methods") {|v| core_options[:output_parameter_names] = v }
|
|
38
40
|
opt.on("--[no-]show-source-locations", "Display definition source locations for methods") {|v| core_options[:output_source_locations] = v }
|
|
41
|
+
opt.on("--[no-]show-stats", "Display type inference statistics after analysis (for debugging purpose)") {|v| core_options[:output_stats] = v }
|
|
39
42
|
|
|
40
43
|
opt.separator ""
|
|
41
44
|
opt.separator "Advanced options:"
|
|
@@ -65,6 +68,8 @@ module TypeProf::CLI
|
|
|
65
68
|
output_errors: false,
|
|
66
69
|
output_parameter_names: false,
|
|
67
70
|
output_source_locations: false,
|
|
71
|
+
output_stats: false,
|
|
72
|
+
exclude_patterns: exclude_patterns,
|
|
68
73
|
}.merge(core_options)
|
|
69
74
|
|
|
70
75
|
@lsp_options = {
|
|
@@ -120,7 +125,7 @@ module TypeProf::CLI
|
|
|
120
125
|
if @lsp_options[:stdio]
|
|
121
126
|
TypeProf::LSP::Server.start_stdio(@core_options)
|
|
122
127
|
else
|
|
123
|
-
TypeProf::LSP::Server.start_socket(@core_options)
|
|
128
|
+
TypeProf::LSP::Server.start_socket(@core_options, @lsp_options[:port])
|
|
124
129
|
end
|
|
125
130
|
rescue Exception
|
|
126
131
|
puts $!.detailed_message(highlight: false).gsub(/^/, "---")
|
|
@@ -151,7 +156,7 @@ module TypeProf::CLI
|
|
|
151
156
|
files = []
|
|
152
157
|
@cli_options[:argv].each do |path|
|
|
153
158
|
if File.directory?(path)
|
|
154
|
-
files.concat(Dir.glob("#{ path }/**/*.{rb,rbs}"))
|
|
159
|
+
files.concat(Dir.glob("#{ path }/**/*.{rb,rbs}").select {|f| File.file?(f) })
|
|
155
160
|
elsif File.file?(path)
|
|
156
161
|
files << path
|
|
157
162
|
else
|
|
@@ -189,7 +194,8 @@ module TypeProf::CLI
|
|
|
189
194
|
{
|
|
190
195
|
"typeprof_version": "experimental",
|
|
191
196
|
"rbs_dir": "sig/",
|
|
192
|
-
"analysis_unit_dirs": #{exist_dirs.inspect}
|
|
197
|
+
"analysis_unit_dirs": #{exist_dirs.inspect},
|
|
198
|
+
// "exclude": ["**/templates/**/*.rb"],
|
|
193
199
|
// "diagnostic_severity": "warning"
|
|
194
200
|
}
|
|
195
201
|
JSONC
|
data/lib/typeprof/code_range.rb
CHANGED
|
@@ -55,12 +55,14 @@ module TypeProf
|
|
|
55
55
|
raise unless first
|
|
56
56
|
end
|
|
57
57
|
|
|
58
|
-
def self.from_node(node,
|
|
58
|
+
def self.from_node(node, file_context)
|
|
59
59
|
node = node.location if node.respond_to?(:location)
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
60
|
+
case node
|
|
61
|
+
when Prism::Location
|
|
62
|
+
start_col, end_col = file_context.column_offsets_for(node)
|
|
63
|
+
pos1 = CodePosition.new(node.start_line, start_col)
|
|
64
|
+
pos2 = CodePosition.new(node.end_line, end_col)
|
|
65
|
+
when RBS::Location
|
|
64
66
|
pos1 = CodePosition.new(*node.start_loc)
|
|
65
67
|
pos2 = CodePosition.new(*node.end_loc)
|
|
66
68
|
else
|
|
@@ -9,7 +9,7 @@ module TypeProf::Core
|
|
|
9
9
|
@ret = nil
|
|
10
10
|
|
|
11
11
|
@changes = ChangeSet.new(self, nil)
|
|
12
|
-
@diagnostics = Set
|
|
12
|
+
@diagnostics = Set::EMPTY
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
attr_reader :lenv
|
|
@@ -53,7 +53,7 @@ module TypeProf::Core
|
|
|
53
53
|
|
|
54
54
|
def code_range
|
|
55
55
|
if @raw_node
|
|
56
|
-
|
|
56
|
+
@lenv.code_range_from_node(@raw_node)
|
|
57
57
|
else
|
|
58
58
|
pp self
|
|
59
59
|
raise
|
|
@@ -104,6 +104,7 @@ module TypeProf::Core
|
|
|
104
104
|
@changes.reuse(self)
|
|
105
105
|
(@prev_node || raise).diagnostics.each do |diag|
|
|
106
106
|
diag.reuse(self)
|
|
107
|
+
@diagnostics = Set.empty if @diagnostics.equal?(Set::EMPTY)
|
|
107
108
|
@diagnostics << diag
|
|
108
109
|
end
|
|
109
110
|
each_subnode do |subnode|
|
|
@@ -129,11 +130,12 @@ module TypeProf::Core
|
|
|
129
130
|
end
|
|
130
131
|
|
|
131
132
|
def add_diagnostic(diag)
|
|
133
|
+
@diagnostics = Set.empty if @diagnostics.equal?(Set::EMPTY)
|
|
132
134
|
@diagnostics << diag
|
|
133
135
|
end
|
|
134
136
|
|
|
135
137
|
def remove_diagnostic(diag)
|
|
136
|
-
@diagnostics.delete(diag)
|
|
138
|
+
@diagnostics.delete(diag) unless @diagnostics.equal?(Set::EMPTY)
|
|
137
139
|
end
|
|
138
140
|
|
|
139
141
|
def diff(prev_node)
|
|
@@ -209,20 +211,30 @@ module TypeProf::Core
|
|
|
209
211
|
end
|
|
210
212
|
|
|
211
213
|
class ProgramNode < Node
|
|
212
|
-
def initialize(raw_node, lenv)
|
|
214
|
+
def initialize(raw_node, lenv, ignore_ranges: [])
|
|
213
215
|
super(raw_node, lenv)
|
|
214
216
|
|
|
215
217
|
@tbl = raw_node.locals
|
|
218
|
+
@ignore_ranges = ignore_ranges
|
|
216
219
|
raw_body = raw_node.statements
|
|
217
220
|
|
|
218
221
|
@body = AST.create_node(raw_body, lenv, false)
|
|
219
222
|
end
|
|
220
223
|
|
|
221
|
-
attr_reader :tbl, :body
|
|
224
|
+
attr_reader :tbl, :ignore_ranges, :body
|
|
222
225
|
|
|
223
226
|
def subnodes = { body: }
|
|
224
227
|
def attrs = { tbl: }
|
|
225
228
|
|
|
229
|
+
def each_diagnostic(genv, &blk)
|
|
230
|
+
return super if @ignore_ranges.empty?
|
|
231
|
+
super(genv) do |diag|
|
|
232
|
+
line = diag.code_range&.first&.lineno
|
|
233
|
+
next if line && @ignore_ranges.any? { |r| r.cover?(line) }
|
|
234
|
+
blk.call(diag)
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
|
|
226
238
|
def install0(genv)
|
|
227
239
|
@tbl.each {|var| @lenv.locals[var] = Source.new(genv.nil_type) }
|
|
228
240
|
@lenv.locals[:"*self"] = lenv.cref.get_self(genv)
|
|
@@ -270,7 +282,7 @@ module TypeProf::Core
|
|
|
270
282
|
@ret = ret
|
|
271
283
|
end
|
|
272
284
|
|
|
273
|
-
attr_reader :lenv, :prev_node, :ret
|
|
285
|
+
attr_reader :lenv, :prev_node, :code_range, :ret
|
|
274
286
|
|
|
275
287
|
def boxes(_)
|
|
276
288
|
[]
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
module TypeProf::Core
|
|
2
2
|
class AST
|
|
3
3
|
class CallBaseNode < Node
|
|
4
|
-
def initialize(raw_node, recv, mid, mid_code_range, raw_args, last_arg, raw_block, lenv)
|
|
4
|
+
def initialize(raw_node, recv, mid, mid_code_range, raw_args, last_arg, raw_block, lenv, forwarding_arguments: false)
|
|
5
5
|
super(raw_node, lenv)
|
|
6
6
|
|
|
7
7
|
@recv = recv
|
|
@@ -16,9 +16,11 @@ module TypeProf::Core
|
|
|
16
16
|
@block_pass = nil
|
|
17
17
|
@block_tbl = nil
|
|
18
18
|
@block_f_args = nil
|
|
19
|
+
@block_opt_positional_defaults = nil
|
|
19
20
|
@block_body = nil
|
|
20
21
|
@safe_navigation = raw_node.respond_to?(:safe_navigation?) && raw_node.safe_navigation?
|
|
21
22
|
@anonymous_block_forwarding = false
|
|
23
|
+
@forwarding_arguments = forwarding_arguments
|
|
22
24
|
|
|
23
25
|
if raw_args
|
|
24
26
|
args = []
|
|
@@ -29,13 +31,13 @@ module TypeProf::Core
|
|
|
29
31
|
args << raw_arg.expression
|
|
30
32
|
@splat_flags << true
|
|
31
33
|
when Prism::ForwardingArgumentsNode
|
|
32
|
-
|
|
34
|
+
@forwarding_arguments = true
|
|
33
35
|
else
|
|
34
36
|
args << raw_arg
|
|
35
37
|
@splat_flags << false
|
|
36
38
|
end
|
|
37
39
|
end
|
|
38
|
-
@positional_args = args.map {|arg| arg ? AST.create_node(arg, lenv) :
|
|
40
|
+
@positional_args = args.map {|arg| arg ? AST.create_node(arg, lenv) : nil }
|
|
39
41
|
|
|
40
42
|
kw = @positional_args.last
|
|
41
43
|
if kw.is_a?(TypeProf::Core::AST::HashNode) && kw.keywords
|
|
@@ -55,10 +57,20 @@ module TypeProf::Core
|
|
|
55
57
|
else
|
|
56
58
|
@block_pass = nil
|
|
57
59
|
@block_tbl = raw_block.locals
|
|
58
|
-
|
|
60
|
+
@block_multi_targets = {}
|
|
59
61
|
@block_f_args = case raw_block.parameters
|
|
60
62
|
when Prism::BlockParametersNode
|
|
61
|
-
raw_block.parameters.parameters
|
|
63
|
+
params = raw_block.parameters.parameters
|
|
64
|
+
req = params.requireds.each_with_index.map do |n, i|
|
|
65
|
+
if n.is_a?(Prism::MultiTargetNode)
|
|
66
|
+
@block_multi_targets[i] = n
|
|
67
|
+
nil
|
|
68
|
+
else
|
|
69
|
+
n.name
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
opt = params.optionals.map {|n| n.name }
|
|
73
|
+
req + opt
|
|
62
74
|
when Prism::NumberedParametersNode
|
|
63
75
|
1.upto(raw_block.parameters.maximum).map { |n| :"_#{n}" }
|
|
64
76
|
when Prism::ItParametersNode
|
|
@@ -69,7 +81,13 @@ module TypeProf::Core
|
|
|
69
81
|
raise "not supported yet: #{ raw_block.parameters.class }"
|
|
70
82
|
end
|
|
71
83
|
ncref = CRef.new(lenv.cref.cpath, :instance, @mid, lenv.cref)
|
|
72
|
-
nlenv = LocalEnv.new(@lenv.
|
|
84
|
+
nlenv = LocalEnv.new(@lenv.file_context, ncref, {}, @lenv.return_boxes)
|
|
85
|
+
@block_opt_positional_defaults = []
|
|
86
|
+
if raw_block.parameters.is_a?(Prism::BlockParametersNode)
|
|
87
|
+
raw_block.parameters.parameters.optionals.each do |n|
|
|
88
|
+
@block_opt_positional_defaults << AST.create_node(n.value, nlenv)
|
|
89
|
+
end
|
|
90
|
+
end
|
|
73
91
|
@block_body = raw_block.body ? AST.create_node(raw_block.body, nlenv) : DummyNilNode.new(code_range, lenv)
|
|
74
92
|
end
|
|
75
93
|
end
|
|
@@ -79,11 +97,12 @@ module TypeProf::Core
|
|
|
79
97
|
|
|
80
98
|
attr_reader :recv, :mid, :mid_code_range, :yield
|
|
81
99
|
attr_reader :positional_args, :splat_flags, :keyword_args
|
|
82
|
-
attr_reader :block_tbl, :block_f_args, :block_body, :block_pass, :anonymous_block_forwarding
|
|
83
|
-
attr_reader :
|
|
100
|
+
attr_reader :block_tbl, :block_f_args, :block_opt_positional_defaults, :block_body, :block_pass, :anonymous_block_forwarding
|
|
101
|
+
attr_reader :block_multi_targets
|
|
102
|
+
attr_reader :safe_navigation, :forwarding_arguments
|
|
84
103
|
|
|
85
|
-
def subnodes = { recv:, positional_args:, keyword_args:, block_body:, block_pass: }
|
|
86
|
-
def attrs = { mid:, splat_flags:, block_tbl:, block_f_args:, yield:, safe_navigation:, anonymous_block_forwarding: }
|
|
104
|
+
def subnodes = { recv:, positional_args:, keyword_args:, block_opt_positional_defaults:, block_body:, block_pass: }
|
|
105
|
+
def attrs = { mid:, splat_flags:, block_tbl:, block_f_args:, yield:, safe_navigation:, anonymous_block_forwarding:, forwarding_arguments: }
|
|
87
106
|
|
|
88
107
|
def install0(genv)
|
|
89
108
|
recv = @recv ? @recv.install(genv) : @yield ? @lenv.get_var(:"*given_block") : @lenv.get_var(:"*self")
|
|
@@ -93,22 +112,30 @@ module TypeProf::Core
|
|
|
93
112
|
recv = NilFilter.new(genv, self, recv, false).next_vtx
|
|
94
113
|
end
|
|
95
114
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
115
|
+
if @forwarding_arguments
|
|
116
|
+
forward_a_args = (@lenv.forward_args || raise).to_actual_arguments(genv, @changes, self)
|
|
117
|
+
positional_args = forward_a_args.positionals
|
|
118
|
+
splat_flags = forward_a_args.splat_flags
|
|
119
|
+
keyword_args = forward_a_args.keywords
|
|
120
|
+
else
|
|
121
|
+
positional_args = @positional_args.map do |arg|
|
|
122
|
+
if arg.nil?
|
|
123
|
+
@lenv.get_var(:"*anonymous_rest")
|
|
124
|
+
else
|
|
125
|
+
arg.install(genv)
|
|
126
|
+
end
|
|
101
127
|
end
|
|
128
|
+
splat_flags = @splat_flags
|
|
129
|
+
keyword_args = @keyword_args ? @keyword_args.install(genv) : nil
|
|
102
130
|
end
|
|
103
131
|
|
|
104
|
-
keyword_args = @keyword_args ? @keyword_args.install(genv) : nil
|
|
105
|
-
|
|
106
132
|
if @block_body
|
|
107
133
|
block_body = @block_body # kinda type annotationty
|
|
108
134
|
block_tbl = @block_tbl || raise
|
|
135
|
+
block_body.lenv.forward_args = @lenv.forward_args
|
|
109
136
|
@lenv.locals.each {|var, vtx| block_body.lenv.locals[var] = vtx }
|
|
110
137
|
block_tbl.each {|var| block_body.lenv.locals[var] = Source.new(genv.nil_type) }
|
|
111
|
-
|
|
138
|
+
block_body.lenv.locals[:"*self"] = block_body.lenv.cref.get_self(genv)
|
|
112
139
|
|
|
113
140
|
blk_f_args = []
|
|
114
141
|
if @block_f_args
|
|
@@ -117,11 +144,28 @@ module TypeProf::Core
|
|
|
117
144
|
end
|
|
118
145
|
end
|
|
119
146
|
|
|
147
|
+
if @block_opt_positional_defaults && !@block_opt_positional_defaults.empty?
|
|
148
|
+
req_count = blk_f_args.size - @block_opt_positional_defaults.size
|
|
149
|
+
@block_opt_positional_defaults.each_with_index do |expr, i|
|
|
150
|
+
@changes.add_edge(genv, expr.install(genv), blk_f_args[req_count + i])
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
if @block_multi_targets
|
|
155
|
+
@block_multi_targets.each do |idx, raw_multi_target|
|
|
156
|
+
param_vtx = blk_f_args[idx]
|
|
157
|
+
lefts = raw_multi_target.lefts.map do |n|
|
|
158
|
+
block_body.lenv.new_var(n.is_a?(Prism::MultiTargetNode) ? nil : n.name, self)
|
|
159
|
+
end
|
|
160
|
+
@changes.add_masgn_box(genv, param_vtx, lefts, nil, nil)
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
120
164
|
@lenv.locals.each do |var, vtx|
|
|
121
165
|
block_body.lenv.set_var(var, vtx)
|
|
122
166
|
end
|
|
123
167
|
vars = []
|
|
124
|
-
|
|
168
|
+
block_body.modified_vars(@lenv.locals.keys - block_tbl, vars)
|
|
125
169
|
vars.uniq!
|
|
126
170
|
vars.each do |var|
|
|
127
171
|
vtx = @lenv.get_var(var)
|
|
@@ -130,25 +174,31 @@ module TypeProf::Core
|
|
|
130
174
|
block_body.lenv.set_var(var, nvtx)
|
|
131
175
|
end
|
|
132
176
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
177
|
+
block_body.lenv.locals[:"*expected_block_ret"] = Vertex.new(self)
|
|
178
|
+
block_body.install(genv)
|
|
179
|
+
block_body.lenv.add_next_box(@changes.add_escape_box(genv, block_body.ret))
|
|
136
180
|
|
|
137
181
|
vars.each do |var|
|
|
138
182
|
@changes.add_edge(genv, block_body.lenv.get_var(var), @lenv.get_var(var))
|
|
139
183
|
end
|
|
140
184
|
|
|
141
185
|
blk_f_ary_arg = Vertex.new(self)
|
|
142
|
-
|
|
143
|
-
|
|
186
|
+
# TODO: support splat "do |a, *b, c|"
|
|
187
|
+
blk_f_args.each_with_index do |f_arg, i|
|
|
188
|
+
elem_vtx = @changes.add_splat_box(genv, blk_f_ary_arg, i).ret
|
|
189
|
+
@changes.add_edge(genv, elem_vtx, f_arg)
|
|
190
|
+
end
|
|
191
|
+
block = Block.new(self, blk_f_ary_arg, blk_f_args, block_body.lenv.next_boxes)
|
|
144
192
|
blk_ty = Source.new(Type::Proc.new(genv, block))
|
|
145
193
|
elsif @block_pass
|
|
146
194
|
blk_ty = @block_pass.install(genv)
|
|
147
195
|
elsif @anonymous_block_forwarding
|
|
148
196
|
blk_ty = @lenv.get_var(:"*anonymous_block")
|
|
197
|
+
elsif @forwarding_arguments
|
|
198
|
+
blk_ty = forward_a_args.block
|
|
149
199
|
end
|
|
150
200
|
|
|
151
|
-
a_args = ActualArguments.new(positional_args,
|
|
201
|
+
a_args = ActualArguments.new(positional_args, splat_flags, keyword_args, blk_ty)
|
|
152
202
|
box = @changes.add_method_call_box(genv, recv, @mid, a_args, !@recv)
|
|
153
203
|
|
|
154
204
|
block_body = @block_body
|
|
@@ -197,7 +247,7 @@ module TypeProf::Core
|
|
|
197
247
|
subnode.modified_vars(tbl, vars)
|
|
198
248
|
end
|
|
199
249
|
else
|
|
200
|
-
subnode.each {|n| n
|
|
250
|
+
subnode.each {|n| n&.modified_vars(tbl, vars) }
|
|
201
251
|
end
|
|
202
252
|
end
|
|
203
253
|
end
|
|
@@ -207,7 +257,7 @@ module TypeProf::Core
|
|
|
207
257
|
def initialize(raw_node, lenv)
|
|
208
258
|
recv = raw_node.receiver ? AST.create_node(raw_node.receiver, lenv) : nil
|
|
209
259
|
mid = raw_node.name
|
|
210
|
-
mid_code_range =
|
|
260
|
+
mid_code_range = lenv.code_range_from_node(raw_node.message_loc) if raw_node.message_loc
|
|
211
261
|
raw_args = raw_node.arguments
|
|
212
262
|
raw_block = raw_node.block
|
|
213
263
|
super(raw_node, recv, mid, mid_code_range, raw_args, nil, raw_block, lenv)
|
|
@@ -231,6 +281,20 @@ module TypeProf::Core
|
|
|
231
281
|
else
|
|
232
282
|
super
|
|
233
283
|
end
|
|
284
|
+
when :nil?
|
|
285
|
+
if @recv.is_a?(LocalVariableReadNode)
|
|
286
|
+
[
|
|
287
|
+
Narrowing.new({ @recv.var => Narrowing::NilConstraint.new(true) }),
|
|
288
|
+
Narrowing.new({ @recv.var => Narrowing::NilConstraint.new(false) })
|
|
289
|
+
]
|
|
290
|
+
elsif @recv.is_a?(InstanceVariableReadNode)
|
|
291
|
+
[
|
|
292
|
+
Narrowing.new({ @recv.var => Narrowing::NilConstraint.new(true) }),
|
|
293
|
+
Narrowing.new({ @recv.var => Narrowing::NilConstraint.new(false) })
|
|
294
|
+
]
|
|
295
|
+
else
|
|
296
|
+
super
|
|
297
|
+
end
|
|
234
298
|
when :!
|
|
235
299
|
then_narrowing, else_narrowing = @recv.narrowings
|
|
236
300
|
[else_narrowing, then_narrowing]
|
|
@@ -251,9 +315,9 @@ module TypeProf::Core
|
|
|
251
315
|
|
|
252
316
|
class ForwardingSuperNode < CallBaseNode
|
|
253
317
|
def initialize(raw_node, lenv)
|
|
254
|
-
raw_args = nil
|
|
318
|
+
raw_args = nil
|
|
255
319
|
raw_block = raw_node.block
|
|
256
|
-
super(raw_node, nil, :"*super", nil, raw_args, nil, raw_block, lenv)
|
|
320
|
+
super(raw_node, nil, :"*super", nil, raw_args, nil, raw_block, lenv, forwarding_arguments: true)
|
|
257
321
|
end
|
|
258
322
|
end
|
|
259
323
|
|
|
@@ -267,7 +331,7 @@ module TypeProf::Core
|
|
|
267
331
|
class OperatorNode < CallBaseNode
|
|
268
332
|
def initialize(raw_node, recv, lenv)
|
|
269
333
|
mid = raw_node.binary_operator
|
|
270
|
-
mid_code_range =
|
|
334
|
+
mid_code_range = lenv.code_range_from_node(raw_node.binary_operator_loc)
|
|
271
335
|
last_arg = AST.create_node(raw_node.value, lenv)
|
|
272
336
|
super(raw_node, recv, mid, mid_code_range, nil, last_arg, nil, lenv)
|
|
273
337
|
end
|
|
@@ -300,7 +364,7 @@ module TypeProf::Core
|
|
|
300
364
|
def initialize(raw_node, lenv)
|
|
301
365
|
recv = AST.create_node(raw_node.receiver, lenv)
|
|
302
366
|
mid = raw_node.read_name
|
|
303
|
-
mid_code_range =
|
|
367
|
+
mid_code_range = lenv.code_range_from_node(raw_node.message_loc)
|
|
304
368
|
super(raw_node, recv, mid, mid_code_range, nil, nil, nil, lenv)
|
|
305
369
|
end
|
|
306
370
|
end
|
|
@@ -309,7 +373,7 @@ module TypeProf::Core
|
|
|
309
373
|
def initialize(raw_node, rhs, lenv)
|
|
310
374
|
recv = AST.create_node(raw_node.receiver, lenv)
|
|
311
375
|
mid = raw_node.is_a?(Prism::CallTargetNode) ? raw_node.name : raw_node.write_name
|
|
312
|
-
mid_code_range =
|
|
376
|
+
mid_code_range = lenv.code_range_from_node(raw_node.message_loc)
|
|
313
377
|
@rhs = rhs
|
|
314
378
|
super(raw_node, recv, mid, mid_code_range, nil, rhs, nil, lenv)
|
|
315
379
|
end
|
|
@@ -8,7 +8,7 @@ module TypeProf::Core
|
|
|
8
8
|
@cbase = nil
|
|
9
9
|
@toplevel = false
|
|
10
10
|
@cname = raw_node.name
|
|
11
|
-
@cname_code_range =
|
|
11
|
+
@cname_code_range = lenv.code_range_from_node(raw_node.location)
|
|
12
12
|
when :constant_path_node, :constant_path_target_node
|
|
13
13
|
if raw_node.parent
|
|
14
14
|
@cbase = AST.create_node(raw_node.parent, lenv)
|
|
@@ -18,7 +18,7 @@ module TypeProf::Core
|
|
|
18
18
|
@toplevel = true
|
|
19
19
|
end
|
|
20
20
|
@cname = raw_node.name
|
|
21
|
-
@cname_code_range =
|
|
21
|
+
@cname_code_range = lenv.code_range_from_node(raw_node.name_loc)
|
|
22
22
|
else
|
|
23
23
|
raise raw_node.type.to_s
|
|
24
24
|
end
|
|
@@ -57,17 +57,17 @@ module TypeProf::Core
|
|
|
57
57
|
# C = expr
|
|
58
58
|
@cpath = nil
|
|
59
59
|
@static_cpath = lenv.cref.cpath + [raw_node.name]
|
|
60
|
-
@cname_code_range =
|
|
60
|
+
@cname_code_range = lenv.code_range_from_node(raw_node.respond_to?(:name_loc) ? raw_node.name_loc : raw_node)
|
|
61
61
|
when :constant_path_write_node, :constant_path_operator_write_node, :constant_path_or_write_node, :constant_path_and_write_node
|
|
62
62
|
# expr::C = expr
|
|
63
63
|
@cpath = AST.create_node(raw_node.target, lenv)
|
|
64
64
|
@static_cpath = AST.parse_cpath(raw_node.target, lenv.cref)
|
|
65
|
-
@cname_code_range =
|
|
65
|
+
@cname_code_range = lenv.code_range_from_node(raw_node.target)
|
|
66
66
|
when :constant_path_target_node
|
|
67
67
|
# expr::C, * = ary
|
|
68
68
|
@cpath = ConstantReadNode.new(raw_node, lenv)
|
|
69
69
|
@static_cpath = AST.parse_cpath(raw_node, lenv.cref)
|
|
70
|
-
@cname_code_range =
|
|
70
|
+
@cname_code_range = lenv.code_range_from_node(raw_node)
|
|
71
71
|
else
|
|
72
72
|
raise
|
|
73
73
|
end
|
|
@@ -83,9 +83,10 @@ module TypeProf::Core
|
|
|
83
83
|
@cpath.define(genv) if @cpath
|
|
84
84
|
@rhs.define(genv) if @rhs
|
|
85
85
|
if @static_cpath
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
86
|
+
cdef = genv.resolve_const(@static_cpath)
|
|
87
|
+
cdef.on_const_added(genv, @static_cpath)
|
|
88
|
+
cdef.add_def(self)
|
|
89
|
+
cdef
|
|
89
90
|
else
|
|
90
91
|
nil
|
|
91
92
|
end
|
|
@@ -102,7 +103,9 @@ module TypeProf::Core
|
|
|
102
103
|
|
|
103
104
|
def undefine0(genv)
|
|
104
105
|
if @static_cpath
|
|
105
|
-
genv.resolve_const(@static_cpath)
|
|
106
|
+
cdef = genv.resolve_const(@static_cpath)
|
|
107
|
+
cdef.remove_def(self)
|
|
108
|
+
cdef.on_const_removed(genv, @static_cpath)
|
|
106
109
|
end
|
|
107
110
|
@rhs.undefine(genv) if @rhs
|
|
108
111
|
@cpath.undefine(genv) if @cpath
|