steep 0.25.0 → 0.31.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +47 -0
  3. data/bin/smoke_runner.rb +3 -4
  4. data/bin/steep-prof +1 -2
  5. data/lib/steep.rb +6 -4
  6. data/lib/steep/annotation_parser.rb +2 -4
  7. data/lib/steep/ast/builtin.rb +11 -21
  8. data/lib/steep/ast/types.rb +5 -3
  9. data/lib/steep/ast/types/any.rb +1 -3
  10. data/lib/steep/ast/types/boolean.rb +1 -3
  11. data/lib/steep/ast/types/bot.rb +1 -3
  12. data/lib/steep/ast/types/class.rb +2 -2
  13. data/lib/steep/ast/types/factory.rb +265 -90
  14. data/lib/steep/ast/types/helper.rb +6 -0
  15. data/lib/steep/ast/types/instance.rb +2 -2
  16. data/lib/steep/ast/types/intersection.rb +20 -13
  17. data/lib/steep/ast/types/literal.rb +1 -3
  18. data/lib/steep/ast/types/logic.rb +63 -0
  19. data/lib/steep/ast/types/name.rb +15 -67
  20. data/lib/steep/ast/types/nil.rb +1 -3
  21. data/lib/steep/ast/types/proc.rb +5 -2
  22. data/lib/steep/ast/types/record.rb +9 -4
  23. data/lib/steep/ast/types/self.rb +1 -1
  24. data/lib/steep/ast/types/top.rb +1 -3
  25. data/lib/steep/ast/types/tuple.rb +5 -3
  26. data/lib/steep/ast/types/union.rb +13 -9
  27. data/lib/steep/ast/types/var.rb +2 -2
  28. data/lib/steep/ast/types/void.rb +1 -3
  29. data/lib/steep/errors.rb +14 -0
  30. data/lib/steep/interface/interface.rb +5 -62
  31. data/lib/steep/interface/method_type.rb +394 -93
  32. data/lib/steep/interface/substitution.rb +48 -6
  33. data/lib/steep/module_helper.rb +25 -0
  34. data/lib/steep/project.rb +25 -0
  35. data/lib/steep/project/completion_provider.rb +57 -58
  36. data/lib/steep/project/file_loader.rb +7 -2
  37. data/lib/steep/project/hover_content.rb +92 -83
  38. data/lib/steep/project/signature_file.rb +33 -0
  39. data/lib/steep/project/{file.rb → source_file.rb} +24 -54
  40. data/lib/steep/project/target.rb +31 -12
  41. data/lib/steep/server/base_worker.rb +5 -3
  42. data/lib/steep/server/code_worker.rb +31 -45
  43. data/lib/steep/server/interaction_worker.rb +42 -38
  44. data/lib/steep/server/master.rb +23 -31
  45. data/lib/steep/server/utils.rb +46 -13
  46. data/lib/steep/server/worker_process.rb +4 -2
  47. data/lib/steep/signature/validator.rb +3 -3
  48. data/lib/steep/source.rb +59 -2
  49. data/lib/steep/subtyping/check.rb +36 -50
  50. data/lib/steep/subtyping/constraints.rb +8 -0
  51. data/lib/steep/type_construction.rb +388 -366
  52. data/lib/steep/type_inference/block_params.rb +5 -0
  53. data/lib/steep/type_inference/constant_env.rb +2 -5
  54. data/lib/steep/type_inference/logic_type_interpreter.rb +219 -0
  55. data/lib/steep/type_inference/type_env.rb +2 -2
  56. data/lib/steep/version.rb +1 -1
  57. data/smoke/alias/a.rb +1 -1
  58. data/smoke/case/a.rb +1 -1
  59. data/smoke/hash/d.rb +1 -1
  60. data/smoke/if/a.rb +1 -1
  61. data/smoke/module/a.rb +1 -1
  62. data/smoke/rescue/a.rb +4 -13
  63. data/smoke/toplevel/Steepfile +5 -0
  64. data/smoke/toplevel/a.rb +4 -0
  65. data/smoke/toplevel/a.rbs +3 -0
  66. data/smoke/type_case/a.rb +0 -7
  67. data/steep.gemspec +3 -3
  68. metadata +17 -13
  69. data/lib/steep/ast/method_type.rb +0 -126
  70. data/lib/steep/ast/namespace.rb +0 -80
  71. data/lib/steep/names.rb +0 -86
