steep 0.29.0 → 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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/lib/steep.rb +2 -1
- data/lib/steep/ast/types/factory.rb +34 -32
- data/lib/steep/project.rb +25 -0
- data/lib/steep/project/file_loader.rb +7 -2
- data/lib/steep/project/signature_file.rb +33 -0
- data/lib/steep/project/{file.rb → source_file.rb} +21 -51
- data/lib/steep/project/target.rb +31 -12
- data/lib/steep/server/code_worker.rb +30 -46
- data/lib/steep/server/master.rb +13 -30
- data/lib/steep/server/utils.rb +46 -13
- data/lib/steep/server/worker_process.rb +4 -2
- data/lib/steep/version.rb +1 -1
- data/smoke/toplevel/Steepfile +5 -0
- data/smoke/toplevel/a.rb +4 -0
- data/smoke/toplevel/a.rbs +3 -0
- metadata +7 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b5293cbc87834cee36e50cb66bab84e466a5182c1e868732b7bd3e685b2bd954
|
4
|
+
data.tar.gz: 7794e42573b5ac04c74780824213cfbe1ca255f1feaa4465a1066377d2647e0b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e723bf77a7452e0696c38d6d1797e71f246fb97d1b1f18082ba21b8eadb8174d6bcc4deda872898b5f39d162b91173c413cacfa28175018517170f8f2568bd70
|
7
|
+
data.tar.gz: 38dbe78df43706fe33d5350ad04524c25606955bcba5397ad18690717a60c59d361485ad2d5d3077787336d23902bd91ba9fa5b31e1933a93d1fe32747837688
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,12 @@
|
|
2
2
|
|
3
3
|
## master
|
4
4
|
|
5
|
+
## 0.30.0 (2020-10-03)
|
6
|
+
|
7
|
+
* Let top-level defs be methods of Object ([#227](https://github.com/soutaro/steep/pull/227))
|
8
|
+
* Fix error caused by attribute definitions ([#228](https://github.com/soutaro/steep/pull/228))
|
9
|
+
* LSP worker improvements ([#222](https://github.com/soutaro/steep/pull/222), [#223](https://github.com/soutaro/steep/pull/223), [#226](https://github.com/soutaro/steep/pull/226), [#229](https://github.com/soutaro/steep/pull/229))
|
10
|
+
|
5
11
|
## 0.29.0 (2020-09-28)
|
6
12
|
|
7
13
|
* Implement reasoning on `is_a?`, `nil?`, and `===` methods. ([#218](https://github.com/soutaro/steep/pull/218))
|
data/lib/steep.rb
CHANGED
@@ -83,7 +83,8 @@ require "steep/server/interaction_worker"
|
|
83
83
|
require "steep/server/master"
|
84
84
|
|
85
85
|
require "steep/project"
|
86
|
-
require "steep/project/
|
86
|
+
require "steep/project/signature_file"
|
87
|
+
require "steep/project/source_file"
|
87
88
|
require "steep/project/options"
|
88
89
|
require "steep/project/target"
|
89
90
|
require "steep/project/dsl"
|
@@ -344,41 +344,43 @@ module Steep
|
|
344
344
|
defined_in = method_def.defined_in
|
345
345
|
member = method_def.member
|
346
346
|
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
347
|
+
if member.is_a?(RBS::AST::Members::MethodDefinition)
|
348
|
+
case
|
349
|
+
when defined_in == RBS::BuiltinNames::Object.name && member.instance?
|
350
|
+
case method_name
|
351
|
+
when :is_a?, :kind_of?, :instance_of?
|
352
|
+
return method_type.with(
|
353
|
+
return_type: AST::Types::Logic::ReceiverIsArg.new(location: method_type.return_type.location)
|
354
|
+
)
|
355
|
+
when :nil?
|
356
|
+
return method_type.with(
|
357
|
+
return_type: AST::Types::Logic::ReceiverIsNil.new(location: method_type.return_type.location)
|
358
|
+
)
|
359
|
+
end
|
359
360
|
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
361
|
+
when defined_in == AST::Builtin::NilClass.module_name && member.instance?
|
362
|
+
case method_name
|
363
|
+
when :nil?
|
364
|
+
return method_type.with(
|
365
|
+
return_type: AST::Types::Logic::ReceiverIsNil.new(location: method_type.return_type.location)
|
366
|
+
)
|
367
|
+
end
|
367
368
|
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
369
|
+
when defined_in == RBS::BuiltinNames::BasicObject.name && member.instance?
|
370
|
+
case method_name
|
371
|
+
when :!
|
372
|
+
return method_type.with(
|
373
|
+
return_type: AST::Types::Logic::Not.new(location: method_type.return_type.location)
|
374
|
+
)
|
375
|
+
end
|
375
376
|
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
377
|
+
when defined_in == RBS::BuiltinNames::Module.name && member.instance?
|
378
|
+
case method_name
|
379
|
+
when :===
|
380
|
+
return method_type.with(
|
381
|
+
return_type: AST::Types::Logic::ArgIsReceiver.new(location: method_type.return_type.location)
|
382
|
+
)
|
383
|
+
end
|
382
384
|
end
|
383
385
|
end
|
384
386
|
end
|
data/lib/steep/project.rb
CHANGED
@@ -24,6 +24,31 @@ module Steep
|
|
24
24
|
(base_dir + path).cleanpath
|
25
25
|
end
|
26
26
|
|
27
|
+
def target_for_source_path(path)
|
28
|
+
targets.find do |target|
|
29
|
+
target.possible_source_file?(path)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def targets_for_path(path)
|
34
|
+
if target = target_for_source_path(path)
|
35
|
+
[target, []]
|
36
|
+
else
|
37
|
+
[
|
38
|
+
nil,
|
39
|
+
targets.select do |target|
|
40
|
+
target.possible_signature_file?(path)
|
41
|
+
end
|
42
|
+
]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def all_source_files
|
47
|
+
targets.each.with_object(Set[]) do |target, paths|
|
48
|
+
paths.merge(target.source_files.keys)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
27
52
|
def type_of_node(path:, line:, column:)
|
28
53
|
source_file = targets.map {|target| target.source_files[path] }.compact[0]
|
29
54
|
|
@@ -28,15 +28,20 @@ module Steep
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def load_sources(command_line_patterns)
|
31
|
+
loaded_paths = Set[]
|
32
|
+
|
31
33
|
project.targets.each do |target|
|
32
34
|
Steep.logger.tagged "target=#{target.name}" do
|
33
35
|
target_patterns = command_line_patterns.empty? ? target.source_patterns : command_line_patterns
|
34
36
|
|
35
|
-
each_path_in_patterns
|
37
|
+
each_path_in_patterns(target_patterns, ".rb") do |path|
|
36
38
|
if target.possible_source_file?(path)
|
37
|
-
|
39
|
+
if loaded_paths.include?(path)
|
40
|
+
Steep.logger.warn { "Skipping #{target} while loading #{path}... (Already loaded to another target.)" }
|
41
|
+
else
|
38
42
|
Steep.logger.info { "Adding source file: #{path}" }
|
39
43
|
target.add_source path, project.absolute_path(path).read
|
44
|
+
loaded_paths << path
|
40
45
|
end
|
41
46
|
end
|
42
47
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Steep
|
2
|
+
class Project
|
3
|
+
class SignatureFile
|
4
|
+
attr_reader :path
|
5
|
+
attr_reader :content
|
6
|
+
attr_reader :content_updated_at
|
7
|
+
|
8
|
+
attr_reader :status
|
9
|
+
|
10
|
+
ParseErrorStatus = Struct.new(:error, :timestamp, keyword_init: true)
|
11
|
+
DeclarationsStatus = Struct.new(:declarations, :timestamp, keyword_init: true)
|
12
|
+
|
13
|
+
def initialize(path:)
|
14
|
+
@path = path
|
15
|
+
self.content = ""
|
16
|
+
end
|
17
|
+
|
18
|
+
def content=(content)
|
19
|
+
@content_updated_at = Time.now
|
20
|
+
@content = content
|
21
|
+
@status = nil
|
22
|
+
end
|
23
|
+
|
24
|
+
def load!
|
25
|
+
buffer = RBS::Buffer.new(name: path, content: content)
|
26
|
+
decls = RBS::Parser.parse_signature(buffer)
|
27
|
+
@status = DeclarationsStatus.new(declarations: decls, timestamp: Time.now)
|
28
|
+
rescue RBS::Parser::SyntaxError, RBS::Parser::SemanticsError => exn
|
29
|
+
@status = ParseErrorStatus.new(error: exn, timestamp: Time.now)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -8,10 +8,10 @@ module Steep
|
|
8
8
|
|
9
9
|
attr_accessor :status
|
10
10
|
|
11
|
-
ParseErrorStatus = Struct.new(:error, keyword_init: true)
|
12
|
-
AnnotationSyntaxErrorStatus = Struct.new(:error, :location, keyword_init: true)
|
11
|
+
ParseErrorStatus = Struct.new(:error, :timestamp, keyword_init: true)
|
12
|
+
AnnotationSyntaxErrorStatus = Struct.new(:error, :location, :timestamp, keyword_init: true)
|
13
13
|
TypeCheckStatus = Struct.new(:typing, :source, :timestamp, keyword_init: true)
|
14
|
-
TypeCheckErrorStatus = Struct.new(:error, keyword_init: true)
|
14
|
+
TypeCheckErrorStatus = Struct.new(:error, :timestamp, keyword_init: true)
|
15
15
|
|
16
16
|
def initialize(path:)
|
17
17
|
@path = path
|
@@ -20,11 +20,9 @@ module Steep
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def content=(content)
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
@status = nil
|
27
|
-
end
|
23
|
+
@content_updated_at = Time.now
|
24
|
+
@content = content
|
25
|
+
@status = nil
|
28
26
|
end
|
29
27
|
|
30
28
|
def errors
|
@@ -55,12 +53,14 @@ module Steep
|
|
55
53
|
context = TypeInference::Context.new(
|
56
54
|
block_context: nil,
|
57
55
|
module_context: TypeInference::Context::ModuleContext.new(
|
58
|
-
instance_type:
|
59
|
-
module_type:
|
56
|
+
instance_type: AST::Builtin::Object.instance_type,
|
57
|
+
module_type: AST::Builtin::Object.module_type,
|
60
58
|
implement_name: nil,
|
61
59
|
current_namespace: RBS::Namespace.root,
|
62
60
|
const_env: const_env,
|
63
|
-
class_name:
|
61
|
+
class_name: AST::Builtin::Object.module_name,
|
62
|
+
instance_definition: subtyping.factory.definition_builder.build_instance(AST::Builtin::Object.module_name),
|
63
|
+
module_definition: subtyping.factory.definition_builder.build_singleton(AST::Builtin::Object.module_name)
|
64
64
|
),
|
65
65
|
method_context: nil,
|
66
66
|
break_context: nil,
|
@@ -86,31 +86,31 @@ module Steep
|
|
86
86
|
|
87
87
|
def type_check(subtyping, env_updated_at)
|
88
88
|
# skip type check
|
89
|
-
return false if status
|
89
|
+
return false if status && env_updated_at <= status.timestamp
|
90
|
+
|
91
|
+
now = Time.now
|
90
92
|
|
91
93
|
parse(subtyping.factory) do |source|
|
92
94
|
typing = self.class.type_check(source, subtyping: subtyping)
|
93
|
-
@status = TypeCheckStatus.new(
|
94
|
-
typing: typing,
|
95
|
-
source: source,
|
96
|
-
timestamp: Time.now
|
97
|
-
)
|
95
|
+
@status = TypeCheckStatus.new(typing: typing, source: source, timestamp: now)
|
98
96
|
rescue RBS::NoTypeFoundError,
|
99
97
|
RBS::NoMixinFoundError,
|
100
98
|
RBS::NoSuperclassFoundError,
|
101
99
|
RBS::DuplicatedMethodDefinitionError,
|
102
100
|
RBS::InvalidTypeApplicationError => exn
|
103
101
|
# Skip logging known signature errors (they are handled with load_signatures(validate: true))
|
104
|
-
@status = TypeCheckErrorStatus.new(error: exn)
|
102
|
+
@status = TypeCheckErrorStatus.new(error: exn, timestamp: now)
|
105
103
|
rescue => exn
|
106
104
|
Steep.log_error(exn)
|
107
|
-
@status = TypeCheckErrorStatus.new(error: exn)
|
105
|
+
@status = TypeCheckErrorStatus.new(error: exn, timestamp: now)
|
108
106
|
end
|
109
107
|
|
110
108
|
true
|
111
109
|
end
|
112
110
|
|
113
111
|
def parse(factory)
|
112
|
+
now = Time.now
|
113
|
+
|
114
114
|
if status.is_a?(TypeCheckStatus)
|
115
115
|
yield status.source
|
116
116
|
else
|
@@ -118,40 +118,10 @@ module Steep
|
|
118
118
|
end
|
119
119
|
rescue AnnotationParser::SyntaxError => exn
|
120
120
|
Steep.logger.warn { "Annotation syntax error on #{path}: #{exn.inspect}" }
|
121
|
-
@status = AnnotationSyntaxErrorStatus.new(error: exn, location: exn.location)
|
121
|
+
@status = AnnotationSyntaxErrorStatus.new(error: exn, location: exn.location, timestamp: now)
|
122
122
|
rescue ::Parser::SyntaxError, EncodingError => exn
|
123
123
|
Steep.logger.warn { "Source parsing error on #{path}: #{exn.inspect}" }
|
124
|
-
@status = ParseErrorStatus.new(error: exn)
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
class SignatureFile
|
129
|
-
attr_reader :path
|
130
|
-
attr_reader :content
|
131
|
-
attr_reader :content_updated_at
|
132
|
-
|
133
|
-
attr_reader :status
|
134
|
-
|
135
|
-
ParseErrorStatus = Struct.new(:error, keyword_init: true)
|
136
|
-
DeclarationsStatus = Struct.new(:declarations, keyword_init: true)
|
137
|
-
|
138
|
-
def initialize(path:)
|
139
|
-
@path = path
|
140
|
-
self.content = ""
|
141
|
-
end
|
142
|
-
|
143
|
-
def content=(content)
|
144
|
-
@content_updated_at = Time.now
|
145
|
-
@content = content
|
146
|
-
@status = nil
|
147
|
-
end
|
148
|
-
|
149
|
-
def load!
|
150
|
-
buffer = RBS::Buffer.new(name: path, content: content)
|
151
|
-
decls = RBS::Parser.parse_signature(buffer)
|
152
|
-
@status = DeclarationsStatus.new(declarations: decls)
|
153
|
-
rescue RBS::Parser::SyntaxError, RBS::Parser::SemanticsError => exn
|
154
|
-
@status = ParseErrorStatus.new(error: exn)
|
124
|
+
@status = ParseErrorStatus.new(error: exn, timestamp: now)
|
155
125
|
end
|
156
126
|
end
|
157
127
|
end
|
data/lib/steep/project/target.rb
CHANGED
@@ -29,9 +29,15 @@ module Steep
|
|
29
29
|
@signature_files = {}
|
30
30
|
end
|
31
31
|
|
32
|
-
def add_source(path, content)
|
32
|
+
def add_source(path, content = "")
|
33
33
|
file = SourceFile.new(path: path)
|
34
|
-
|
34
|
+
|
35
|
+
if block_given?
|
36
|
+
file.content = yield
|
37
|
+
else
|
38
|
+
file.content = content
|
39
|
+
end
|
40
|
+
|
35
41
|
source_files[path] = file
|
36
42
|
end
|
37
43
|
|
@@ -39,14 +45,22 @@ module Steep
|
|
39
45
|
source_files.delete(path)
|
40
46
|
end
|
41
47
|
|
42
|
-
def update_source(path, content)
|
48
|
+
def update_source(path, content = nil)
|
43
49
|
file = source_files[path]
|
44
|
-
|
50
|
+
if block_given?
|
51
|
+
file.content = yield(file.content)
|
52
|
+
else
|
53
|
+
file.content = content || file.content
|
54
|
+
end
|
45
55
|
end
|
46
56
|
|
47
|
-
def add_signature(path, content)
|
57
|
+
def add_signature(path, content = "")
|
48
58
|
file = SignatureFile.new(path: path)
|
49
|
-
|
59
|
+
if block_given?
|
60
|
+
file.content = yield
|
61
|
+
else
|
62
|
+
file.content = content
|
63
|
+
end
|
50
64
|
signature_files[path] = file
|
51
65
|
end
|
52
66
|
|
@@ -54,9 +68,13 @@ module Steep
|
|
54
68
|
signature_files.delete(path)
|
55
69
|
end
|
56
70
|
|
57
|
-
def update_signature(path, content)
|
71
|
+
def update_signature(path, content = nil)
|
58
72
|
file = signature_files[path]
|
59
|
-
|
73
|
+
if block_given?
|
74
|
+
file.content = yield(file.content)
|
75
|
+
else
|
76
|
+
file.content = content || file.content
|
77
|
+
end
|
60
78
|
end
|
61
79
|
|
62
80
|
def source_file?(path)
|
@@ -115,6 +133,7 @@ module Steep
|
|
115
133
|
when TypeCheckStatus
|
116
134
|
status.timestamp
|
117
135
|
end
|
136
|
+
now = Time.now
|
118
137
|
|
119
138
|
updated_files = []
|
120
139
|
|
@@ -151,11 +170,11 @@ module Steep
|
|
151
170
|
validator.validate()
|
152
171
|
|
153
172
|
if validator.no_error?
|
154
|
-
yield env, check,
|
173
|
+
yield env, check, now
|
155
174
|
else
|
156
175
|
@status = SignatureValidationErrorStatus.new(
|
157
176
|
errors: validator.each_error.to_a,
|
158
|
-
timestamp:
|
177
|
+
timestamp: now
|
159
178
|
)
|
160
179
|
end
|
161
180
|
else
|
@@ -169,11 +188,11 @@ module Steep
|
|
169
188
|
location: exn.decls[0].location
|
170
189
|
)
|
171
190
|
],
|
172
|
-
timestamp:
|
191
|
+
timestamp: now
|
173
192
|
)
|
174
193
|
rescue => exn
|
175
194
|
Steep.log_error exn
|
176
|
-
@status = SignatureOtherErrorStatus.new(error: exn, timestamp:
|
195
|
+
@status = SignatureOtherErrorStatus.new(error: exn, timestamp: now)
|
177
196
|
end
|
178
197
|
end
|
179
198
|
|
@@ -5,47 +5,32 @@ module Steep
|
|
5
5
|
|
6
6
|
include Utils
|
7
7
|
|
8
|
-
attr_reader :
|
8
|
+
attr_reader :typecheck_paths
|
9
9
|
attr_reader :queue
|
10
10
|
|
11
11
|
def initialize(project:, reader:, writer:, queue: Queue.new)
|
12
12
|
super(project: project, reader: reader, writer: writer)
|
13
13
|
|
14
|
-
@
|
14
|
+
@typecheck_paths = Set[]
|
15
15
|
@queue = queue
|
16
16
|
end
|
17
17
|
|
18
|
-
def enqueue_type_check(target:, path
|
19
|
-
Steep.logger.info "Enqueueing type check: #{
|
20
|
-
|
21
|
-
queue << [path, version, target]
|
22
|
-
end
|
23
|
-
|
24
|
-
def each_type_check_subject(path:, version:)
|
25
|
-
case
|
26
|
-
when !(updated_targets = project.targets.select {|target| target.signature_file?(path) }).empty?
|
27
|
-
updated_targets.each do |target|
|
28
|
-
target_files.each_key do |path|
|
29
|
-
if target.source_file?(path)
|
30
|
-
yield target, path, target_files[path]
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
when target = project.targets.find {|target| target.source_file?(path) }
|
36
|
-
if target_files.key?(path)
|
37
|
-
yield target, path, version
|
38
|
-
end
|
39
|
-
end
|
18
|
+
def enqueue_type_check(target:, path:)
|
19
|
+
Steep.logger.info "Enqueueing type check: #{target.name}::#{path}..."
|
20
|
+
queue << [target, path]
|
40
21
|
end
|
41
22
|
|
42
23
|
def typecheck_file(path, target)
|
43
|
-
Steep.logger.info "Starting type checking: #{
|
24
|
+
Steep.logger.info "Starting type checking: #{target.name}::#{path}..."
|
44
25
|
|
45
26
|
source = target.source_files[path]
|
46
27
|
target.type_check(target_sources: [source], validate_signatures: false)
|
47
28
|
|
48
|
-
|
29
|
+
if target.status.is_a?(Project::Target::TypeCheckStatus) && target.status.type_check_sources.empty?
|
30
|
+
Steep.logger.debug "Skipped type checking: #{target.name}::#{path}"
|
31
|
+
else
|
32
|
+
Steep.logger.info "Finished type checking: #{target.name}::#{path}"
|
33
|
+
end
|
49
34
|
|
50
35
|
diagnostics = source_diagnostics(source, target.options)
|
51
36
|
|
@@ -109,8 +94,8 @@ module Steep
|
|
109
94
|
# Don't respond to initialize request, but start type checking.
|
110
95
|
project.targets.each do |target|
|
111
96
|
target.source_files.each_key do |path|
|
112
|
-
if
|
113
|
-
enqueue_type_check(target: target, path: path
|
97
|
+
if typecheck_paths.include?(path)
|
98
|
+
enqueue_type_check(target: target, path: path)
|
114
99
|
end
|
115
100
|
end
|
116
101
|
end
|
@@ -118,35 +103,34 @@ module Steep
|
|
118
103
|
when "workspace/executeCommand"
|
119
104
|
if request[:params][:command] == "steep/registerSourceToWorker"
|
120
105
|
paths = request[:params][:arguments].map {|arg| source_path(URI.parse(arg)) }
|
121
|
-
paths
|
122
|
-
target_files[path] = 0
|
123
|
-
end
|
106
|
+
typecheck_paths.merge(paths)
|
124
107
|
end
|
125
108
|
|
126
109
|
when "textDocument/didChange"
|
127
|
-
update_source(request) do |path,
|
128
|
-
|
129
|
-
|
110
|
+
update_source(request) do |path, _|
|
111
|
+
source_target, signature_targets = project.targets_for_path(path)
|
112
|
+
|
113
|
+
if source_target
|
114
|
+
if typecheck_paths.include?(path)
|
115
|
+
enqueue_type_check(target: source_target, path: path)
|
116
|
+
end
|
130
117
|
end
|
131
|
-
end
|
132
118
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
119
|
+
signature_targets.each do |target|
|
120
|
+
target.source_files.each_key do |source_path|
|
121
|
+
if typecheck_paths.include?(source_path)
|
122
|
+
enqueue_type_check(target: target, path: source_path)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
137
126
|
end
|
138
127
|
end
|
139
128
|
end
|
140
129
|
|
141
130
|
def handle_job(job)
|
142
|
-
|
131
|
+
target, path = job
|
143
132
|
|
144
|
-
path,
|
145
|
-
if !version || target_files[path] == version
|
146
|
-
typecheck_file(path, target)
|
147
|
-
else
|
148
|
-
Steep.logger.info "Skipping type check: #{path}@#{target.name}, queued version=#{version}, latest version=#{target_files[path]}"
|
149
|
-
end
|
133
|
+
typecheck_file(path, target)
|
150
134
|
end
|
151
135
|
end
|
152
136
|
end
|
data/lib/steep/server/master.rb
CHANGED
@@ -14,6 +14,8 @@ module Steep
|
|
14
14
|
attr_reader :signature_worker
|
15
15
|
attr_reader :code_workers
|
16
16
|
|
17
|
+
include Utils
|
18
|
+
|
17
19
|
def initialize(project:, reader:, writer:, interaction_worker:, signature_worker:, code_workers:, queue: Queue.new)
|
18
20
|
@project = project
|
19
21
|
@reader = reader
|
@@ -27,19 +29,24 @@ module Steep
|
|
27
29
|
end
|
28
30
|
|
29
31
|
def start
|
30
|
-
source_paths = project.
|
32
|
+
source_paths = project.all_source_files
|
31
33
|
bin_size = (source_paths.size / code_workers.size) + 1
|
32
34
|
source_paths.each_slice(bin_size).with_index do |paths, index|
|
33
35
|
register_code_to_worker(paths, worker: code_workers[index])
|
34
36
|
end
|
35
37
|
|
38
|
+
tags = Steep.logger.formatter.current_tags.dup
|
39
|
+
tags << "master"
|
40
|
+
|
36
41
|
Thread.new do
|
42
|
+
Steep.logger.formatter.push_tags(*tags, "from-worker@interaction")
|
37
43
|
interaction_worker.reader.read do |message|
|
38
44
|
process_message_from_worker(message)
|
39
45
|
end
|
40
46
|
end
|
41
47
|
|
42
48
|
Thread.new do
|
49
|
+
Steep.logger.formatter.push_tags(*tags, "from-worker@signature")
|
43
50
|
signature_worker.reader.read do |message|
|
44
51
|
process_message_from_worker(message)
|
45
52
|
end
|
@@ -47,6 +54,7 @@ module Steep
|
|
47
54
|
|
48
55
|
code_workers.each do |worker|
|
49
56
|
Thread.new do
|
57
|
+
Steep.logger.formatter.push_tags(*tags, "from-worker@#{worker.name}")
|
50
58
|
worker.reader.read do |message|
|
51
59
|
process_message_from_worker(message)
|
52
60
|
end
|
@@ -54,6 +62,7 @@ module Steep
|
|
54
62
|
end
|
55
63
|
|
56
64
|
Thread.new do
|
65
|
+
Steep.logger.formatter.push_tags(*tags, "from-client")
|
57
66
|
reader.read do |request|
|
58
67
|
process_message_from_client(request)
|
59
68
|
end
|
@@ -97,7 +106,7 @@ module Steep
|
|
97
106
|
result: LSP::Interface::InitializeResult.new(
|
98
107
|
capabilities: LSP::Interface::ServerCapabilities.new(
|
99
108
|
text_document_sync: LSP::Interface::TextDocumentSyncOptions.new(
|
100
|
-
change: LSP::Constant::TextDocumentSyncKind::
|
109
|
+
change: LSP::Constant::TextDocumentSyncKind::INCREMENTAL
|
101
110
|
),
|
102
111
|
hover_provider: true,
|
103
112
|
completion_provider: LSP::Interface::CompletionOptions.new(
|
@@ -112,36 +121,10 @@ module Steep
|
|
112
121
|
end
|
113
122
|
|
114
123
|
when "textDocument/didChange"
|
124
|
+
update_source(message)
|
125
|
+
|
115
126
|
uri = URI.parse(message[:params][:textDocument][:uri])
|
116
127
|
path = project.relative_path(Pathname(uri.path))
|
117
|
-
text = message[:params][:contentChanges][0][:text]
|
118
|
-
|
119
|
-
project.targets.each do |target|
|
120
|
-
case
|
121
|
-
when target.source_file?(path)
|
122
|
-
if text.empty? && !path.file?
|
123
|
-
Steep.logger.info { "Deleting source file: #{path}..." }
|
124
|
-
target.remove_source(path)
|
125
|
-
else
|
126
|
-
Steep.logger.info { "Updating source file: #{path}..." }
|
127
|
-
target.update_source(path, text)
|
128
|
-
end
|
129
|
-
when target.possible_source_file?(path)
|
130
|
-
Steep.logger.info { "Adding source file: #{path}..." }
|
131
|
-
target.add_source(path, text)
|
132
|
-
when target.signature_file?(path)
|
133
|
-
if text.empty? && !path.file?
|
134
|
-
Steep.logger.info { "Deleting signature file: #{path}..." }
|
135
|
-
target.remove_signature(path)
|
136
|
-
else
|
137
|
-
Steep.logger.info { "Updating signature file: #{path}..." }
|
138
|
-
target.update_signature(path, text)
|
139
|
-
end
|
140
|
-
when target.possible_signature_file?(path)
|
141
|
-
Steep.logger.info { "Adding signature file: #{path}..." }
|
142
|
-
target.add_signature(path, text)
|
143
|
-
end
|
144
|
-
end
|
145
128
|
|
146
129
|
unless registered_path?(path)
|
147
130
|
register_code_to_worker [path], worker: least_busy_worker()
|
data/lib/steep/server/utils.rb
CHANGED
@@ -7,23 +7,56 @@ module Steep
|
|
7
7
|
project.relative_path(Pathname(uri.path))
|
8
8
|
end
|
9
9
|
|
10
|
+
def apply_change(change, text)
|
11
|
+
range = change[:range]
|
12
|
+
|
13
|
+
if range
|
14
|
+
text = text.dup
|
15
|
+
|
16
|
+
buf = AST::Buffer.new(name: :_, content: text)
|
17
|
+
|
18
|
+
start_pos = buf.loc_to_pos(range[:start].yield_self {|pos| [pos[:line]+1, pos[:character]] })
|
19
|
+
end_pos = buf.loc_to_pos(range[:end].yield_self {|pos| [pos[:line]+1, pos[:character]] })
|
20
|
+
|
21
|
+
text[start_pos...end_pos] = change[:text]
|
22
|
+
text
|
23
|
+
else
|
24
|
+
change[:text]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
10
28
|
def update_source(request)
|
11
29
|
path = source_path(URI.parse(request[:params][:textDocument][:uri]))
|
12
|
-
text = request[:params][:contentChanges][0][:text]
|
13
30
|
version = request[:params][:textDocument][:version]
|
31
|
+
Steep.logger.info { "Updating source: path=#{path}, version=#{version}..." }
|
32
|
+
|
33
|
+
changes = request[:params][:contentChanges]
|
34
|
+
|
35
|
+
source_target, signature_targets = project.targets_for_path(path)
|
36
|
+
|
37
|
+
if source_target
|
38
|
+
changes.each do |change|
|
39
|
+
case
|
40
|
+
when source_target.source_file?(path)
|
41
|
+
Steep.logger.debug { "Updating source in #{source_target.name}: path=#{path}" }
|
42
|
+
source_target.update_source(path) {|text| apply_change(change, text) }
|
43
|
+
when source_target.possible_source_file?(path)
|
44
|
+
Steep.logger.debug { "Adding source to #{source_target.name}: path=#{path}" }
|
45
|
+
source_target.add_source(path, change[:text])
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
14
49
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
when target.possible_signature_file?(path)
|
26
|
-
target.add_signature path, text
|
50
|
+
signature_targets.each do |target|
|
51
|
+
changes.each do |change|
|
52
|
+
case
|
53
|
+
when target.signature_file?(path)
|
54
|
+
Steep.logger.debug { "Updating signature in #{target.name}: path=#{path}" }
|
55
|
+
target.update_signature(path) {|text| apply_change(change, text) }
|
56
|
+
when target.possible_signature_file?(path)
|
57
|
+
Steep.logger.debug { "Adding signature to #{target.name}: path=#{path}" }
|
58
|
+
target.add_signature(path, change[:text])
|
59
|
+
end
|
27
60
|
end
|
28
61
|
end
|
29
62
|
|
@@ -5,13 +5,15 @@ module Steep
|
|
5
5
|
attr_reader :writer
|
6
6
|
attr_reader :stderr
|
7
7
|
|
8
|
+
attr_reader :name
|
8
9
|
attr_reader :wait_thread
|
9
10
|
|
10
|
-
def initialize(reader:, writer:, stderr:, wait_thread:)
|
11
|
+
def initialize(reader:, writer:, stderr:, wait_thread:, name:)
|
11
12
|
@reader = reader
|
12
13
|
@writer = writer
|
13
14
|
@stderr = stderr
|
14
15
|
@wait_thread = wait_thread
|
16
|
+
@name = name
|
15
17
|
end
|
16
18
|
|
17
19
|
def self.spawn_worker(type, name:, steepfile:)
|
@@ -33,7 +35,7 @@ module Steep
|
|
33
35
|
writer = LanguageServer::Protocol::Transport::Io::Writer.new(stdin)
|
34
36
|
reader = LanguageServer::Protocol::Transport::Io::Reader.new(stdout)
|
35
37
|
|
36
|
-
new(reader: reader, writer: writer, stderr: stderr, wait_thread: thread)
|
38
|
+
new(reader: reader, writer: writer, stderr: stderr, wait_thread: thread, name: name)
|
37
39
|
end
|
38
40
|
|
39
41
|
def self.spawn_code_workers(steepfile:, count: [Etc.nprocessors-3, 1].max)
|
data/lib/steep/version.rb
CHANGED
data/smoke/toplevel/a.rb
ADDED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: steep
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.30.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Soutaro Matsumoto
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-10-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: parser
|
@@ -187,10 +187,11 @@ files:
|
|
187
187
|
- lib/steep/project.rb
|
188
188
|
- lib/steep/project/completion_provider.rb
|
189
189
|
- lib/steep/project/dsl.rb
|
190
|
-
- lib/steep/project/file.rb
|
191
190
|
- lib/steep/project/file_loader.rb
|
192
191
|
- lib/steep/project/hover_content.rb
|
193
192
|
- lib/steep/project/options.rb
|
193
|
+
- lib/steep/project/signature_file.rb
|
194
|
+
- lib/steep/project/source_file.rb
|
194
195
|
- lib/steep/project/target.rb
|
195
196
|
- lib/steep/server/base_worker.rb
|
196
197
|
- lib/steep/server/code_worker.rb
|
@@ -347,6 +348,9 @@ files:
|
|
347
348
|
- smoke/super/Steepfile
|
348
349
|
- smoke/super/a.rb
|
349
350
|
- smoke/super/a.rbs
|
351
|
+
- smoke/toplevel/Steepfile
|
352
|
+
- smoke/toplevel/a.rb
|
353
|
+
- smoke/toplevel/a.rbs
|
350
354
|
- smoke/type_case/Steepfile
|
351
355
|
- smoke/type_case/a.rb
|
352
356
|
- smoke/yield/Steepfile
|