steep 0.28.0 → 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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +27 -0
  3. data/bin/steep-prof +1 -2
  4. data/lib/steep.rb +5 -3
  5. data/lib/steep/annotation_parser.rb +2 -4
  6. data/lib/steep/ast/builtin.rb +9 -1
  7. data/lib/steep/ast/types/factory.rb +177 -53
  8. data/lib/steep/ast/types/logic.rb +63 -0
  9. data/lib/steep/interface/method_type.rb +14 -4
  10. data/lib/steep/module_helper.rb +25 -0
  11. data/lib/steep/project.rb +25 -0
  12. data/lib/steep/project/completion_provider.rb +57 -58
  13. data/lib/steep/project/file_loader.rb +7 -2
  14. data/lib/steep/project/hover_content.rb +92 -83
  15. data/lib/steep/project/signature_file.rb +33 -0
  16. data/lib/steep/project/{file.rb → source_file.rb} +24 -54
  17. data/lib/steep/project/target.rb +31 -12
  18. data/lib/steep/server/code_worker.rb +30 -46
  19. data/lib/steep/server/interaction_worker.rb +42 -38
  20. data/lib/steep/server/master.rb +13 -30
  21. data/lib/steep/server/utils.rb +46 -13
  22. data/lib/steep/server/worker_process.rb +4 -2
  23. data/lib/steep/signature/validator.rb +3 -3
  24. data/lib/steep/source.rb +58 -1
  25. data/lib/steep/subtyping/check.rb +5 -7
  26. data/lib/steep/subtyping/constraints.rb +8 -0
  27. data/lib/steep/type_construction.rb +204 -207
  28. data/lib/steep/type_inference/constant_env.rb +2 -5
  29. data/lib/steep/type_inference/logic_type_interpreter.rb +225 -0
  30. data/lib/steep/type_inference/type_env.rb +2 -2
  31. data/lib/steep/version.rb +1 -1
  32. data/smoke/toplevel/Steepfile +5 -0
  33. data/smoke/toplevel/a.rb +4 -0
  34. data/smoke/toplevel/a.rbs +3 -0
  35. data/smoke/type_case/a.rb +0 -7
  36. data/steep.gemspec +2 -2
  37. metadata +18 -14
  38. data/lib/steep/ast/method_type.rb +0 -126
  39. data/lib/steep/ast/namespace.rb +0 -80
  40. 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
@@ -27,19 +29,24 @@ module Steep
27
29
  end
28
30
 
29
31
  def start
30
- source_paths = project.targets.flat_map {|target| target.source_files.keys }
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::FULL
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()
@@ -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
  )
@@ -107,7 +107,7 @@ module Steep
107
107
 
108
108
  if node.children[1]
109
109
  if node.loc.keyword.source == "if" || node.loc.keyword.source == "elsif"
110
- then_start = node.loc.begin&.loc&.last_line || node.children[0].loc.last_line
110
+ then_start = node.loc.begin&.last_line || node.children[0].loc.last_line
111
111
  then_end = node.children[2] ? node.loc.else.line : node.loc.last_line
112
112
  else
113
113
  then_start = node.loc.else.last_line
@@ -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
@@ -51,11 +50,10 @@ module Steep
51
50
  end
52
51
 
53
52
  def singleton_super_types(type_name)
54
- type_name_1 = factory.type_name_1(type_name)
55
- ancestors = factory.definition_builder.one_singleton_ancestors(type_name_1)
53
+ ancestors = factory.definition_builder.one_singleton_ancestors(type_name)
56
54
 
57
55
  ancestors.each_ancestor.map do |ancestor|
58
- name = factory.type_name(ancestor.name)
56
+ name = ancestor.name
59
57
 
60
58
  case ancestor
61
59
  when RBS::Definition::Ancestor::Instance
@@ -392,7 +390,7 @@ module Steep
392
390
  end
393
391
 
394
392
  def definition_for_type(type)
395
- type_name = factory.type_name_1(type.name)
393
+ type_name = type.name
396
394
 
397
395
  case type
398
396
  when AST::Types::Name::Instance
@@ -104,6 +104,14 @@ module Steep
104
104
  def add(var, sub_type: nil, super_type: nil)
105
105
  subs, supers = dictionary[var]
106
106
 
107
+ if sub_type.is_a?(AST::Types::Logic::Base)
108
+ sub_type = AST::Builtin.bool_type
109
+ end
110
+
111
+ if super_type.is_a?(AST::Types::Logic::Base)
112
+ super_type = AST::Builtin.bool_type
113
+ end
114
+
107
115
  if super_type && !super_type.is_a?(AST::Types::Top)