@@ -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
@@ -23,22 +25,28 @@ module Steep
23
25
  @signature_worker = signature_worker
24
26
  @code_workers = code_workers
25
27
  @worker_to_paths = {}
28
+ @shutdown_request_id = nil
26
29
  end
27
30
 
28
31
  def start
29
- source_paths = project.targets.flat_map {|target| target.source_files.keys }
32
+ source_paths = project.all_source_files
30
33
  bin_size = (source_paths.size / code_workers.size) + 1
31
34
  source_paths.each_slice(bin_size).with_index do |paths, index|
32
35
  register_code_to_worker(paths, worker: code_workers[index])
33
36
  end
34
37
 
38
+ tags = Steep.logger.formatter.current_tags.dup
39
+ tags << "master"
40
+
35
41
  Thread.new do
42
+ Steep.logger.formatter.push_tags(*tags, "from-worker@interaction")
36
43
  interaction_worker.reader.read do |message|
37
44
  process_message_from_worker(message)
38
45
  end
39
46
  end
40
47
 
41
48
  Thread.new do
49
+ Steep.logger.formatter.push_tags(*tags, "from-worker@signature")
42
50
  signature_worker.reader.read do |message|
43
51
  process_message_from_worker(message)
44
52
  end
@@ -46,6 +54,7 @@ module Steep
46
54
 
47
55
  code_workers.each do |worker|
48
56
  Thread.new do
57
+ Steep.logger.formatter.push_tags(*tags, "from-worker@#{worker.name}")
49
58
  worker.reader.read do |message|
50
59
  process_message_from_worker(message)
51
60
  end
@@ -53,13 +62,21 @@ module Steep
53
62
  end
54
63
 
55
64
  Thread.new do
65
+ Steep.logger.formatter.push_tags(*tags, "from-client")
56
66
  reader.read do |request|
57
67
  process_message_from_client(request)
58
68
  end
59
69
  end
60
70
 
61
71
  while job = queue.pop
62
- writer.write(job)
72
+ if @shutdown_request_id
73
+ if job[:id] == @shutdown_request_id
74
+ writer.write(job)
75
+ break
76
+ end
77
+ else
78
+ writer.write(job)
79
+ end
63
80
  end
64
81
 
65
82
  writer.io.close
