steep 1.8.0.dev.2 → 1.8.0.pre.1
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/CHANGELOG.md +33 -0
- data/bin/mem_graph.rb +67 -0
- data/bin/mem_prof.rb +102 -0
- data/bin/stackprof_test.rb +19 -0
- data/bin/steep-check.rb +251 -0
- data/lib/steep/annotation_parser.rb +1 -1
- data/lib/steep/ast/builtin.rb +5 -5
- data/lib/steep/ast/node/type_application.rb +7 -6
- data/lib/steep/ast/types/any.rb +1 -9
- data/lib/steep/ast/types/boolean.rb +8 -16
- data/lib/steep/ast/types/bot.rb +2 -10
- data/lib/steep/ast/types/class.rb +1 -13
- data/lib/steep/ast/types/factory.rb +101 -85
- data/lib/steep/ast/types/instance.rb +1 -13
- data/lib/steep/ast/types/intersection.rb +8 -15
- data/lib/steep/ast/types/literal.rb +2 -8
- data/lib/steep/ast/types/logic.rb +3 -24
- data/lib/steep/ast/types/name.rb +5 -16
- data/lib/steep/ast/types/nil.rb +3 -12
- data/lib/steep/ast/types/proc.rb +4 -13
- data/lib/steep/ast/types/record.rb +21 -12
- data/lib/steep/ast/types/self.rb +1 -13
- data/lib/steep/ast/types/shared_instance.rb +11 -0
- data/lib/steep/ast/types/top.rb +1 -9
- data/lib/steep/ast/types/tuple.rb +4 -10
- data/lib/steep/ast/types/union.rb +10 -15
- data/lib/steep/ast/types/var.rb +4 -13
- data/lib/steep/ast/types/void.rb +2 -10
- data/lib/steep/diagnostic/ruby.rb +4 -4
- data/lib/steep/drivers/check.rb +11 -14
- data/lib/steep/drivers/checkfile.rb +8 -10
- data/lib/steep/drivers/stats.rb +17 -13
- data/lib/steep/drivers/utils/driver_helper.rb +24 -3
- data/lib/steep/drivers/watch.rb +3 -3
- data/lib/steep/interface/builder.rb +162 -138
- data/lib/steep/interface/method_type.rb +12 -20
- data/lib/steep/interface/shape.rb +66 -10
- data/lib/steep/interface/substitution.rb +2 -0
- data/lib/steep/interface/type_param.rb +20 -7
- data/lib/steep/located_value.rb +20 -0
- data/lib/steep/server/change_buffer.rb +5 -7
- data/lib/steep/server/custom_methods.rb +61 -0
- data/lib/steep/server/delay_queue.rb +8 -1
- data/lib/steep/server/interaction_worker.rb +10 -5
- data/lib/steep/server/lsp_formatter.rb +8 -6
- data/lib/steep/server/master.rb +193 -140
- data/lib/steep/server/type_check_worker.rb +18 -19
- data/lib/steep/server/work_done_progress.rb +64 -0
- data/lib/steep/services/completion_provider.rb +24 -22
- data/lib/steep/services/goto_service.rb +3 -2
- data/lib/steep/services/hover_provider/ruby.rb +7 -6
- data/lib/steep/services/signature_help_provider.rb +7 -6
- data/lib/steep/services/signature_service.rb +1 -1
- data/lib/steep/services/type_check_service.rb +3 -3
- data/lib/steep/signature/validator.rb +17 -20
- data/lib/steep/subtyping/check.rb +105 -55
- data/lib/steep/subtyping/constraints.rb +11 -15
- data/lib/steep/type_construction.rb +100 -100
- data/lib/steep/type_inference/block_params.rb +6 -6
- data/lib/steep/type_inference/logic_type_interpreter.rb +11 -7
- data/lib/steep/type_inference/method_call.rb +3 -3
- data/lib/steep/type_inference/method_params.rb +1 -1
- data/lib/steep/type_inference/send_args.rb +1 -1
- data/lib/steep/typing.rb +158 -102
- data/lib/steep/version.rb +1 -1
- data/lib/steep.rb +28 -3
- data/steep.gemspec +2 -2
- metadata +16 -9
- data/lib/steep/type_inference/context_array.rb +0 -112
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c87015f545300c9c126b0121aa9534db083c157fbd791b7117006b6683bdc05d
|
4
|
+
data.tar.gz: 6bb606ac1b4cc9cdd6364745c02f878714cdf2ca2d61079376a3ea50fbf4b9ba
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4787c76c6049f2e1a2a9856d26dd0157419a2f4258a185559d0fe676500380089d75b30f916e353836f0e6af4eab16e2d977a9be5798bcfae1d13f8902d21491
|
7
|
+
data.tar.gz: 462bb7747747fd5a34bf3205cd71d94f22beb4efd4407e5e59fbc31c049583b8350cdac262591319ad2ed09d802d94e3ff42d2f9c54ba0addff5547c7258f898
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,38 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
+
## 1.8.0.pre.1 (2024-09-17)
|
4
|
+
|
5
|
+
### Type checker core
|
6
|
+
|
7
|
+
* Fix some subtyping problems ([#1221](https://github.com/soutaro/steep/pull/1221))
|
8
|
+
* Support optional keys in record types ([#1223](https://github.com/soutaro/steep/pull/1223))
|
9
|
+
* Revert implicit generic upper bound ([#1220](https://github.com/soutaro/steep/pull/1220))
|
10
|
+
* Improve generics ([#1216](https://github.com/soutaro/steep/pull/1216))
|
11
|
+
* Delete meta data from `MethodType` and `Types::*` ([#1201](https://github.com/soutaro/steep/pull/1201))
|
12
|
+
* Delete `ContextArray` ([#1199](https://github.com/soutaro/steep/pull/1199))
|
13
|
+
* Fix shape calculation error ([#1197](https://github.com/soutaro/steep/pull/1197))
|
14
|
+
* Skip `#:` syntax in `Data.define` and `Struct.new` ([#1196](https://github.com/soutaro/steep/pull/1196))
|
15
|
+
* Support literals for Rational and Complex ([#1178](https://github.com/soutaro/steep/pull/1178))
|
16
|
+
* Ignore type assertions on arguments/receiver on `def`/`defs` ([#1179](https://github.com/soutaro/steep/pull/1179))
|
17
|
+
* Ignore `#:` annotation on `attr_*` calls ([#1176](https://github.com/soutaro/steep/pull/1176))
|
18
|
+
|
19
|
+
### Commandline tool
|
20
|
+
|
21
|
+
* Improve performance when there are many files ([#1184](https://github.com/soutaro/steep/pull/1184))
|
22
|
+
* Fix type errors ([#1183](https://github.com/soutaro/steep/pull/1183))
|
23
|
+
|
24
|
+
### Language server
|
25
|
+
|
26
|
+
* Make type checking a LSP request, not a LSP notification ([#1218](https://github.com/soutaro/steep/pull/1218))
|
27
|
+
* No `timeout: nil` ([#1217](https://github.com/soutaro/steep/pull/1217))
|
28
|
+
* Print `loading project` message via LSP ([#1213](https://github.com/soutaro/steep/pull/1213))
|
29
|
+
* Load files in main process ([#1206](https://github.com/soutaro/steep/pull/1206))
|
30
|
+
|
31
|
+
### Miscellaneous
|
32
|
+
|
33
|
+
* Drop Ruby 3.0 ([#1225](https://github.com/soutaro/steep/pull/1225))
|
34
|
+
* Add `bin/steep-check` for profiling ([#1198](https://github.com/soutaro/steep/pull/1198))
|
35
|
+
|
3
36
|
## 1.7.1 (2024-06-12)
|
4
37
|
|
5
38
|
### Type checker core
|
data/bin/mem_graph.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
class MemGraph
|
2
|
+
attr_reader :edges
|
3
|
+
|
4
|
+
attr_reader :checked
|
5
|
+
|
6
|
+
attr_reader :generation
|
7
|
+
|
8
|
+
def initialize(generation)
|
9
|
+
@generation = generation
|
10
|
+
@edges = []
|
11
|
+
@checked = Set.new.compare_by_identity
|
12
|
+
@checked << self
|
13
|
+
@checked << edges
|
14
|
+
@checked << checked
|
15
|
+
end
|
16
|
+
|
17
|
+
IVARS = Object.instance_method(:instance_variables)
|
18
|
+
IVGET = Object.instance_method(:instance_variable_get)
|
19
|
+
|
20
|
+
def traverse(object)
|
21
|
+
return if checked.include?(object)
|
22
|
+
checked << object
|
23
|
+
|
24
|
+
case object
|
25
|
+
when Array
|
26
|
+
object.each do |value|
|
27
|
+
insert_edge(object, value)
|
28
|
+
traverse(value)
|
29
|
+
end
|
30
|
+
when Hash
|
31
|
+
object.each do |key, value|
|
32
|
+
insert_edge(object, key)
|
33
|
+
insert_edge(object, value)
|
34
|
+
|
35
|
+
traverse(key)
|
36
|
+
traverse(value)
|
37
|
+
end
|
38
|
+
else
|
39
|
+
IVARS.bind_call(object).each do |name|
|
40
|
+
if name.is_a?(Symbol)
|
41
|
+
value = IVGET.bind_call(object, name)
|
42
|
+
traverse(value)
|
43
|
+
insert_edge(object, value)
|
44
|
+
else
|
45
|
+
STDERR.puts "Unexpected instance variable name: #{name} in #{object.class}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def insert_edge(source, dest)
|
52
|
+
case dest
|
53
|
+
when Integer, Symbol, nil, true, false, Float
|
54
|
+
else
|
55
|
+
edges << [
|
56
|
+
"#{source.class}(#{source.__id__})",
|
57
|
+
"#{dest.class}(#{dest.__id__})",
|
58
|
+
]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def dot
|
63
|
+
"digraph G {\n" + edges.uniq.map do |source, dest|
|
64
|
+
" #{source} -> #{dest};"
|
65
|
+
end.join("\n") + "}"
|
66
|
+
end
|
67
|
+
end
|
data/bin/mem_prof.rb
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
require "objspace"
|
2
|
+
|
3
|
+
class MemProf
|
4
|
+
attr_reader :generation
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.trace(io: STDOUT, &block)
|
10
|
+
profiler = MemProf.new
|
11
|
+
profiler.start
|
12
|
+
|
13
|
+
begin
|
14
|
+
ret = yield
|
15
|
+
rescue
|
16
|
+
ObjectSpace.trace_object_allocations_stop
|
17
|
+
ObjectSpace.trace_object_allocations_clear
|
18
|
+
raise
|
19
|
+
end
|
20
|
+
|
21
|
+
allocated, retained, collected = profiler.stop
|
22
|
+
|
23
|
+
counts = {}
|
24
|
+
collected.each do |id, entry|
|
25
|
+
counts[entry] ||= 0
|
26
|
+
counts[entry] += 1
|
27
|
+
end
|
28
|
+
|
29
|
+
counts.keys.sort_by {|entry| -counts[entry] }.take(200).each do |entry|
|
30
|
+
count = counts.fetch(entry)
|
31
|
+
io.puts "#{entry[0]},#{entry[1]},#{entry[2]},#{count}"
|
32
|
+
end
|
33
|
+
|
34
|
+
STDERR.puts "Total allocated: #{allocated.size}"
|
35
|
+
STDERR.puts "Total retained: #{retained.size}"
|
36
|
+
STDERR.puts "Total collected: #{collected.size}"
|
37
|
+
|
38
|
+
ret
|
39
|
+
end
|
40
|
+
|
41
|
+
def start
|
42
|
+
GC.disable
|
43
|
+
3.times { GC.start }
|
44
|
+
GC.start
|
45
|
+
|
46
|
+
@generation = GC.count
|
47
|
+
ObjectSpace.trace_object_allocations_start
|
48
|
+
end
|
49
|
+
|
50
|
+
def stop
|
51
|
+
ObjectSpace.trace_object_allocations_stop
|
52
|
+
|
53
|
+
allocated = objects()
|
54
|
+
retained = {}
|
55
|
+
|
56
|
+
GC.enable
|
57
|
+
GC.start
|
58
|
+
GC.start
|
59
|
+
GC.start
|
60
|
+
|
61
|
+
ObjectSpace.each_object do |obj|
|
62
|
+
next unless ObjectSpace.allocation_generation(obj) == generation
|
63
|
+
if o = allocated[obj.__id__]
|
64
|
+
retained[obj.__id__] = o
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# ObjectSpace.trace_object_allocations_clear
|
69
|
+
|
70
|
+
collected = {}
|
71
|
+
allocated.each do |id, state|
|
72
|
+
collected[id] = state unless retained.key?(id)
|
73
|
+
end
|
74
|
+
|
75
|
+
[allocated, retained, collected]
|
76
|
+
end
|
77
|
+
|
78
|
+
def objects(hash = {})
|
79
|
+
ObjectSpace.each_object do |obj|
|
80
|
+
next unless ObjectSpace.allocation_generation(obj) == generation
|
81
|
+
|
82
|
+
file = ObjectSpace.allocation_sourcefile(obj) || "(no name)"
|
83
|
+
line = ObjectSpace.allocation_sourceline(obj)
|
84
|
+
klass = object_class(obj)
|
85
|
+
|
86
|
+
hash[obj.__id__] = [file, line, klass]
|
87
|
+
end
|
88
|
+
|
89
|
+
hash
|
90
|
+
end
|
91
|
+
|
92
|
+
KERNEL_CLASS_METHOD = Kernel.instance_method(:class)
|
93
|
+
def object_class(obj)
|
94
|
+
klass = obj.class rescue nil
|
95
|
+
|
96
|
+
unless Class === klass
|
97
|
+
# attempt to determine the true Class when .class returns something other than a Class
|
98
|
+
klass = KERNEL_CLASS_METHOD.bind_call(obj)
|
99
|
+
end
|
100
|
+
klass
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "stackprof"
|
4
|
+
|
5
|
+
mode = (ENV["STEEP_STACKPROF_MODE"] || :cpu).to_sym
|
6
|
+
out = ENV["STEEP_STACKPROF_OUT"] || "tmp/stackprof-#{mode}-test.dump"
|
7
|
+
interval = ENV["STEEP_STACKPROF_INTERVAL"]&.to_i || 1000
|
8
|
+
|
9
|
+
STDERR.puts "Running profiler: mode => #{mode}, out => #{out}"
|
10
|
+
StackProf.run(mode: mode, out: out, raw: true, interval: interval) do
|
11
|
+
# 10.times do
|
12
|
+
# 1_000.times do
|
13
|
+
# Array.new(1_000_000)
|
14
|
+
# end
|
15
|
+
# sleep 0.1
|
16
|
+
# end
|
17
|
+
|
18
|
+
sleep 5
|
19
|
+
end
|
data/bin/steep-check.rb
ADDED
@@ -0,0 +1,251 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'pathname'
|
4
|
+
|
5
|
+
$LOAD_PATH << Pathname(__dir__) + "../lib"
|
6
|
+
|
7
|
+
require 'steep'
|
8
|
+
require "fileutils"
|
9
|
+
require "optparse"
|
10
|
+
|
11
|
+
puts <<MESSAGE
|
12
|
+
This is a single-threaded and one-process type checker for profiling.
|
13
|
+
It runs really slow because it's not parallelized, but it's easier to profiling and analyzing the result.
|
14
|
+
|
15
|
+
$ bundle exec bin/steep-check --target=app
|
16
|
+
$ bundle exec bin/steep-check --target=app files...
|
17
|
+
|
18
|
+
MESSAGE
|
19
|
+
|
20
|
+
steep_file_path = Pathname("Steepfile")
|
21
|
+
target_name = nil #: Symbol?
|
22
|
+
profile_mode = :none #: Symbol?
|
23
|
+
|
24
|
+
OptionParser.new do |opts|
|
25
|
+
opts.on("--steepfile=FILE") do |file|
|
26
|
+
steep_file_path = Pathname(file)
|
27
|
+
end
|
28
|
+
opts.on("--target=TARGET") do |target|
|
29
|
+
target_name = target.to_sym
|
30
|
+
end
|
31
|
+
opts.on("--profile=MODE", "vernier, memory, stackprof, none, majo, memory2, dumpall") do |mode|
|
32
|
+
profile_mode = mode.to_sym
|
33
|
+
end
|
34
|
+
end.parse!(ARGV)
|
35
|
+
|
36
|
+
command_line_args = ARGV.dup
|
37
|
+
|
38
|
+
class Command
|
39
|
+
include Steep
|
40
|
+
|
41
|
+
attr_reader :project, :target
|
42
|
+
|
43
|
+
def initialize(steep_file_path:, target_name:)
|
44
|
+
@project = Project.new(steepfile_path: steep_file_path).tap do |project|
|
45
|
+
Project::DSL.parse(project, steep_file_path.read, filename: steep_file_path.to_s)
|
46
|
+
end
|
47
|
+
|
48
|
+
if target_name
|
49
|
+
@target = project.targets.find { _1.name == target_name}
|
50
|
+
else
|
51
|
+
@target = project.targets[0]
|
52
|
+
end
|
53
|
+
|
54
|
+
unless target
|
55
|
+
raise "!! Cannot find a target with #{target_name}: targets=[#{project.targets.map(&:name).join(", ")}]"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def load_signatures()
|
60
|
+
file_loader = Steep::Services::FileLoader.new(base_dir: project.base_dir)
|
61
|
+
|
62
|
+
signature_files = {}
|
63
|
+
file_loader.each_path_in_patterns(target.signature_pattern) do |path|
|
64
|
+
signature_files[path] = path.read
|
65
|
+
end
|
66
|
+
|
67
|
+
target.options.load_collection_lock
|
68
|
+
|
69
|
+
signature_service = Steep::Project::Target.construct_env_loader(options: target.options, project: project).yield_self do |loader|
|
70
|
+
Steep::Services::SignatureService.load_from(loader)
|
71
|
+
end
|
72
|
+
|
73
|
+
env = signature_service.latest_env
|
74
|
+
|
75
|
+
new_decls = Set[]
|
76
|
+
|
77
|
+
signature_files.each do |path, content|
|
78
|
+
buffer = RBS::Buffer.new(name: path.to_s, content: content)
|
79
|
+
buffer, dirs, decls = RBS::Parser.parse_signature(buffer)
|
80
|
+
env.add_signature(buffer: buffer, directives: dirs, decls: decls)
|
81
|
+
new_decls.merge(decls)
|
82
|
+
end
|
83
|
+
|
84
|
+
env.resolve_type_names(only: new_decls)
|
85
|
+
end
|
86
|
+
|
87
|
+
def type_check_files(command_line_args, env)
|
88
|
+
file_loader = Steep::Services::FileLoader.new(base_dir: project.base_dir)
|
89
|
+
|
90
|
+
source_files = {}
|
91
|
+
file_loader.each_path_in_patterns(target.source_pattern, command_line_args) do |path|
|
92
|
+
source_files[path] = path.read
|
93
|
+
end
|
94
|
+
|
95
|
+
definition_builder = RBS::DefinitionBuilder.new(env: env)
|
96
|
+
factory = AST::Types::Factory.new(builder: definition_builder)
|
97
|
+
builder = Interface::Builder.new(factory)
|
98
|
+
subtyping = Subtyping::Check.new(builder: builder)
|
99
|
+
|
100
|
+
typings = {}
|
101
|
+
|
102
|
+
source_files.each do |path, content|
|
103
|
+
source = Source.parse(content, path: path, factory: factory)
|
104
|
+
|
105
|
+
self_type = AST::Builtin::Object.instance_type
|
106
|
+
|
107
|
+
annotations = source.annotations(block: source.node, factory: factory, context: nil)
|
108
|
+
resolver = RBS::Resolver::ConstantResolver.new(builder: factory.definition_builder)
|
109
|
+
const_env = TypeInference::ConstantEnv.new(factory: factory, context: nil, resolver: resolver)
|
110
|
+
|
111
|
+
type_env = TypeInference::TypeEnvBuilder.new(
|
112
|
+
TypeInference::TypeEnvBuilder::Command::ImportGlobalDeclarations.new(factory),
|
113
|
+
TypeInference::TypeEnvBuilder::Command::ImportInstanceVariableAnnotations.new(annotations),
|
114
|
+
TypeInference::TypeEnvBuilder::Command::ImportConstantAnnotations.new(annotations),
|
115
|
+
TypeInference::TypeEnvBuilder::Command::ImportLocalVariableAnnotations.new(annotations)
|
116
|
+
).build(TypeInference::TypeEnv.new(const_env))
|
117
|
+
|
118
|
+
context = TypeInference::Context.new(
|
119
|
+
block_context: nil,
|
120
|
+
method_context: nil,
|
121
|
+
module_context: TypeInference::Context::ModuleContext.new(
|
122
|
+
instance_type: AST::Builtin::Object.instance_type,
|
123
|
+
module_type: AST::Builtin::Object.module_type,
|
124
|
+
implement_name: nil,
|
125
|
+
nesting: nil,
|
126
|
+
class_name: AST::Builtin::Object.module_name,
|
127
|
+
instance_definition: factory.definition_builder.build_instance(AST::Builtin::Object.module_name),
|
128
|
+
module_definition: factory.definition_builder.build_singleton(AST::Builtin::Object.module_name)
|
129
|
+
),
|
130
|
+
break_context: nil,
|
131
|
+
self_type: self_type,
|
132
|
+
type_env: type_env,
|
133
|
+
call_context: TypeInference::MethodCall::TopLevelContext.new(),
|
134
|
+
variable_context: TypeInference::Context::TypeVariableContext.empty
|
135
|
+
)
|
136
|
+
|
137
|
+
typing = Typing.new(source: source, root_context: context, cursor: nil)
|
138
|
+
construction = TypeConstruction.new(checker: subtyping, source: source, annotations: annotations, context: context, typing: typing)
|
139
|
+
|
140
|
+
construction.synthesize(source.node)
|
141
|
+
typings[path] = typing
|
142
|
+
end
|
143
|
+
|
144
|
+
typings
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
command = Command.new(steep_file_path: Pathname.pwd + steep_file_path, target_name: target_name)
|
149
|
+
|
150
|
+
puts ">> Loading RBS files..."
|
151
|
+
env = command.load_signatures()
|
152
|
+
|
153
|
+
puts ">> Type checking files with #{profile_mode}..."
|
154
|
+
|
155
|
+
typings = nil
|
156
|
+
|
157
|
+
GC.start(immediate_sweep: true, immediate_mark: true, full_mark: true)
|
158
|
+
# GC.config[:rgengc_allow_major_gc] = false
|
159
|
+
|
160
|
+
case profile_mode
|
161
|
+
when :vernier
|
162
|
+
require "vernier"
|
163
|
+
out = Pathname.pwd + "tmp/typecheck-#{Process.pid}.vernier.json"
|
164
|
+
puts ">> Profiling with vernier: #{out}"
|
165
|
+
Vernier.profile(out: out.to_s) do
|
166
|
+
typings = command.type_check_files(command_line_args, env)
|
167
|
+
end
|
168
|
+
|
169
|
+
when :memory
|
170
|
+
require 'memory_profiler'
|
171
|
+
out = Pathname.pwd + "tmp/typecheck-#{Process.pid}.memory.txt"
|
172
|
+
puts ">> Profiling with memory_profiler: #{out}"
|
173
|
+
classes = nil
|
174
|
+
report = MemoryProfiler.report(trace: classes) do
|
175
|
+
typings = command.type_check_files(command_line_args, env)
|
176
|
+
end
|
177
|
+
report.pretty_print(to_file: out, detailed_report: true, scale_bytes: true, retained_strings: false, allocated_strings: false)
|
178
|
+
|
179
|
+
when :memory2
|
180
|
+
require_relative 'mem_prof'
|
181
|
+
out = Pathname.pwd + "tmp/typecheck-#{Process.pid}.memory2.csv"
|
182
|
+
puts ">> Profiling with mem_prof: #{out}"
|
183
|
+
generation = nil
|
184
|
+
out.open("w") do |io|
|
185
|
+
MemProf.trace(io: io) do
|
186
|
+
generation = GC.count
|
187
|
+
typings = command.type_check_files(command_line_args, env)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
require_relative 'mem_graph'
|
192
|
+
graph = MemGraph.new(generation)
|
193
|
+
ObjectSpace.each_object do |obj|
|
194
|
+
if ObjectSpace.allocation_generation(obj) == generation
|
195
|
+
graph.traverse(obj)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
(Pathname.pwd + "objects-#{Process.pid}.dot").write(graph.dot)
|
199
|
+
|
200
|
+
when :stackprof
|
201
|
+
require "stackprof"
|
202
|
+
out = Pathname.pwd + "tmp/typecheck-#{Process.pid}.stackprof"
|
203
|
+
puts ">> Profiling with stackprof: #{out}"
|
204
|
+
StackProf.run(out: out, raw: true, interval: 1000) do
|
205
|
+
typings = command.type_check_files(command_line_args, env)
|
206
|
+
end
|
207
|
+
|
208
|
+
when :majo
|
209
|
+
require "majo"
|
210
|
+
out = Pathname.pwd + "tmp/typecheck-#{Process.pid}.majo.csv"
|
211
|
+
puts ">> Profiling with majo: #{out}"
|
212
|
+
|
213
|
+
result = Majo.run do
|
214
|
+
typings = command.type_check_files(command_line_args, env)
|
215
|
+
end
|
216
|
+
|
217
|
+
out.open("w") do |io|
|
218
|
+
result.report(out: io, formatter: :csv)
|
219
|
+
end
|
220
|
+
|
221
|
+
when :dumpall
|
222
|
+
require "objspace"
|
223
|
+
out = Pathname.pwd + "tmp/dumpall-#{Process.pid}.json"
|
224
|
+
puts ">> Profiling with dumpall: #{out}"
|
225
|
+
ObjectSpace.trace_object_allocations_start
|
226
|
+
typings = command.type_check_files(command_line_args, env)
|
227
|
+
out.open('w+') do |io|
|
228
|
+
ObjectSpace.dump_all(output: io)
|
229
|
+
end
|
230
|
+
|
231
|
+
when :none
|
232
|
+
|
233
|
+
pp rbs_method_types: ObjectSpace.each_object(RBS::MethodType).count
|
234
|
+
GC.start(immediate_sweep: true, immediate_mark: true, full_mark: true)
|
235
|
+
|
236
|
+
pp defs: ObjectSpace.each_object(RBS::AST::Members::MethodDefinition).count
|
237
|
+
pp aliases: ObjectSpace.each_object(RBS::AST::Members::Alias).count
|
238
|
+
pp attr_reader: ObjectSpace.each_object(RBS::AST::Members::AttrReader).count
|
239
|
+
pp attr_writer: ObjectSpace.each_object(RBS::AST::Members::AttrWriter).count
|
240
|
+
pp attr_accessor: ObjectSpace.each_object(RBS::AST::Members::AttrAccessor).count
|
241
|
+
|
242
|
+
Steep.measure("type check", level: :fatal) do
|
243
|
+
GC.disable
|
244
|
+
typings = command.type_check_files(command_line_args, env)
|
245
|
+
|
246
|
+
pp steep_method_types: ObjectSpace.each_object(Steep::Interface::MethodType).count, rbs_method_types: ObjectSpace.each_object(RBS::MethodType).count
|
247
|
+
pp any: ObjectSpace.each_object(Steep::AST::Types::Any).count, void: ObjectSpace.each_object(Steep::AST::Types::Void).count, self: ObjectSpace.each_object(Steep::AST::Types::Self).count
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
typings.size
|
@@ -91,7 +91,7 @@ module Steep
|
|
91
91
|
name = match[:name] or raise
|
92
92
|
type = match[:type] or raise
|
93
93
|
|
94
|
-
method_type = factory.method_type(RBS::Parser.parse_method_type(type) || raise
|
94
|
+
method_type = factory.method_type(RBS::Parser.parse_method_type(type) || raise)
|
95
95
|
|
96
96
|
AST::Annotation::MethodType.new(name: name.to_sym,
|
97
97
|
type: method_type,
|
data/lib/steep/ast/builtin.rb
CHANGED
@@ -67,23 +67,23 @@ module Steep
|
|
67
67
|
Proc = Type.new("::Proc")
|
68
68
|
|
69
69
|
def self.nil_type
|
70
|
-
AST::Types::Nil.
|
70
|
+
AST::Types::Nil.instance
|
71
71
|
end
|
72
72
|
|
73
73
|
def self.any_type
|
74
|
-
AST::Types::Any.
|
74
|
+
AST::Types::Any.instance
|
75
75
|
end
|
76
76
|
|
77
77
|
def self.bool_type
|
78
|
-
AST::Types::Boolean.
|
78
|
+
AST::Types::Boolean.instance
|
79
79
|
end
|
80
80
|
|
81
81
|
def self.bottom_type
|
82
|
-
AST::Types::Bot.
|
82
|
+
AST::Types::Bot.instance
|
83
83
|
end
|
84
84
|
|
85
85
|
def self.top_type
|
86
|
-
AST::Types::Top.
|
86
|
+
AST::Types::Top.instance
|
87
87
|
end
|
88
88
|
|
89
89
|
def self.optional(type)
|
@@ -27,14 +27,15 @@ module Steep
|
|
27
27
|
def types(context, subtyping, type_vars)
|
28
28
|
resolver = RBS::Resolver::TypeNameResolver.new(subtyping.factory.env)
|
29
29
|
|
30
|
-
# @type var types: Array[Types::t]
|
30
|
+
# @type var types: Array[LocatedValue[Types::t]]
|
31
31
|
types = []
|
32
32
|
|
33
33
|
loc = type_location
|
34
34
|
|
35
35
|
while true
|
36
|
-
|
37
|
-
|
36
|
+
rbs_ty = RBS::Parser.parse_type(loc.buffer, range: loc.range, variables: type_vars) or break
|
37
|
+
rbs_loc = rbs_ty.location or raise
|
38
|
+
ty = rbs_ty.map_type_name {|name| resolver.resolve(name, context: context) || name.absolute! }
|
38
39
|
|
39
40
|
validator = Signature::Validator.new(checker: subtyping)
|
40
41
|
validator.rescue_validation_errors do
|
@@ -46,11 +47,11 @@ module Steep
|
|
46
47
|
end
|
47
48
|
|
48
49
|
ty = subtyping.factory.type(ty)
|
49
|
-
types << ty
|
50
|
+
types << LocatedValue.new(value: ty, location: rbs_loc)
|
50
51
|
|
51
|
-
match = RBS::Location.new(loc.buffer,
|
52
|
+
match = RBS::Location.new(loc.buffer, rbs_loc.end_pos, type_location.end_pos).source.match(/\A\s*,\s*/) or break
|
52
53
|
offset = match.length
|
53
|
-
loc = RBS::Location.new(loc.buffer,
|
54
|
+
loc = RBS::Location.new(loc.buffer, rbs_loc.end_pos + offset, type_location.end_pos)
|
54
55
|
end
|
55
56
|
|
56
57
|
types
|
data/lib/steep/ast/types/any.rb
CHANGED
@@ -2,11 +2,7 @@ module Steep
|
|
2
2
|
module AST
|
3
3
|
module Types
|
4
4
|
class Any
|
5
|
-
|
6
|
-
|
7
|
-
def initialize(location: nil)
|
8
|
-
@location = location
|
9
|
-
end
|
5
|
+
extend SharedInstance
|
10
6
|
|
11
7
|
def ==(other)
|
12
8
|
other.is_a?(Any)
|
@@ -33,10 +29,6 @@ module Steep
|
|
33
29
|
def level
|
34
30
|
[1]
|
35
31
|
end
|
36
|
-
|
37
|
-
def with_location(new_location)
|
38
|
-
self.class.new(location: new_location)
|
39
|
-
end
|
40
32
|
end
|
41
33
|
end
|
42
34
|
end
|
@@ -2,12 +2,8 @@ module Steep
|
|
2
2
|
module AST
|
3
3
|
module Types
|
4
4
|
class Boolean
|
5
|
-
|
6
|
-
|
7
|
-
def initialize(location: nil)
|
8
|
-
@location = location
|
9
|
-
end
|
10
|
-
|
5
|
+
extend SharedInstance
|
6
|
+
|
11
7
|
def ==(other)
|
12
8
|
other.is_a?(Boolean)
|
13
9
|
end
|
@@ -34,17 +30,13 @@ module Steep
|
|
34
30
|
[0]
|
35
31
|
end
|
36
32
|
|
37
|
-
def with_location(new_location)
|
38
|
-
self.class.new(location: new_location)
|
39
|
-
end
|
40
|
-
|
41
33
|
def back_type
|
42
|
-
Union.build(
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
34
|
+
Union.build(
|
35
|
+
types: [
|
36
|
+
Builtin::TrueClass.instance_type,
|
37
|
+
Builtin::FalseClass.instance_type
|
38
|
+
]
|
39
|
+
)
|
48
40
|
end
|
49
41
|
end
|
50
42
|
end
|
data/lib/steep/ast/types/bot.rb
CHANGED
@@ -2,12 +2,8 @@ module Steep
|
|
2
2
|
module AST
|
3
3
|
module Types
|
4
4
|
class Bot
|
5
|
-
|
6
|
-
|
7
|
-
def initialize(location: nil)
|
8
|
-
@location = location
|
9
|
-
end
|
10
|
-
|
5
|
+
extend SharedInstance
|
6
|
+
|
11
7
|
def ==(other)
|
12
8
|
other.is_a?(Bot)
|
13
9
|
end
|
@@ -33,10 +29,6 @@ module Steep
|
|
33
29
|
def level
|
34
30
|
[2]
|
35
31
|
end
|
36
|
-
|
37
|
-
def with_location(new_location)
|
38
|
-
self.class.new(location: new_location)
|
39
|
-
end
|
40
32
|
end
|
41
33
|
end
|
42
34
|
end
|
@@ -2,15 +2,7 @@ module Steep
|
|
2
2
|
module AST
|
3
3
|
module Types
|
4
4
|
class Class
|
5
|
-
|
6
|
-
|
7
|
-
def initialize(location: nil)
|
8
|
-
@location = location
|
9
|
-
end
|
10
|
-
|
11
|
-
def self.instance
|
12
|
-
@instance ||= new()
|
13
|
-
end
|
5
|
+
extend SharedInstance
|
14
6
|
|
15
7
|
def to_s
|
16
8
|
"class"
|
@@ -45,10 +37,6 @@ module Steep
|
|
45
37
|
def level
|
46
38
|
[0]
|
47
39
|
end
|
48
|
-
|
49
|
-
def with_location(new_location)
|
50
|
-
self.class.new(location: new_location)
|
51
|
-
end
|
52
40
|
end
|
53
41
|
end
|
54
42
|
end
|