steep 0.28.0 → 0.32.0

Sign up to get free protection for your applications and to get access to all the features.
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