108
116
  supers << eliminate_variable(super_type, to: AST::Types::Top.new)
109
117
  end
@@ -33,6 +33,8 @@ module Steep
33
33
  end
34
34
  end
35
35
 
36
+ include ModuleHelper
37
+
36
38
  attr_reader :checker
37
39
  attr_reader :source
38
40
  attr_reader :annotations
@@ -169,7 +171,7 @@ module Steep
169
171
 
170
172
  super_method = if definition
171
173
  if (this_method = definition.methods[method_name])
172
- if module_context&.class_name == checker.factory.type_name(this_method.defined_in)
174
+ if module_context&.class_name == this_method.defined_in
173
175
  this_method.super_method
174
176
  else
175
177
  this_method
@@ -254,7 +256,7 @@ module Steep
254
256
  end
255
257
 
256
258
  if name
257
- absolute_name_ = checker.factory.type_name_1(name)
259
+ absolute_name_ = name
258
260
  entry = checker.factory.env.class_decls[absolute_name_]
259
261
  AST::Annotation::Implements::Module.new(
260
262
  name: name,
@@ -265,7 +267,7 @@ module Steep
265
267
  end
266
268
 
267
269
  def for_module(node)
268
- new_module_name = Names::Module.from_node(node.children.first) or raise "Unexpected module name: #{node.children.first}"
270
+ new_module_name = module_name_from_node(node.children.first) or raise "Unexpected module name: #{node.children.first}"
269
271
  new_namespace = nested_namespace_for_module(new_module_name)
270
272
 
271
273
  const_context = [new_namespace] + self.module_context.const_env.context
@@ -280,7 +282,7 @@ module Steep
280
282
  module_name = implement_module_name.name
281
283
  module_args = implement_module_name.args.map {|x| AST::Types::Var.new(name: x)}
282
284
 
283
- type_name_ = checker.factory.type_name_1(implement_module_name.name)
285
+ type_name_ = implement_module_name.name
284
286
  module_entry = checker.factory.definition_builder.env.class_decls[type_name_]
285
287
  instance_def = checker.factory.definition_builder.build_instance(type_name_)
286
288
  module_def = checker.factory.definition_builder.build_singleton(type_name_)
@@ -359,8 +361,8 @@ module Steep
359
361
  end
360
362
 
361
363
  def for_class(node)
362
- new_class_name = Names::Module.from_node(node.children.first) or raise "Unexpected class name: #{node.children.first}"
363
- super_class_name = node.children[1] && Names::Module.from_node(node.children[1])
364
+ new_class_name = module_name_from_node(node.children.first) or raise "Unexpected class name: #{node.children.first}"
365
+ super_class_name = node.children[1] && module_name_from_node(node.children[1])
364
366
  new_namespace = nested_namespace_for_module(new_class_name)
365
367
 
366
368
  annots = source.annotations(block: node, factory: checker.factory, current_module: new_namespace)
@@ -375,7 +377,7 @@ module Steep
375
377
  class_name = implement_module_name.name
376
378
  class_args = implement_module_name.args.map {|x| AST::Types::Var.new(name: x)}
377
379
 
378
- type_name_ = checker.factory.type_name_1(implement_module_name.name)
380
+ type_name_ = implement_module_name.name
379
381
  instance_def = checker.factory.definition_builder.build_instance(type_name_)
380
382
  module_def = checker.factory.definition_builder.build_singleton(type_name_)
381
383
 
@@ -445,7 +447,7 @@ module Steep
445
447
 
446
448
  module_type = case instance_type
447
449
  when AST::Types::Name::Singleton
448
- type_name = checker.factory.type_name_1(instance_type.name)
450
+ type_name = instance_type.name
449
451
 
450
452
  case checker.factory.env.class_decls[type_name]
451
453
  when RBS::Environment::ModuleEntry
@@ -464,16 +466,16 @@ module Steep
464
466
 
465
467
  instance_definition = case instance_type
466
468
  when AST::Types::Name::Singleton
467
- type_name = checker.factory.type_name_1(instance_type.name)
469
+ type_name = instance_type.name
468
470
  checker.factory.definition_builder.build_singleton(type_name)
469
471
  when AST::Types::Name::Instance
470
- type_name = checker.factory.type_name_1(instance_type.name)
472
+ type_name = instance_type.name
471
473
  checker.factory.definition_builder.build_instance(type_name)
472
474
  end
473
475
 
474
476
  module_definition = case module_type
475
477
  when AST::Types::Name::Singleton
476
- type_name = checker.factory.type_name_1(instance_type.name)
478
+ type_name = instance_type.name
477
479
  checker.factory.definition_builder.build_singleton(type_name)
478
480
  else
479
481
  nil
@@ -888,10 +890,10 @@ module Steep
888
890
  self_type = expand_self(self_type)
889
891
  definition = case self_type
890
892
  when AST::Types::Name::Instance
891
- name = checker.factory.type_name_1(self_type.name)
893
+ name = self_type.name
892
894
  checker.factory.definition_builder.build_singleton(name)
893
895
  when AST::Types::Name::Singleton
894
- name = checker.factory.type_name_1(self_type.name)
896
+ name = self_type.name
895
897
  checker.factory.definition_builder.build_singleton(name)
896
898
  end
897
899
 
@@ -1270,7 +1272,7 @@ module Steep
1270
1272
  add_typing node, type: AST::Types::Self.new
1271
1273
 
1272
1274
  when :const
1273
- const_name = Names::Module.from_node(node)
1275
+ const_name = module_name_from_node(node)
1274
1276
 
1275
1277
  if const_name
1276
1278
  type = type_env.get(const: const_name) do
@@ -1283,7 +1285,7 @@ module Steep
1283
1285
 
1284
1286
  when :casgn
1285
1287
  yield_self do
1286
- const_name = Names::Module.from_node(node)
1288
+ const_name = module_name_from_node(node)
1287
1289
  if const_name
1288
1290
  const_type = type_env.get(const: const_name) {}
1289
1291
  value_type = synthesize(node.children.last, hint: const_type).type
@@ -1396,15 +1398,17 @@ module Steep
1396
1398
  when :and
1397
1399
  yield_self do
1398
1400
  left, right = node.children
1399
- logic = TypeInference::Logic.new(subtyping: checker)
1400
- truthy, falsey = logic.nodes(node: left)
1401
1401
 
1402
1402
  left_type, constr = synthesize(left)
1403
- truthy_env, falsey_env = logic.environments(truthy_vars: truthy.vars,
1404
- falsey_vars: falsey.vars,
1405
- lvar_env: constr.context.lvar_env)
1406
1403
 
1407
- right_type, constr = constr.update_lvar_env { truthy_env }.for_branch(right).synthesize(right)
1404
+ interpreter = TypeInference::LogicTypeInterpreter.new(subtyping: checker, typing: typing)
1405
+ truthy_env, falsey_env = interpreter.eval(env: constr.context.lvar_env, type: left_type, node: left)
1406
+
1407
+ right_type, constr = constr
1408
+ .update_lvar_env { truthy_env }
1409
+ .tap {|constr| typing.add_context_for_node(right, context: constr.context) }
1410
+ .for_branch(right)
1411
+ .synthesize(right)
1408
1412
 
1409
1413
  type = if left_type.is_a?(AST::Types::Boolean)
1410
1414
  union_type(left_type, right_type)
@@ -1426,16 +1430,18 @@ module Steep
1426
1430
  when :or
1427
1431
  yield_self do
1428
1432
  left, right = node.children
1429
- logic = TypeInference::Logic.new(subtyping: checker)
1430
- truthy, falsey = logic.nodes(node: left)
1431
1433
 
1432
1434
  left_type, constr = synthesize(left, hint: hint)
1433
- truthy_env, falsey_env = logic.environments(truthy_vars: truthy.vars,
1434
- falsey_vars: falsey.vars,
1435
- lvar_env: constr.context.lvar_env)
1436
- left_type_t, _ = logic.partition_union(left_type)
1437
1435
 
1438
- right_type, constr = constr.update_lvar_env { falsey_env }.for_branch(right).synthesize(right, hint: left_type_t)
1436
+ interpreter = TypeInference::LogicTypeInterpreter.new(subtyping: checker, typing: typing)
1437
+ truthy_env, falsey_env = interpreter.eval(env: constr.context.lvar_env, type: left_type, node: left)
1438
+
1439
+ left_type_t, _ = checker.factory.unwrap_optional(left_type)
1440
+ right_type, constr = constr
1441
+ .update_lvar_env { falsey_env }
1442
+ .tap {|constr| typing.add_context_for_node(right, context: constr.context) }
1443
+ .for_branch(right)
1444
+ .synthesize(right, hint: left_type_t)
1439
1445
 
1440
1446
  type = union_type(left_type_t, right_type)
1441
1447
 
@@ -1454,12 +1460,8 @@ module Steep
1454
1460
  cond, true_clause, false_clause = node.children
1455
1461
 
1456
1462
  cond_type, constr = synthesize(cond)
1457
- logic = TypeInference::Logic.new(subtyping: checker)
1458
-
1459
- truthys, falseys = logic.nodes(node: cond)
1460
- truthy_env, falsey_env = logic.environments(truthy_vars: truthys.vars,
1461
- falsey_vars: falseys.vars,
1462
- lvar_env: constr.context.lvar_env)
1463
+ interpreter = TypeInference::LogicTypeInterpreter.new(subtyping: checker, typing: constr.typing)
1464
+ truthy_env, falsey_env = interpreter.eval(env: constr.context.lvar_env, type: cond_type, node: cond)
1463
1465
 
1464
1466
  if true_clause
1465
1467
  true_pair = constr
@@ -1509,70 +1511,91 @@ module Steep
1509
1511
  cond, *whens, els = node.children
1510
1512
 
1511
1513
  constr = self
1514
+ interpreter = TypeInference::LogicTypeInterpreter.new(subtyping: checker, typing: typing)
1512
1515
 
1513
1516
  if cond
1514
- cond_type, constr = synthesize(cond)
1515
- cond_type = expand_alias(cond_type)
1516
- if cond_type.is_a?(AST::Types::Union)
1517
- var_names = TypeConstruction.value_variables(cond)
1518
- var_types = cond_type.types.dup
1519
- end
1520
- end
1517
+ branch_pairs = []
1521
1518
 
1522
- branch_pairs = []
1519
+ cond_type, constr = constr.synthesize(cond)
1520
+ _, cond_vars = interpreter.decompose_value(cond)
1523
1521
 
1524
- whens.each do |clause|
1525
- *tests, body = clause.children
1522
+ when_constr = constr
1523
+ whens.each do |clause|
1524
+ *tests, body = clause.children
1526
1525
 
1527
- test_types = []
1528
- clause_constr = constr
1526
+ test_constr = when_constr
1527
+ test_envs = []
1529
1528
 
1530
- tests.each do |test|
1531
- type, clause_constr = synthesize(test)
1532
- test_types << expand_alias(type)
1533
- end
1534
-
1535
- if var_names && var_types && test_types.all? {|ty| ty.is_a?(AST::Types::Name::Singleton) }
1536
- var_types_in_body = test_types.flat_map do |test_type|
1537
- filtered_types = var_types.select do |var_type|
1538
- var_type.is_a?(AST::Types::Name::Base) && var_type.name == test_type.name
1539
- end
1540
- if filtered_types.empty?
1541
- to_instance_type(test_type)
1542
- else
1543
- filtered_types
1544
- end
1529
+ tests.each do |test|
1530
+ test_node = test.updated(:send, [test, :===, cond.dup])
1531
+ test_type, test_constr = test_constr.synthesize(test_node)
1532
+ truthy_env, falsy_env = interpreter.eval(type: test_type, node: test_node, env: test_constr.context.lvar_env)
1533
+ test_envs << truthy_env
1534
+ test_constr = test_constr.update_lvar_env { falsy_env }
1545
1535
  end
1546
1536
 
1547
- var_types.reject! do |type|
1548
- var_types_in_body.any? do |test_type|
1549
- type.is_a?(AST::Types::Name::Base) && test_type.name == type.name
1550
- end
1551
- end
1552
-
1553
- var_type_in_body = union_type(*var_types_in_body)
1554
- type_case_override = var_names.each.with_object({}) do |var_name, hash|
1555
- hash[var_name] = var_type_in_body
1556
- end
1537
+ body_constr = when_constr.update_lvar_env {|env| env.except(cond_vars).join(*test_envs) }
1557
1538
 
1558
1539
  if body
1559
- branch_pairs << clause_constr
1560
- .for_branch(body, type_case_override: type_case_override)
1540
+ branch_pairs << body_constr
1541
+ .for_branch(body)
1542
+ .tap {|constr| typing.add_context_for_node(body, context: constr.context) }
1561
1543
  .synthesize(body, hint: hint)
1562
1544
  else
1563
- branch_pairs << Pair.new(type: AST::Builtin.nil_type, constr: clause_constr)
1545
+ branch_pairs << Pair.new(type: AST::Builtin.nil_type, constr: body_constr)
1546
+ end
1547
+
1548
+ when_constr = test_constr
1549
+ end
1550
+
1551
+ if els
1552
+ begin_pos = node.loc.else.end_pos
1553
+ end_pos = node.loc.end.begin_pos
1554
+ typing.add_context(begin_pos..end_pos, context: when_constr.context)
1555
+
1556
+ branch_pairs << when_constr.synthesize(els, hint: hint)
1557
+ end
1558
+
1559
+ types = branch_pairs.map(&:type)
1560
+ constrs = branch_pairs.map(&:constr)
1561
+
1562
+ unless els
1563
+ constrs << when_constr
1564
+ end
1565
+
1566
+ if when_constr.context.lvar_env[cond_vars.first].is_a?(AST::Types::Bot)
1567
+ # Exhaustive
1568
+ if els
1569
+ typing.add_error Errors::ElseOnExhaustiveCase.new(node: els, type: cond_type)
1564
1570
  end
1565
1571
  else
1566
- logic = TypeInference::Logic.new(subtyping: checker)
1572
+ unless els
1573
+ types << AST::Builtin.nil_type
1574
+ end
1575
+ end
1576
+ else
1577
+ branch_pairs = []
1578
+
1579
+ when_constr = constr
1580
+
1581
+ whens.each do |clause|
1582
+ *tests, body = clause.children
1567
1583
 
1568
- truthys, falseys = logic.nodes(node: ::AST::Node.new(:begin, tests))
1569
- truthy_env, _ = logic.environments(truthy_vars: truthys.vars,
1570
- falsey_vars: falseys.vars,
1571
- lvar_env: clause_constr.context.lvar_env)
1584
+ test_constr = when_constr
1585
+ test_envs = []
1586
+
1587
+ tests.each do |test|
1588
+ test_type, test_constr = test_constr.synthesize(test)
1589
+ truthy_env, falsy_env = interpreter.eval(env: test_constr.context.lvar_env, type: test_type, node: test)
1590
+ test_envs << truthy_env
1591
+ test_constr = test_constr.update_lvar_env { falsy_env }
1592
+ end
1593
+
1594
+ clause_constr = when_constr.update_lvar_env {|env| env.join(*test_envs) }
1595
+ when_constr = test_constr
1572
1596
 
1573
1597
  if body
1574
- branch_pairs << constr
1575
- .update_lvar_env { truthy_env }
1598
+ branch_pairs << clause_constr
1576
1599
  .for_branch(body)
1577
1600
  .tap {|constr| typing.add_context_for_node(body, context: constr.context) }
1578
1601
  .synthesize(body, hint: hint)
@@ -1580,34 +1603,17 @@ module Steep
1580
1603
  branch_pairs << Pair.new(type: AST::Builtin.nil_type, constr: clause_constr)
1581
1604
  end
1582
1605
  end
1583
- end
1584
1606
 
1585
- if els
1586
- if var_names && var_types
1587
- if var_types.empty?
1588
- typing.add_error Errors::ElseOnExhaustiveCase.new(node: node, type: cond_type)
1589
- end
1590
-
1591
- else_override = var_names.each.with_object({}) do |var_name, hash|
1592
- hash[var_name] = unless var_types.empty?
1593
- union_type(*var_types)
1594
- else
1595
- AST::Builtin.any_type
1596
- end
1597
- end
1598
- branch_pairs << constr
1599
- .for_branch(els, type_case_override: else_override)
1600
- .synthesize(els, hint: hint)
1601
- else
1602
- branch_pairs << constr.synthesize(els, hint: hint)
1607
+ if els
1608
+ branch_pairs << when_constr.synthesize(els, hint: hint)
1603
1609
  end
1604
- end
1605
1610
 
1606
- types = branch_pairs.map(&:type)
1607
- constrs = branch_pairs.map(&:constr)
1611
+ types = branch_pairs.map(&:type)
1612
+ constrs = branch_pairs.map(&:constr)
1608
1613
 
1609
- unless var_types&.empty? || els
1610
- types.push AST::Builtin.nil_type
1614
+ unless els
1615
+ types << AST::Builtin.nil_type
1616
+ end
1611
1617
  end
1612
1618
 
1613
1619
  constr = constr.update_lvar_env do |env|
@@ -1620,7 +1626,7 @@ module Steep
1620
1626
  when :rescue
1621
1627
  yield_self do
1622
1628
  body, *resbodies, else_node = node.children
1623
- body_pair = synthesize(body) if body
1629
+ body_pair = synthesize(body, hint: hint) if body
1624
1630
 
1625
1631
  body_constr = if body_pair
1626
1632
  self.update_lvar_env do |env|
@@ -1672,7 +1678,7 @@ module Steep
1672
1678
  resbody_construction = body_constr.for_branch(resbody, type_case_override: type_override)
1673
1679
 
1674
1680
  if body
1675
- resbody_construction.synthesize(body)
1681
+ resbody_construction.synthesize(body, hint: hint)
1676
1682
  else
1677
1683
  Pair.new(constr: body_constr, type: AST::Builtin.nil_type)
1678
1684
  end
@@ -1682,7 +1688,7 @@ module Steep
1682
1688
  resbody_envs = resbody_pairs.map {|pair| pair.context.lvar_env }
1683
1689
 
1684
1690
  if else_node
1685
- else_pair = (body_pair&.constr || self).for_branch(else_node).synthesize(else_node)
1691
+ else_pair = (body_pair&.constr || self).for_branch(else_node).synthesize(else_node, hint: hint)
1686
1692
  add_typing(node,
1687
1693
  type: union_type(*[else_pair.type, *resbody_types].compact),
1688
1694
  constr: update_lvar_env {|env| env.join(*resbody_envs, env) })
@@ -1698,7 +1704,7 @@ module Steep
1698
1704
  klasses, asgn, body = node.children
1699
1705
  synthesize(klasses) if klasses
1700
1706
  synthesize(asgn) if asgn
1701
- body_type = synthesize(body).type if body
1707
+ body_type = synthesize(body, hint: hint).type if body
1702
1708
  add_typing(node, type: body_type)
1703
1709
  end
1704
1710
 
@@ -1759,16 +1765,16 @@ module Steep
1759
1765
  when :while, :until
1760
1766
  yield_self do
1761
1767
  cond, body = node.children
1762
- _, constr = synthesize(cond)
1768
+ cond_type, constr = synthesize(cond)
1763
1769
 
1764
- logic = TypeInference::Logic.new(subtyping: checker)
1765
- truthy, falsey = logic.nodes(node: cond)
1770
+ interpreter = TypeInference::LogicTypeInterpreter.new(subtyping: checker, typing: typing)
1771
+ truthy_env, falsy_env = interpreter.eval(env: constr.context.lvar_env, node: cond, type: cond_type)
1766
1772
 
1767
1773
  case node.type
1768
1774
  when :while
1769
- body_env, exit_env = logic.environments(truthy_vars: truthy.vars, falsey_vars: falsey.vars, lvar_env: constr.context.lvar_env)
1775
+ body_env, exit_env = truthy_env, falsy_env
1770
1776
  when :until
1771
- exit_env, body_env = logic.environments(truthy_vars: truthy.vars, falsey_vars: falsey.vars, lvar_env: constr.context.lvar_env)
1777
+ exit_env, body_env = truthy_env, falsy_env
1772
1778
  end
1773
1779
 
1774
1780
  if body
@@ -2007,8 +2013,18 @@ module Steep
2007
2013
  add_typing node, type: AST::Builtin.any_type
2008
2014
  end
2009
2015
 
2016
+ when :args
2017
+ constr = self
2018
+
2019
+ each_child_node(node) do |child|
2020
+ _, constr = constr.synthesize(child)
2021
+ end
2022
+
2023
+ add_typing node, type: AST::Builtin.any_type, constr: constr
2024
+
2010
2025
  else
2011
2026
  raise "Unexpected node: #{node.inspect}, #{node.location.expression}"
2027
+
2012
2028
  end.tap do |pair|
2013
2029
  unless pair.is_a?(Pair) && !pair.type.is_a?(Pair)
2014
2030
  # Steep.logger.error { "result = #{pair.inspect}" }
@@ -2271,7 +2287,7 @@ module Steep
2271
2287
 
2272
2288
  def type_send(node, send_node:, block_params:, block_body:, unwrap: false)
2273
2289
  receiver, method_name, *arguments = send_node.children
2274
- receiver_type = receiver ? synthesize(receiver).type : AST::Types::Self.new
2290
+ receiver_type, constr = receiver ? synthesize(receiver) : [AST::Types::Self.new, self]
2275
2291
 
2276
2292
  if unwrap
2277
2293
  receiver_type = unwrap(receiver_type)
@@ -2279,74 +2295,80 @@ module Steep
2279
2295
 
2280
2296
  receiver_type = expand_alias(receiver_type)
2281
2297
 
2282
- pair = case receiver_type
2283
- when AST::Types::Any
2284
- add_typing node, type: AST::Builtin.any_type
2298
+ type, constr = case receiver_type
2299
+ when AST::Types::Any
2300
+ each_child_node(send_node) do |child|
2301
+ unless child.equal?(receiver)
2302
+ _, constr = constr.synthesize(child)
2303
+ end
2304
+ end
2285
2305
 
2286
- when nil
2287
- fallback_to_any node
2306
+ add_typing node, type: AST::Builtin.any_type
2288
2307
 
2289
- when AST::Types::Void, AST::Types::Bot, AST::Types::Top
2290
- fallback_to_any node do
2291
- Errors::NoMethod.new(node: node, method: method_name, type: receiver_type)
2292
- end
2308
+ when nil
2309
+ fallback_to_any node
2293
2310
 
2294
- else
2295
- case expanded_receiver_type = expand_self(receiver_type)
2296
- when AST::Types::Self
2297
- Steep.logger.debug { "`self` type cannot be resolved to concrete type" }
2298
- fallback_to_any node do
2299
- Errors::NoMethod.new(node: node, method: method_name, type: receiver_type)
2300
- end
2301
- else
2302
- begin
2303
- interface = checker.factory.interface(receiver_type,
2304
- private: !receiver,
2305
- self_type: expanded_receiver_type)
2306
-
2307
- method = interface.methods[method_name]
2308
-
2309
- if method
2310
- args = TypeInference::SendArgs.from_nodes(arguments)
2311
- return_type, constr, _ = type_method_call(node,
2312
- method: method,
2313
- method_name: method_name,
2314
- args: args,
2315
- block_params: block_params,
2316
- block_body: block_body,
2317
- receiver_type: receiver_type,
2318
- topdown_hint: true)
2319
-
2320
- add_typing node, type: return_type, constr: constr
2321
- else
2322
- fallback_to_any node do
2323
- Errors::NoMethod.new(node: node, method: method_name, type: expanded_receiver_type)
2324
- end
2325
- end
2326
- rescue => exn
2327
- case exn
2328
- when RBS::NoTypeFoundError, RBS::NoMixinFoundError, RBS::NoSuperclassFoundError, RBS::InvalidTypeApplicationError
2329
- # ignore known RBS errors.
2330
- else
2331
- Steep.log_error(exn, message: "Unexpected error in #type_send: #{exn.message} (#{exn.class})")
2332
- end
2311
+ when AST::Types::Void, AST::Types::Bot, AST::Types::Top
2312
+ fallback_to_any node do
2313
+ Errors::NoMethod.new(node: node, method: method_name, type: receiver_type)
2314
+ end
2333
2315
 
2334
- fallback_to_any node do
2335
- Errors::NoMethod.new(node: node, method: method_name, type: expanded_receiver_type)
2336
- end
2337
- end
2338
- end
2339
- end
2316
+ else
2317
+ case expanded_receiver_type = expand_self(receiver_type)
2318
+ when AST::Types::Self
2319
+ Steep.logger.debug { "`self` type cannot be resolved to concrete type" }
2320
+ fallback_to_any node do
2321
+ Errors::NoMethod.new(node: node, method: method_name, type: receiver_type)
2322
+ end
2323
+ else
2324
+ begin
2325
+ interface = checker.factory.interface(receiver_type,
2326
+ private: !receiver,
2327
+ self_type: expanded_receiver_type)
2328
+
2329
+ method = interface.methods[method_name]
2330
+
2331
+ if method
2332
+ args = TypeInference::SendArgs.from_nodes(arguments)
2333
+ return_type, constr, _ = constr.type_method_call(node,
2334
+ method: method,
2335
+ method_name: method_name,
2336
+ args: args,
2337
+ block_params: block_params,
2338
+ block_body: block_body,
2339
+ receiver_type: receiver_type,
2340
+ topdown_hint: true)
2341
+
2342
+ add_typing node, type: return_type, constr: constr
2343
+ else
2344
+ fallback_to_any node do
2345
+ Errors::NoMethod.new(node: node, method: method_name, type: expanded_receiver_type)
2346
+ end
2347
+ end
2348
+ rescue => exn
2349
+ case exn
2350
+ when RBS::NoTypeFoundError, RBS::NoMixinFoundError, RBS::NoSuperclassFoundError, RBS::InvalidTypeApplicationError
2351
+ # ignore known RBS errors.
2352
+ else
2353
+ Steep.log_error(exn, message: "Unexpected error in #type_send: #{exn.message} (#{exn.class})")
2354
+ end
2340
2355
 
2341
- case pair.type
2356
+ fallback_to_any node do
2357
+ Errors::NoMethod.new(node: node, method: method_name, type: expanded_receiver_type)
2358
+ end
2359
+ end
2360
+ end
2361
+ end
2362
+
2363
+ case type
2342
2364
  when nil, Errors::Base
2343
2365
  arguments.each do |arg|
2344
2366
  unless typing.has_type?(arg)
2345
2367
  if arg.type == :splat
2346
- type = synthesize(arg.children[0]).type
2368
+ type, constr = constr.synthesize(arg.children[0])
2347
2369
  add_typing(arg, type: AST::Builtin::Array.instance_type(type))
2348
2370
  else
2349
- synthesize(arg)
2371
+ _, constr = constr.synthesize(arg)
2350
2372
  end
2351
2373
  end
2352
2374
  end
@@ -2368,7 +2390,7 @@ module Steep
2368
2390
  end
2369
2391
  end
2370
2392
  else
2371
- pair
2393
+ Pair.new(type: type, constr: constr)
2372
2394
  end
2373
2395
  end
2374
2396
 
@@ -2867,7 +2889,7 @@ module Steep
2867
2889
  decls = param_types_hash.each.with_object({}) do |(name, type), hash|
2868
2890
  hash[name] = TypeInference::LocalVariableTypeEnv::Entry.new(type: type)
2869
2891
  end
2870
- env.update(declared_types: env.declared_types.merge(decls))
2892
+ env.except(decls.keys).update(assigned_types: decls)
2871
2893
  end.annotate(block_annotations)
2872
2894
 
2873
2895
  break_type = if block_annotations.break_type
@@ -3010,7 +3032,7 @@ module Steep
3010
3032
  end
3011
3033
 
3012
3034
  def nested_namespace_for_module(module_name)
3013
- if module_name.relative?
3035
+ if module_name.namespace.relative?
3014
3036
  (current_namespace + module_name.namespace).append(module_name.name)
3015
3037
  else
3016
3038
  module_name
@@ -3019,7 +3041,7 @@ module Steep
3019
3041
 
3020
3042
  def absolute_name(module_name)
3021
3043
  if current_namespace
3022
- module_name.in_namespace(current_namespace)
3044
+ module_name.with_prefix(current_namespace)
3023
3045
  else
3024
3046
  module_name.absolute!
3025
3047
  end
@@ -3037,7 +3059,7 @@ module Steep
3037
3059
  end
3038
3060
 
3039
3061
  def validate_method_definitions(node, module_name)
3040
- module_name_1 = checker.factory.type_name_1(module_name.name)
3062
+ module_name_1 = module_name.name
3041
3063
  member_decl_count = checker.factory.env.class_decls[module_name_1].decls.count {|d| d.decl.each_member.count > 0 }
3042
3064
 
3043
3065
  return unless member_decl_count == 1
@@ -3185,37 +3207,12 @@ module Steep
3185
3207
  end
3186
3208
  end
3187
3209
 
3188
- def deep_expand_alias(type, recursive: Set.new, &block)
3189
- raise "Recursive type definition: #{type}" if recursive.member?(type)
3190
-
3191
- ty = case type
3192
- when AST::Types::Name::Alias
3193
- deep_expand_alias(expand_alias(type), recursive: recursive.union([type]))
3194
- when AST::Types::Union
3195
- AST::Types::Union.build(
3196
- types: type.types.map {|ty| deep_expand_alias(ty, recursive: recursive, &block) },
3197
- location: type.location
3198
- )
3199
- else
3200
- type
3201
- end
3202
-
3203
- if block_given?
3204
- yield ty
3205
- else
3206
- ty
3207
- end
3210
+ def deep_expand_alias(type, &block)
3211
+ checker.factory.deep_expand_alias(type, &block)
3208
3212
  end
3209
3213
 
3210
- def flatten_union(type, acc = [])
3211
- case type
3212
- when AST::Types::Union
3213
- type.types.each {|ty| flatten_union(ty, acc) }
3214
- else
3215
- acc << type
3216
- end
3217
-
3218
- acc
3214
+ def flatten_union(type)
3215
+ checker.factory.flatten_union(type)
3219
3216
  end
3220
3217
 
3221
3218
  def select_flatten_types(type, &block)
@@ -3277,7 +3274,7 @@ module Steep
3277
3274
  def to_instance_type(type, args: nil)
3278
3275
  args = args || case type
3279
3276
  when AST::Types::Name::Singleton
3280
- checker.factory.env.class_decls[checker.factory.type_name_1(type.name)].type_params.each.map { AST::Builtin.any_type }
3277
+ checker.factory.env.class_decls[type.name].type_params.each.map { AST::Builtin.any_type }
3281
3278
  else
3282
3279
  raise "unexpected type to to_instance_type: #{type}"
3283
3280
  end