@@ -89,7 +106,7 @@ module Steep
89
106
  result: LSP::Interface::InitializeResult.new(
90
107
  capabilities: LSP::Interface::ServerCapabilities.new(
91
108
  text_document_sync: LSP::Interface::TextDocumentSyncOptions.new(
92
- change: LSP::Constant::TextDocumentSyncKind::FULL
109
+ change: LSP::Constant::TextDocumentSyncKind::INCREMENTAL
93
110
  ),
94
111
  hover_provider: true,
95
112
  completion_provider: LSP::Interface::CompletionOptions.new(
@@ -104,36 +121,10 @@ module Steep
104
121
  end
105
122
 
106
123
  when "textDocument/didChange"
124
+ update_source(message)
125
+
107
126
  uri = URI.parse(message[:params][:textDocument][:uri])
108
127
  path = project.relative_path(Pathname(uri.path))
109
- text = message[:params][:contentChanges][0][:text]
110
-
111
- project.targets.each do |target|
112
- case
113
- when target.source_file?(path)
114
- if text.empty? && !path.file?
115
- Steep.logger.info { "Deleting source file: #{path}..." }
116
- target.remove_source(path)
117
- else
118
- Steep.logger.info { "Updating source file: #{path}..." }
119
- target.update_source(path, text)
120
- end
121
- when target.possible_source_file?(path)
122
- Steep.logger.info { "Adding source file: #{path}..." }
123
- target.add_source(path, text)
124
- when target.signature_file?(path)
125
- if text.empty? && !path.file?
126
- Steep.logger.info { "Deleting signature file: #{path}..." }
127
- target.remove_signature(path)
128
- else
129
- Steep.logger.info { "Updating signature file: #{path}..." }
130
- target.update_signature(path, text)
131
- end
132
- when target.possible_signature_file?(path)
133
- Steep.logger.info { "Adding signature file: #{path}..." }
134
- target.add_signature(path, text)
135
- end
136
- end
137
128
 
138
129
  unless registered_path?(path)
139
130
  register_code_to_worker [path], worker: least_busy_worker()
@@ -154,6 +145,7 @@ module Steep
154
145
 
155
146
  when "shutdown"
156
147
  queue << { id: id, result: nil }
148
+ @shutdown_request_id = id
157
149
 
158
150
  when "exit"
159
151
  queue << nil
@@ -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
- Steep.logger.debug "Updateing source: path=#{path}, version=#{version}, size=#{text.bytesize}"
16
-
17
- project.targets.each do |target|
18
- case
19
- when target.source_file?(path)
20
- target.update_source path, text
21
- when target.possible_source_file?(path)
22
- target.add_source path, text
23
- when target.signature_file?(path)
24
- target.update_signature path, text
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)
@@ -130,19 +130,19 @@ module Steep
130
130
  yield
131
131
  rescue RBS::InvalidTypeApplicationError => exn
132
132
  @errors << Errors::InvalidTypeApplicationError.new(
133
- name: factory.type_name(exn.type_name),
133
+ name: exn.type_name,
134
134
  args: exn.args.map {|ty| factory.type(ty) },
135
135
  params: exn.params,
136
136
  location: exn.location
137
137
  )
138
138
  rescue RBS::NoTypeFoundError, RBS::NoSuperclassFoundError, RBS::NoMixinFoundError => exn
139
139
  @errors << Errors::UnknownTypeNameError.new(
140
- name: factory.type_name(exn.type_name),
140
+ name: exn.type_name,
141
141
  location: exn.location
142
142
  )
143
143
  rescue RBS::InvalidOverloadMethodError => exn
144
144
  @errors << Errors::InvalidMethodOverloadError.new(
145
- class_name: factory.type_name(exn.type_name),
145
+ class_name: exn.type_name,
146
146
  method_name: exn.method_name,
147
147
  location: exn.members[0].location
148
148
  )
@@ -38,7 +38,7 @@ module Steep
38
38
  end
39
39
 
40
40
  def self.parser
41
- ::Parser::Ruby25.new(Builder.new).tap do |parser|
41
+ ::Parser::Ruby27.new(Builder.new).tap do |parser|
42
42
  parser.diagnostics.all_errors_are_fatal = true
43
43
  parser.diagnostics.ignore_warnings = true
44
44
  end
@@ -60,7 +60,7 @@ module Steep
60
60
  _, comments, _ = yield_self do
61
61
  buffer = ::Parser::Source::Buffer.new(path.to_s)
62
62
  buffer.source = source_code
63
- parser = ::Parser::Ruby25.new
63
+ parser = ::Parser::Ruby27.new
64
64
 
65
65
  parser.tokenize(buffer)
66
66
  end
@@ -276,6 +276,18 @@ module Steep
276
276
  end
277
277
  end
278
278
 
279
+ def self.map_child_nodes(node)
280
+ children = node.children.map do |child|
281
+ if child.is_a?(::AST::Node)
282
+ yield child
283
+ else
284
+ child
285
+ end
286
+ end
287
+
288
+ node.updated(nil, children)
289
+ end
290
+
279
291
  def annotations(block:, factory:, current_module:)
280
292
  AST::Annotation::Collection.new(
281
293
  annotations: mapping[block.__id__] || [],
@@ -316,5 +328,50 @@ module Steep
316
328
  end
317
329
  end
318
330
  end
331
+
332
+ def self.delete_defs(node, allow_list)
333
+ case node.type
334
+ when :def
335
+ if allow_list.include?(node)
336
+ node
337
+ else
338
+ node.updated(:nil, [])
339
+ end
340
+ when :defs
341
+ if allow_list.include?(node)
342
+ node
343
+ else
344
+ delete_defs(node.children[0], allow_list)
345
+ end
346
+ else
347
+ map_child_nodes(node) do |child|
348
+ delete_defs(child, allow_list)
349
+ end
350
+ end
351
+ end
352
+
353
+ def without_unrelated_defs(line:, column:)
354
+ nodes = find_nodes(line: line, column: column) || []
355
+ defs = Set[].compare_by_identity.merge(nodes.select {|node| node.type == :def || node.type == :defs })
356
+
357
+ node_ = Source.delete_defs(node, defs)
358
+
359
+ Source.new(path: path, node: node_, mapping: mapping)
360
+ end
361
+
362
+ def compact_siblings(node)
363
+ case node
364
+ when :def
365
+ node.updated(:nil, [])
366
+ when :defs
367
+ node.children[0]
368
+ when :class
369
+ node.updated(:class, [node.children[0], node.children[1], nil])
370
+ when :module
371
+ node.updated(:module, [node.children[0], nil])
372
+ else
373
+ node
374
+ end
375
+ end
319
376
  end
320
377
  end
@@ -10,8 +10,7 @@ module Steep
10
10
  end
11
11
 
12
12
  def instance_super_types(type_name, args:)
13
- type_name_1 = factory.type_name_1(type_name)
14
- ancestors = factory.definition_builder.one_instance_ancestors(type_name_1)
13
+ ancestors = factory.definition_builder.one_instance_ancestors(type_name)
15
14
 
16
15
  subst = unless args.empty?
17
16
  args_ = args.map {|type| factory.type_1(type) }
@@ -19,7 +18,7 @@ module Steep
19
18
  end
20
19
 
21
20
  ancestors.each_ancestor.map do |ancestor|
22
- name = factory.type_name(ancestor.name)
21
+ name = ancestor.name
23
22
 
24
23
  case ancestor
25
24
  when RBS::Definition::Ancestor::Instance
@@ -42,9 +41,8 @@ module Steep
42
41
  )
43
42
  end
44
43
  when RBS::Definition::Ancestor::Singleton
45
- AST::Types::Name::Class.new(
44
+ AST::Types::Name::Singleton.new(
46
45
  name: name,
47
- constructor: nil,
48
46
  location: nil
49
47
  )
50
48
  end
@@ -52,11 +50,10 @@ module Steep
52
50
  end
53
51
 
54
52
  def singleton_super_types(type_name)
55
- type_name_1 = factory.type_name_1(type_name)
56
- ancestors = factory.definition_builder.one_singleton_ancestors(type_name_1)
53
+ ancestors = factory.definition_builder.one_singleton_ancestors(type_name)
57
54
 
58
55
  ancestors.each_ancestor.map do |ancestor|
59
- name = factory.type_name(ancestor.name)
56
+ name = ancestor.name
60
57
 
61
58
  case ancestor
62
59
  when RBS::Definition::Ancestor::Instance
@@ -78,9 +75,8 @@ module Steep
78
75
  )
79
76
  end
80
77
  when RBS::Definition::Ancestor::Singleton
81
- AST::Types::Name::Class.new(
78
+ AST::Types::Name::Singleton.new(
82
79
  name: name,
83
- constructor: nil,
84
80
  location: nil
85
81
  )
86
82
  end
@@ -180,6 +176,14 @@ module Steep
180
176
  constraints: constraints
181
177
  )
182
178
 
179
+ when relation.super_type.is_a?(AST::Types::Var) && constraints.unknown?(relation.super_type.name)
180
+ constraints.add(relation.super_type.name, sub_type: relation.sub_type)
181
+ success(constraints: constraints)
182
+
183
+ when relation.sub_type.is_a?(AST::Types::Var) && constraints.unknown?(relation.sub_type.name)
184
+ constraints.add(relation.sub_type.name, super_type: relation.super_type)
185
+ success(constraints: constraints)
186
+
183
187
  when relation.sub_type.is_a?(AST::Types::Union)
184
188
  results = relation.sub_type.types.map do |sub_type|
185
189
  check(Relation.new(sub_type: sub_type, super_type: relation.super_type),
@@ -232,14 +236,6 @@ module Steep
232
236
  results.find(&:failure?)
233
237
  end
234
238
 
235
- when relation.super_type.is_a?(AST::Types::Var) && constraints.unknown?(relation.super_type.name)
236
- constraints.add(relation.super_type.name, sub_type: relation.sub_type)
237
- success(constraints: constraints)
238
-
239
- when relation.sub_type.is_a?(AST::Types::Var) && constraints.unknown?(relation.sub_type.name)
240
- constraints.add(relation.sub_type.name, super_type: relation.super_type)
241
- success(constraints: constraints)
242
-
243
239
  when relation.super_type.is_a?(AST::Types::Var) || relation.sub_type.is_a?(AST::Types::Var)
244
240
  failure(error: Result::Failure::UnknownPairError.new(relation: relation),
245
241
  trace: trace)
@@ -266,7 +262,7 @@ module Steep
266
262
  possible_sub_types = case relation.sub_type
267
263
  when AST::Types::Name::Instance
268
264
  instance_super_types(relation.sub_type.name, args: relation.sub_type.args)
269
- when AST::Types::Name::Class
265
+ when AST::Types::Name::Singleton
270
266
  singleton_super_types(relation.sub_type.name)
271
267
  else
272
268
  []
@@ -302,10 +298,9 @@ module Steep
302
298
  when relation.sub_type.is_a?(AST::Types::Tuple) && relation.super_type.is_a?(AST::Types::Tuple)
303
299
  if relation.sub_type.types.size >= relation.super_type.types.size
304
300
  pairs = relation.sub_type.types.take(relation.super_type.types.size).zip(relation.super_type.types)
305
- results = pairs.flat_map do |t1, t2|
301
+ results = pairs.map do |t1, t2|
306
302
  relation = Relation.new(sub_type: t1, super_type: t2)
307
- [check(relation, self_type: self_type, assumption: assumption, trace: trace, constraints: constraints),
308
- check(relation.flip, self_type: self_type, assumption: assumption, trace: trace, constraints: constraints)]
303
+ check(relation, self_type: self_type, assumption: assumption, trace: trace, constraints: constraints)
309
304
  end
310
305
 
311
306
  if results.all?(&:success?)
@@ -395,12 +390,12 @@ module Steep
395
390
  end
396
391
 
397
392
  def definition_for_type(type)
398
- type_name = factory.type_name_1(type.name)
393
+ type_name = type.name
399
394
 
400
395
  case type
401
396
  when AST::Types::Name::Instance
402
397
  factory.definition_builder.build_instance(type_name)
403
- when AST::Types::Name::Class
398
+ when AST::Types::Name::Singleton
404
399
  factory.definition_builder.build_singleton(type_name)
405
400
  when AST::Types::Name::Interface
406
401
  factory.definition_builder.build_interface(type_name)
@@ -485,11 +480,7 @@ module Steep
485
480
  if sub_type.name == super_type.name && sub_type.args.size == super_type.args.size
486
481
  sub_type.args.zip(super_type.args)
487
482
  end
488
- when sub_type.is_a?(AST::Types::Name::Class) && super_type.is_a?(AST::Types::Name::Class)
489
- if sub_type.name == super_type.name
490
- []
491
- end
492
- when sub_type.is_a?(AST::Types::Name::Module) && super_type.is_a?(AST::Types::Name::Module)
483
+ when sub_type.is_a?(AST::Types::Name::Singleton) && super_type.is_a?(AST::Types::Name::Singleton)
493
484
  if sub_type.name == super_type.name
494
485
  []
495
486
  end
@@ -536,29 +527,24 @@ module Steep
536
527
 
537
528
  def check_method(name, sub_method, super_method, self_type:, assumption:, trace:, constraints:)
538
529
  trace.method name, sub_method, super_method do
539
- case
540
- when sub_method.overload? && super_method.overload?
541
- super_method.types.map do |super_type|
542
- sub_method.types.map do |sub_type|
543
- check_generic_method_type name,
544
- sub_type,
545
- super_type,
546
- self_type: self_type,
547
- assumption: assumption,
548
- trace: trace,
549
- constraints: constraints
550
- end.yield_self do |results|
551
- results.find(&:success?) || results[0]
552
- end
530
+ super_method.method_types.map do |super_type|
531
+ sub_method.method_types.map do |sub_type|
532
+ check_generic_method_type name,
533
+ sub_type,
534
+ super_type,
535
+ self_type: self_type,
536
+ assumption: assumption,
537
+ trace: trace,
538
+ constraints: constraints
553
539
  end.yield_self do |results|
554
- if results.all?(&:success?) || sub_method.incompatible?
555
- success constraints: constraints
556
- else
557
- results.select(&:failure?).last
558
- end
540
+ results.find(&:success?) || results[0]
541
+ end
542
+ end.yield_self do |results|
543
+ if results.all?(&:success?)
544
+ success constraints: constraints
545
+ else
546
+ results.select(&:failure?).last
559
547
  end
560
- else
561
- raise "aaaaaaaaaaaaaa"
562
548
  end
563
549
  end
564
550
  end