steep 0.43.1 → 0.46.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (109) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +8 -0
  3. data/.github/workflows/ruby.yml +4 -2
  4. data/.gitignore +0 -1
  5. data/CHANGELOG.md +41 -0
  6. data/Gemfile +0 -1
  7. data/Gemfile.lock +77 -0
  8. data/bin/output_test.rb +8 -2
  9. data/lib/steep/ast/builtin.rb +7 -1
  10. data/lib/steep/ast/types/factory.rb +19 -25
  11. data/lib/steep/cli.rb +7 -1
  12. data/lib/steep/diagnostic/lsp_formatter.rb +59 -6
  13. data/lib/steep/diagnostic/ruby.rb +188 -60
  14. data/lib/steep/diagnostic/signature.rb +34 -0
  15. data/lib/steep/drivers/check.rb +3 -0
  16. data/lib/steep/drivers/init.rb +10 -3
  17. data/lib/steep/drivers/utils/driver_helper.rb +15 -0
  18. data/lib/steep/drivers/validate.rb +1 -1
  19. data/lib/steep/drivers/watch.rb +3 -0
  20. data/lib/steep/equatable.rb +21 -0
  21. data/lib/steep/index/source_index.rb +55 -5
  22. data/lib/steep/interface/block.rb +4 -0
  23. data/lib/steep/interface/function.rb +798 -579
  24. data/lib/steep/project/dsl.rb +105 -33
  25. data/lib/steep/project/options.rb +12 -53
  26. data/lib/steep/project/target.rb +21 -8
  27. data/lib/steep/server/interaction_worker.rb +239 -20
  28. data/lib/steep/server/master.rb +22 -1
  29. data/lib/steep/server/type_check_worker.rb +74 -9
  30. data/lib/steep/services/file_loader.rb +26 -19
  31. data/lib/steep/services/goto_service.rb +322 -0
  32. data/lib/steep/services/hover_content.rb +132 -80
  33. data/lib/steep/services/type_check_service.rb +25 -0
  34. data/lib/steep/source.rb +7 -10
  35. data/lib/steep/type_construction.rb +496 -518
  36. data/lib/steep/type_inference/block_params.rb +2 -5
  37. data/lib/steep/type_inference/method_params.rb +483 -0
  38. data/lib/steep/type_inference/send_args.rb +610 -128
  39. data/lib/steep/typing.rb +46 -21
  40. data/lib/steep/version.rb +1 -1
  41. data/lib/steep.rb +4 -1
  42. data/sample/Steepfile +10 -3
  43. data/sig/steep/type_inference/send_args.rbs +42 -0
  44. data/smoke/alias/Steepfile +2 -1
  45. data/smoke/and/Steepfile +2 -1
  46. data/smoke/array/Steepfile +2 -1
  47. data/smoke/array/test_expectations.yml +3 -3
  48. data/smoke/block/Steepfile +2 -2
  49. data/smoke/block/c.rb +0 -1
  50. data/smoke/case/Steepfile +2 -1
  51. data/smoke/class/Steepfile +2 -1
  52. data/smoke/class/test_expectations.yml +12 -15
  53. data/smoke/const/Steepfile +2 -1
  54. data/smoke/const/test_expectations.yml +0 -10
  55. data/smoke/diagnostics/Steepfile +2 -1
  56. data/smoke/diagnostics/a.rbs +0 -4
  57. data/smoke/diagnostics/different_method_parameter_kind.rb +9 -0
  58. data/smoke/diagnostics/method_arity_mismatch.rb +2 -2
  59. data/smoke/diagnostics/method_parameter_mismatch.rb +10 -0
  60. data/smoke/diagnostics/test_expectations.yml +108 -57
  61. data/smoke/diagnostics-rbs/Steepfile +1 -1
  62. data/smoke/diagnostics-rbs/mixin-class-error.rbs +6 -0
  63. data/smoke/diagnostics-rbs/test_expectations.yml +12 -0
  64. data/smoke/diagnostics-rbs-duplicated/Steepfile +2 -1
  65. data/smoke/diagnostics-ruby-unsat/Steepfile +6 -0
  66. data/smoke/diagnostics-ruby-unsat/a.rbs +3 -0
  67. data/smoke/diagnostics-ruby-unsat/test_expectations.yml +27 -0
  68. data/smoke/{diagnostics → diagnostics-ruby-unsat}/unsatisfiable_constraint.rb +0 -1
  69. data/smoke/dstr/Steepfile +2 -1
  70. data/smoke/ensure/Steepfile +2 -1
  71. data/smoke/ensure/test_expectations.yml +3 -3
  72. data/smoke/enumerator/Steepfile +2 -1
  73. data/smoke/enumerator/test_expectations.yml +1 -1
  74. data/smoke/extension/Steepfile +2 -1
  75. data/smoke/hash/Steepfile +2 -1
  76. data/smoke/hello/Steepfile +2 -1
  77. data/smoke/if/Steepfile +2 -1
  78. data/smoke/implements/Steepfile +2 -1
  79. data/smoke/initialize/Steepfile +2 -1
  80. data/smoke/integer/Steepfile +2 -1
  81. data/smoke/interface/Steepfile +2 -1
  82. data/smoke/kwbegin/Steepfile +2 -1
  83. data/smoke/lambda/Steepfile +2 -1
  84. data/smoke/literal/Steepfile +2 -1
  85. data/smoke/literal/test_expectations.yml +2 -2
  86. data/smoke/map/Steepfile +2 -1
  87. data/smoke/method/Steepfile +2 -1
  88. data/smoke/method/test_expectations.yml +11 -10
  89. data/smoke/module/Steepfile +2 -1
  90. data/smoke/regexp/Steepfile +2 -1
  91. data/smoke/regression/Steepfile +2 -1
  92. data/smoke/regression/issue_372.rb +8 -0
  93. data/smoke/regression/issue_372.rbs +4 -0
  94. data/smoke/regression/test_expectations.yml +0 -12
  95. data/smoke/rescue/Steepfile +2 -1
  96. data/smoke/rescue/test_expectations.yml +3 -3
  97. data/smoke/self/Steepfile +2 -1
  98. data/smoke/skip/Steepfile +2 -1
  99. data/smoke/stdout/Steepfile +2 -1
  100. data/smoke/super/Steepfile +2 -1
  101. data/smoke/toplevel/Steepfile +2 -1
  102. data/smoke/toplevel/test_expectations.yml +3 -3
  103. data/smoke/tsort/Steepfile +4 -5
  104. data/smoke/tsort/test_expectations.yml +2 -2
  105. data/smoke/type_case/Steepfile +2 -1
  106. data/smoke/unexpected/Steepfile +2 -1
  107. data/smoke/yield/Steepfile +2 -1
  108. data/steep.gemspec +2 -2
  109. metadata +24 -10
@@ -5,6 +5,10 @@ module Steep
5
5
  VariableContent = Struct.new(:node, :name, :type, :location, keyword_init: true)
6
6
  MethodCallContent = Struct.new(:node, :method_name, :type, :definition, :location, keyword_init: true)
7
7
  DefinitionContent = Struct.new(:node, :method_name, :method_type, :definition, :location, keyword_init: true) do
8
+ TypeAliasContent = Struct.new(:location, :decl, keyword_init: true)
9
+ ClassContent = Struct.new(:location, :decl, keyword_init: true)
10
+ InterfaceContent = Struct.new(:location, :decl, keyword_init: true)
11
+
8
12
  def comment_string
9
13
  if comments = definition&.comments
10
14
  comments.map {|c| c.string.chomp }.uniq.join("\n----\n")
@@ -50,99 +54,147 @@ module Steep
50
54
  end
51
55
 
52
56
  def content_for(path:, line:, column:)
53
- target = project.target_for_source_path(path)
54
-
55
- if target
56
- file = service.source_files[path]
57
- typing = typecheck(target, path: path, content: file.content, line: line, column: column) or return
57
+ target_for_code, targets_for_sigs = project.targets_for_path(path)
58
58
 
59
- node, *parents = typing.source.find_nodes(line: line, column: column)
59
+ case
60
+ when target = target_for_code
61
+ Steep.logger.info "target #{target}"
60
62
 
61
- if node
62
- case node.type
63
- when :lvar
64
- var_name = node.children[0]
65
- context = typing.context_at(line: line, column: column)
66
- var_type = context.lvar_env[var_name] || AST::Types::Any.new(location: nil)
63
+ hover_for_source(column, line, path, target)
67
64
 
68
- VariableContent.new(node: node, name: var_name, type: var_type, location: node.location.name)
69
- when :lvasgn
70
- var_name, rhs = node.children
71
- context = typing.context_at(line: line, column: column)
72
- type = context.lvar_env[var_name] || typing.type_of(node: rhs)
65
+ when target = targets_for_sigs[0]
66
+ service = self.service.signature_services[target.name]
73
67
 
74
- VariableContent.new(node: node, name: var_name, type: type, location: node.location.name)
75
- when :send
76
- receiver, method_name, *_ = node.children
68
+ _buffer, decls = service.latest_env.buffers_decls.find do |buffer, _|
69
+ Pathname(buffer.name) == path
70
+ end
77
71
 
72
+ return if decls.nil?
73
+
74
+ locator = RBS::Locator.new(decls: decls)
75
+ hd, tail = locator.find2(line: line, column: column)
76
+
77
+ case type = tail[0]
78
+ when RBS::Types::Alias
79
+ alias_decl = service.latest_env.alias_decls[type.name]&.decl or raise
80
+
81
+ location = tail[0].location
82
+ TypeAliasContent.new(
83
+ location: location,
84
+ decl: alias_decl
85
+ )
86
+ when RBS::Types::ClassInstance, RBS::Types::ClassSingleton
87
+ if hd == :name
88
+ env = service.latest_env
89
+ class_decl = env.class_decls[type.name]&.decls[0]&.decl or raise
90
+ location = tail[0].location[:name]
91
+ ClassContent.new(
92
+ location: location,
93
+ decl: class_decl
94
+ )
95
+ end
96
+ when RBS::Types::Interface
97
+ env = service.latest_env
98
+ interface_decl = env.interface_decls[type.name]&.decl or raise
99
+ location = type.location[:name]
100
+
101
+ InterfaceContent.new(
102
+ location: location,
103
+ decl: interface_decl
104
+ )
105
+ end
106
+ end
107
+ end
78
108
 
79
- result_node = if parents[0]&.type == :block
80
- parents[0]
109
+ def hover_for_source(column, line, path, target)
110
+ file = service.source_files[path]
111
+ typing = typecheck(target, path: path, content: file.content, line: line, column: column) or return
112
+ node, *parents = typing.source.find_nodes(line: line, column: column)
113
+
114
+ if node
115
+ case node.type
116
+ when :lvar
117
+ var_name = node.children[0]
118
+ context = typing.context_at(line: line, column: column)
119
+ var_type = context.lvar_env[var_name] || AST::Types::Any.new(location: nil)
120
+
121
+ VariableContent.new(node: node, name: var_name, type: var_type, location: node.location.name)
122
+ when :lvasgn
123
+ var_name, rhs = node.children
124
+ context = typing.context_at(line: line, column: column)
125
+ type = context.lvar_env[var_name] || typing.type_of(node: rhs)
126
+
127
+ VariableContent.new(node: node, name: var_name, type: type, location: node.location.name)
128
+ when :send
129
+ receiver, method_name, *_ = node.children
130
+
131
+ result_node = case parents[0]&.type
132
+ when :block, :numblock
133
+ parents[0]
134
+ else
135
+ node
136
+ end
137
+
138
+ context = typing.context_at(line: line, column: column)
139
+
140
+ receiver_type = if receiver
141
+ typing.type_of(node: receiver)
81
142
  else
82
- node
143
+ context.self_type
83
144
  end
84
145
 
85
- context = typing.context_at(line: line, column: column)
86
-
87
- receiver_type = if receiver
88
- typing.type_of(node: receiver)
89
- else
90
- context.self_type
91
- end
92
-
93
- factory = context.type_env.subtyping.factory
94
- method_name, definition = case receiver_type
95
- when AST::Types::Name::Instance
96
- method_definition = method_definition_for(factory, receiver_type.name, instance_method: method_name)
97
- if method_definition&.defined_in
98
- owner_name = method_definition.defined_in
99
- [
100
- InstanceMethodName.new(owner_name, method_name),
101
- method_definition
102
- ]
103
- end
104
- when AST::Types::Name::Singleton
105
- method_definition = method_definition_for(factory, receiver_type.name, singleton_method: method_name)
106
- if method_definition&.defined_in
107
- owner_name = method_definition.defined_in
108
- [
109
- SingletonMethodName.new(owner_name, method_name),
110
- method_definition
111
- ]
112
- end
113
- else
114
- nil
146
+ factory = context.type_env.subtyping.factory
147
+ method_name, definition = case receiver_type
148
+ when AST::Types::Name::Instance
149
+ method_definition = method_definition_for(factory, receiver_type.name, instance_method: method_name)
150
+ if method_definition&.defined_in
151
+ owner_name = method_definition.defined_in
152
+ [
153
+ InstanceMethodName.new(owner_name, method_name),
154
+ method_definition
155
+ ]
115
156
  end
116
-
117
- MethodCallContent.new(
118
- node: node,
119
- method_name: method_name,
120
- type: typing.type_of(node: result_node),
121
- definition: definition,
122
- location: result_node.location.expression
123
- )
124
- when :def, :defs
125
- context = typing.context_at(line: line, column: column)
126
- method_context = context.method_context
127
-
128
- if method_context && method_context.method
129
- DefinitionContent.new(
130
- node: node,
131
- method_name: method_context.name,
132
- method_type: method_context.method_type,
133
- definition: method_context.method,
134
- location: node.loc.expression
135
- )
136
- end
137
- else
138
- type = typing.type_of(node: node)
139
-
140
- TypeContent.new(
157
+ when AST::Types::Name::Singleton
158
+ method_definition = method_definition_for(factory, receiver_type.name, singleton_method: method_name)
159
+ if method_definition&.defined_in
160
+ owner_name = method_definition.defined_in
161
+ [
162
+ SingletonMethodName.new(owner_name, method_name),
163
+ method_definition
164
+ ]
165
+ end
166
+ else
167
+ nil
168
+ end
169
+
170
+ MethodCallContent.new(
171
+ node: node,
172
+ method_name: method_name,
173
+ type: typing.type_of(node: result_node),
174
+ definition: definition,
175
+ location: result_node.location.expression
176
+ )
177
+ when :def, :defs
178
+ context = typing.context_at(line: line, column: column)
179
+ method_context = context.method_context
180
+
181
+ if method_context && method_context.method
182
+ DefinitionContent.new(
141
183
  node: node,
142
- type: type,
143
- location: node.location.expression
184
+ method_name: method_context.name,
185
+ method_type: method_context.method_type,
186
+ definition: method_context.method,
187
+ location: node.loc.expression
144
188
  )
145
189
  end
190
+ else
191
+ type = typing.type_of(node: node)
192
+
193
+ TypeContent.new(
194
+ node: node,
195
+ type: type,
196
+ location: node.location.expression
197
+ )
146
198
  end
147
199
  end
148
200
  end
@@ -383,6 +383,31 @@ module Steep
383
383
 
384
384
  typing
385
385
  end
386
+
387
+ def source_file?(path)
388
+ if source_files.key?(path)
389
+ project.target_for_source_path(path)
390
+ end
391
+ end
392
+
393
+ def signature_file?(path)
394
+ relative_path = project.relative_path(path)
395
+ targets = signature_services.select {|_, sig| sig.files.key?(relative_path) || sig.env_rbs_paths.include?(path) }
396
+ unless targets.empty?
397
+ targets.keys
398
+ end
399
+ end
400
+
401
+ def app_signature_file?(path)
402
+ target_names = signature_services.select {|_, sig| sig.files.key?(path) }.keys
403
+ unless target_names.empty?
404
+ target_names
405
+ end
406
+ end
407
+
408
+ def lib_signature_file?(path)
409
+ signature_services.each_value.any? {|sig| sig.env_rbs_paths.include?(path) }
410
+ end
386
411
  end
387
412
  end
388
413
  end
data/lib/steep/source.rb CHANGED
@@ -35,28 +35,25 @@ module Steep
35
35
 
36
36
  self.emit_lambda = true
37
37
  self.emit_procarg0 = true
38
+ self.emit_kwargs = true
38
39
  end
39
40
 
40
- def self.parser
41
- ::Parser::Ruby27.new(Builder.new).tap do |parser|
41
+ def self.new_parser
42
+ ::Parser::Ruby30.new(Builder.new).tap do |parser|
42
43
  parser.diagnostics.all_errors_are_fatal = true
43
44
  parser.diagnostics.ignore_warnings = true
44
45
  end
45
46
  end
46
47
 
47
48
  def self.parse(source_code, path:, factory:)
48
- buffer = ::Parser::Source::Buffer.new(path.to_s, 1)
49
- buffer.source = source_code
50
- node = parser.parse(buffer)
49
+ buffer = ::Parser::Source::Buffer.new(path.to_s, 1, source: source_code)
50
+ node = new_parser().parse(buffer)
51
51
 
52
52
  annotations = []
53
53
 
54
54
  _, comments, _ = yield_self do
55
- buffer = ::Parser::Source::Buffer.new(path.to_s)
56
- buffer.source = source_code
57
- parser = ::Parser::Ruby27.new
58
-
59
- parser.tokenize(buffer)
55
+ buffer = ::Parser::Source::Buffer.new(path.to_s, 1, source: source_code)
56
+ new_parser().tokenize(buffer)
60
57
  end
61
58
 
62
59
  buffer = RBS::Buffer.new(name: path, content: source_code)
@@ -10,10 +10,7 @@ module Steep
10
10
  end
11
11
 
12
12
  def with(type: self.type, constr: self.constr)
13
- self.class.new(
14
- type: type,
15
- constr: constr
16
- )
13
+ self.class.new(type: type, constr: constr)
17
14
  end
18
15
 
19
16
  def +(other)
@@ -162,23 +159,6 @@ module Steep
162
159
 
163
160
  # constructor_method = method&.attributes&.include?(:constructor)
164
161
 
165
- if method_type
166
- var_types = TypeConstruction.parameter_types(args, method_type.type)
167
- unless TypeConstruction.valid_parameter_env?(var_types, args.reject {|arg| arg.type == :blockarg}, method_type.type.params)
168
- typing.add_error Diagnostic::Ruby::MethodArityMismatch.new(node: node, method_type: method_type)
169
- end
170
- end
171
-
172
- if (block_arg = args.find {|arg| arg.type == :blockarg})
173
- if method_type&.block
174
- block_type = AST::Types::Proc.new(type: method_type.block.type, block: nil)
175
- if method_type.block.optional?
176
- block_type = AST::Types::Union.build(types: [block_type, AST::Builtin.nil_type])
177
- end
178
- var_types[block_arg.children[0]] = block_type
179
- end
180
- end
181
-
182
162
  super_method = if definition
183
163
  if (this_method = definition.methods[method_name])
184
164
  if module_context&.class_name == this_method.defined_in
@@ -219,13 +199,21 @@ module Steep
219
199
  class_type: module_context.module_type
220
200
  )
221
201
 
222
- if var_types
223
- lvar_env = lvar_env.update(
224
- assigned_types: var_types.each.with_object({}) {|(var, type), hash|
225
- arg_node = args.find {|arg| arg.children[0] == var }
226
- hash[var] = TypeInference::LocalVariableTypeEnv::Entry.new(type: type, nodes: [arg_node].compact)
227
- }
228
- )
202
+ method_params =
203
+ if method_type
204
+ TypeInference::MethodParams.build(node: node, method_type: method_type)
205
+ else
206
+ TypeInference::MethodParams.empty(node: node)
207
+ end
208
+
209
+ method_params.each_param do |param|
210
+ lvar_env = lvar_env.assign(param.name, type: param.var_type, node: param.node) {
211
+ raise "Unexpected assignment error: #{param.name}"
212
+ }
213
+ end
214
+
215
+ method_params.errors.each do |error|
216
+ typing.add_error error
229
217
  end
230
218
 
231
219
  lvar_env = lvar_env.annotate(annots)
@@ -692,7 +680,7 @@ module Steep
692
680
  end
693
681
 
694
682
  def synthesize(node, hint: nil, condition: false)
695
- Steep.logger.tagged "synthesize:(#{node.location.expression.to_s.split(/:/, 2).last})" do
683
+ Steep.logger.tagged "synthesize:(#{node.location&.yield_self {|loc| loc.expression.to_s.split(/:/, 2).last } || "-"})" do
696
684
  Steep.logger.debug node.type
697
685
  case node.type
698
686
  when :begin, :kwbegin
@@ -732,8 +720,17 @@ module Steep
732
720
  when :__skip__
733
721
  add_typing(node, type: AST::Builtin.any_type)
734
722
  else
735
- if !hint || hint.is_a?(AST::Types::Void)
736
- hint = context.lvar_env.declared_types[name]&.type
723
+ if declared_type = context.lvar_env.declared_types[name]&.type
724
+ case hint
725
+ when nil
726
+ hint = declared_type
727
+ else
728
+ if check_relation(sub_type: declared_type, super_type: hint).success?
729
+ # declared_type is compatible with hint and more specific to hint.
730
+ # This typically happens when hint is untyped, top, or void.
731
+ hint = declared_type
732
+ end
733
+ end
737
734
  end
738
735
 
739
736
  rhs_result = synthesize(rhs, hint: hint)
@@ -751,7 +748,7 @@ module Steep
751
748
  end
752
749
  end
753
750
 
754
- add_typing(node, type: rhs_result.type, constr: constr)
751
+ constr.add_typing(node, type: rhs_result.type)
755
752
  end
756
753
  end
757
754
 
@@ -888,13 +885,12 @@ module Steep
888
885
  checker.factory.method_type(method_type, self_type: self_type, method_decls: Set[decl])
889
886
  }
890
887
  )
891
- args = TypeInference::SendArgs.from_nodes(node.children.dup)
892
888
 
893
889
  call, constr = type_method_call(node,
894
890
  receiver_type: self_type,
895
891
  method_name: method_context.name,
896
892
  method: super_method,
897
- args: args,
893
+ arguments: node.children,
898
894
  block_params: nil,
899
895
  block_body: nil,
900
896
  topdown_hint: true)
@@ -940,18 +936,46 @@ module Steep
940
936
  end
941
937
  end
942
938
 
939
+ when :numblock
940
+ yield_self do
941
+ send_node, max_num, body = node.children
942
+
943
+ if max_num == 1
944
+ arg_nodes = [Parser::AST::Node.new(:procarg0, [:_1])]
945
+ else
946
+ arg_nodes = max_num.times.map {|i| Parser::AST::Node.new(:arg, [:"_#{i+1}"]) }
947
+ end
948
+
949
+ params = Parser::AST::Node.new(:args, arg_nodes)
950
+
951
+ if send_node.type == :lambda
952
+ type_lambda(node, block_params: params, block_body: body, type_hint: hint)
953
+ else
954
+ type_send(node, send_node: send_node, block_params: params, block_body: body, unwrap: send_node.type == :csend)
955
+ end
956
+ end
957
+
943
958
  when :def
944
959
  yield_self do
945
960
  name, args_node, body_node = node.children
946
961
 
947
- new = for_new_method(name,
948
- node,
949
- args: args_node.children,
950
- self_type: module_context&.instance_type,
951
- definition: module_context&.instance_definition)
962
+ new = for_new_method(
963
+ name,
964
+ node,
965
+ args: args_node.children,
966
+ self_type: module_context&.instance_type,
967
+ definition: module_context&.instance_definition
968
+ )
952
969
  new.typing.add_context_for_node(node, context: new.context)
953
970
  new.typing.add_context_for_body(node, context: new.context)
954
971
 
972
+ new.method_context.tap do |method_context|
973
+ if method_context.method
974
+ method_name = InstanceMethodName.new(type_name: method_context.method.implemented_in, method_name: name)
975
+ new.typing.source_index.add_definition(method: method_name, definition: node)
976
+ end
977
+ end
978
+
955
979
  new = new.synthesize_children(args_node)
956
980
 
957
981
  body_pair = if body_node
@@ -990,10 +1014,13 @@ module Steep
990
1014
  end
991
1015
 
992
1016
  if body_node
993
- begin_pos = body_node.loc.expression.end_pos
994
- end_pos = node.loc.end.begin_pos
995
-
996
- typing.add_context(begin_pos..end_pos, context: body_pair.context)
1017
+ # Add context to ranges from the end of the method body to the beginning of the `end` keyword
1018
+ if node.loc.end
1019
+ # Skip end-less def
1020
+ begin_pos = body_node.loc.expression.end_pos
1021
+ end_pos = node.loc.end.begin_pos
1022
+ typing.add_context(begin_pos..end_pos, context: body_pair.context)
1023
+ end
997
1024
  end
998
1025
 
999
1026
  if module_context
@@ -1006,24 +1033,43 @@ module Steep
1006
1033
  when :defs
1007
1034
  synthesize(node.children[0]).type.tap do |self_type|
1008
1035
  self_type = expand_self(self_type)
1009
- definition = case self_type
1010
- when AST::Types::Name::Instance
1011
- name = self_type.name
1012
- checker.factory.definition_builder.build_singleton(name)
1013
- when AST::Types::Name::Singleton
1014
- name = self_type.name
1015
- checker.factory.definition_builder.build_singleton(name)
1016
- end
1036
+ definition =
1037
+ case self_type
1038
+ when AST::Types::Name::Instance
1039
+ name = self_type.name
1040
+ checker.factory.definition_builder.build_instance(name)
1041
+ when AST::Types::Name::Singleton
1042
+ name = self_type.name
1043
+ checker.factory.definition_builder.build_singleton(name)
1044
+ end
1017
1045
 
1018
1046
  args_node = node.children[2]
1019
- new = for_new_method(node.children[1],
1020
- node,
1021
- args: args_node.children,
1022
- self_type: self_type,
1023
- definition: definition)
1047
+ new = for_new_method(
1048
+ node.children[1],
1049
+ node,
1050
+ args: args_node.children,
1051
+ self_type: self_type,
1052
+ definition: definition
1053
+ )
1024
1054
  new.typing.add_context_for_node(node, context: new.context)
1025
1055
  new.typing.add_context_for_body(node, context: new.context)
1026
1056
 
1057
+ new.method_context.tap do |method_context|
1058
+ if method_context.method
1059
+ name_ = node.children[1]
1060
+
1061
+ method_name =
1062
+ case self_type
1063
+ when AST::Types::Name::Instance
1064
+ InstanceMethodName.new(type_name: method_context.method.implemented_in, method_name: name_)
1065
+ when AST::Types::Name::Singleton
1066
+ SingletonMethodName.new(type_name: method_context.method.implemented_in, method_name: name_)
1067
+ end
1068
+
1069
+ new.typing.source_index.add_definition(method: method_name, definition: node)
1070
+ end
1071
+ end
1072
+
1027
1073
  new = new.synthesize_children(args_node)
1028
1074
 
1029
1075
  each_child_node(node.children[2]) do |arg|
@@ -1115,15 +1161,16 @@ module Steep
1115
1161
  )
1116
1162
  end
1117
1163
  else
1118
- check_relation(sub_type: AST::Builtin.nil_type, super_type: break_type).else do |result|
1119
- typing.add_error(
1120
- Diagnostic::Ruby::BreakTypeMismatch.new(
1121
- node: node,
1122
- expected: break_type,
1123
- actual: AST::Builtin.nil_type,
1124
- result: result
1164
+ unless break_type.is_a?(AST::Types::Bot)
1165
+ check_relation(sub_type: AST::Builtin.nil_type, super_type: break_type).else do |result|
1166
+ typing.add_error(
1167
+ Diagnostic::Ruby::ImplicitBreakValueMismatch.new(
1168
+ node: node,
1169
+ jump_type: break_type,
1170
+ result: result
1171
+ )
1125
1172
  )
1126
- )
1173
+ end
1127
1174
  end
1128
1175
  end
1129
1176
  else
@@ -1335,52 +1382,20 @@ module Steep
1335
1382
  add_typing(node, type: AST::Types::Boolean.new)
1336
1383
  end
1337
1384
 
1338
- when :hash
1339
- yield_self do
1340
- ty = try_hash_type(node, hint) and return ty
1341
-
1342
- if AST::Builtin::Hash.instance_type?(hint)
1343
- key_hint = hint.args[0]
1344
- value_hint = hint.args[1]
1345
- end
1346
-
1347
- key_types = []
1348
- value_types = []
1349
-
1350
- each_child_node(node) do |child|
1351
- case child.type
1352
- when :pair
1353
- key, value = child.children
1354
- key_types << synthesize(key, hint: key_hint).type.yield_self do |type|
1355
- select_super_type(type, key_hint)
1356
- end
1357
- value_types << synthesize(value, hint: value_hint).type.yield_self do |type|
1358
- select_super_type(type, value_hint)
1359
- end
1360
- when :kwsplat
1361
- expand_alias(synthesize(child.children[0]).type) do |splat_type, original_type|
1362
- if AST::Builtin::Hash.instance_type?(splat_type)
1363
- key_types << splat_type.args[0]
1364
- value_types << splat_type.args[1]
1365
- else
1366
- typing.add_error Diagnostic::Ruby::UnexpectedSplat.new(node: child, type: original_type)
1367
- key_types << AST::Builtin.any_type
1368
- value_types << AST::Builtin.any_type
1369
- end
1370
- end
1385
+ when :hash, :kwargs
1386
+ # :kwargs happens for method calls with keyword argument, but the method doesn't have keyword params.
1387
+ # Conversion from kwargs to hash happens, and this when-clause is to support it.
1388
+ type_hash(node, hint: hint).tap do |pair|
1389
+ if pair.type == AST::Builtin::Hash.instance_type(fill_untyped: true)
1390
+ case hint
1391
+ when AST::Types::Any, AST::Types::Top, AST::Types::Void
1392
+ # ok
1393
+ when hint == pair.type
1394
+ # ok
1371
1395
  else
1372
- raise "Unexpected non pair: #{child.inspect}" unless child.type == :pair
1396
+ pair.constr.typing.add_error Diagnostic::Ruby::FallbackAny.new(node: node)
1373
1397
  end
1374
1398
  end
1375
-
1376
- key_type = key_types.empty? ? AST::Builtin.any_type : AST::Types::Union.build(types: key_types)
1377
- value_type = value_types.empty? ? AST::Builtin.any_type : AST::Types::Union.build(types: value_types)
1378
-
1379
- if key_types.empty? && value_types.empty? && !hint
1380
- typing.add_error Diagnostic::Ruby::FallbackAny.new(node: node)
1381
- end
1382
-
1383
- add_typing(node, type: AST::Builtin::Hash.instance_type(key_type, value_type))
1384
1399
  end
1385
1400
 
1386
1401
  when :dstr, :xstr
@@ -1443,9 +1458,22 @@ module Steep
1443
1458
  constr = self
1444
1459
 
1445
1460
  name, _ = node.children
1446
- _, constr = constr.synthesize(name)
1461
+ if name.type == :const
1462
+ # skip the last constant reference
1463
+ if const_parent = name.children[0]
1464
+ _, constr = constr.synthesize(const_parent)
1465
+ end
1466
+ else
1467
+ _, constr = constr.synthesize(name)
1468
+ end
1447
1469
 
1448
1470
  for_module(node).yield_self do |constructor|
1471
+ if module_type = constructor.module_context&.module_type
1472
+ _, constructor = constructor.add_typing(name, type: module_type)
1473
+ else
1474
+ _, constructor = constructor.fallback_to_any(name)
1475
+ end
1476
+
1449
1477
  constructor.typing.source_index.add_definition(
1450
1478
  constant: constructor.module_context.class_name,
1451
1479
  definition: node
@@ -1642,8 +1670,7 @@ module Steep
1642
1670
  tuples.each do |tuple|
1643
1671
  typing.new_child(node_range) do |child_typing|
1644
1672
  if pair = with_new_typing(child_typing).try_tuple_type(node, tuple)
1645
- child_typing.save!
1646
- return pair.with(constr: pair.constr.with_new_typing(typing))
1673
+ return pair.with(constr: pair.constr.save_typing)
1647
1674
  end
1648
1675
  end
1649
1676
  end
@@ -1654,8 +1681,7 @@ module Steep
1654
1681
  typing.new_child(node_range) do |child_typing|
1655
1682
  pair = with_new_typing(child_typing).try_array_type(node, array)
1656
1683
  if pair.constr.check_relation(sub_type: pair.type, super_type: hint).success?
1657
- child_typing.save!
1658
- return pair.with(constr: pair.constr.with_new_typing(typing))
1684
+ return pair.with(constr: pair.constr.save_typing)
1659
1685
  end
1660
1686
  end
1661
1687
  end
@@ -2250,7 +2276,9 @@ module Steep
2250
2276
  unless return_types.empty?
2251
2277
  type = AST::Types::Proc.new(
2252
2278
  type: Interface::Function.new(
2253
- params: Interface::Function::Params.empty.update(required: [param_type]),
2279
+ params: Interface::Function::Params.empty.with_first_param(
2280
+ Interface::Function::Params::PositionalParams::Required.new(param_type)
2281
+ ),
2254
2282
  return_type: AST::Types::Union.build(types: return_types),
2255
2283
  location: nil
2256
2284
  ),
@@ -2348,6 +2376,7 @@ module Steep
2348
2376
 
2349
2377
  else
2350
2378
  typing.add_error(Diagnostic::Ruby::UnsupportedSyntax.new(node: node))
2379
+ add_typing(node, type: AST::Builtin.any_type)
2351
2380
 
2352
2381
  end.tap do |pair|
2353
2382
  unless pair.is_a?(Pair) && !pair.type.is_a?(Pair)
@@ -2697,11 +2726,10 @@ module Steep
2697
2726
  method = interface.methods[method_name]
2698
2727
 
2699
2728
  if method
2700
- args = TypeInference::SendArgs.from_nodes(arguments)
2701
2729
  call, constr = type_method_call(node,
2702
2730
  method: method,
2703
2731
  method_name: method_name,
2704
- args: args,
2732
+ arguments: arguments,
2705
2733
  block_params: block_params,
2706
2734
  block_body: block_body,
2707
2735
  receiver_type: receiver_type,
@@ -2881,27 +2909,22 @@ module Steep
2881
2909
  end
2882
2910
  end
2883
2911
 
2884
- def type_method_call(node, method_name:, receiver_type:, method:, args:, block_params:, block_body:, topdown_hint:)
2912
+ def type_method_call(node, method_name:, receiver_type:, method:, arguments:, block_params:, block_body:, topdown_hint:)
2885
2913
  node_range = node.loc.expression.yield_self {|l| l.begin_pos..l.end_pos }
2886
2914
 
2887
- results = method.method_types.flat_map do |method_type|
2915
+ results = method.method_types.map do |method_type|
2888
2916
  Steep.logger.tagged method_type.to_s do
2889
- zips = args.zips(method_type.type.params, method_type.block&.type)
2890
-
2891
- zips.map do |arg_pairs|
2892
- typing.new_child(node_range) do |child_typing|
2893
- self.with_new_typing(child_typing).try_method_type(
2894
- node,
2895
- receiver_type: receiver_type,
2896
- method_name: method_name,
2897
- method_type: method_type,
2898
- args: args,
2899
- arg_pairs: arg_pairs,
2900
- block_params: block_params,
2901
- block_body: block_body,
2902
- topdown_hint: topdown_hint
2903
- )
2904
- end
2917
+ typing.new_child(node_range) do |child_typing|
2918
+ self.with_new_typing(child_typing).try_method_type(
2919
+ node,
2920
+ receiver_type: receiver_type,
2921
+ method_name: method_name,
2922
+ method_type: method_type,
2923
+ arguments: arguments,
2924
+ block_params: block_params,
2925
+ block_body: block_body,
2926
+ topdown_hint: topdown_hint
2927
+ )
2905
2928
  end
2906
2929
  end
2907
2930
  end
@@ -2941,138 +2964,34 @@ module Steep
2941
2964
  ]
2942
2965
  end
2943
2966
 
2944
- def check_keyword_arg(receiver_type:, node:, method_type:, constraints:)
2945
- params = method_type.type.params
2946
-
2947
- case node.type
2948
- when :hash
2949
- keyword_hash_type = AST::Builtin::Hash.instance_type(AST::Builtin::Symbol.instance_type,
2950
- AST::Builtin.any_type)
2951
- add_typing node, type: keyword_hash_type
2952
-
2953
- given_keys = Set.new()
2954
-
2955
- node.children.each do |element|
2956
- case element.type
2957
- when :pair
2958
- key_node, value_node = element.children
2959
-
2960
- case key_node.type
2961
- when :sym
2962
- key_symbol = key_node.children[0]
2963
- keyword_type = case
2964
- when params.required_keywords.key?(key_symbol)
2965
- params.required_keywords[key_symbol]
2966
- when params.optional_keywords.key?(key_symbol)
2967
- AST::Types::Union.build(
2968
- types: [params.optional_keywords[key_symbol],
2969
- AST::Builtin.nil_type]
2970
- )
2971
- when params.rest_keywords
2972
- params.rest_keywords
2973
- end
2974
-
2975
- add_typing key_node, type: AST::Builtin::Symbol.instance_type
2976
-
2977
- given_keys << key_symbol
2978
-
2979
- if keyword_type
2980
- check(value_node, keyword_type, constraints: constraints) do |expected, actual, result|
2981
- return Diagnostic::Ruby::IncompatibleAssignment.new(
2982
- node: value_node,
2983
- lhs_type: expected,
2984
- rhs_type: actual,
2985
- result: result
2986
- )
2987
- end
2988
- else
2989
- synthesize(value_node)
2990
- end
2991
-
2992
- else
2993
- check(key_node, AST::Builtin::Symbol.instance_type, constraints: constraints) do |expected, actual, result|
2994
- return Diagnostic::Ruby::IncompatibleAssignment.new(
2995
- node: key_node,
2996
- lhs_type: expected,
2997
- rhs_type: actual,
2998
- result: result
2999
- )
3000
- end
3001
- end
3002
-
3003
- when :kwsplat
3004
- Steep.logger.warn("Keyword arg with kwsplat(**) node are not supported.")
3005
-
3006
- check(element.children[0], keyword_hash_type, constraints: constraints) do |expected, actual, result|
3007
- return Diagnostic::Ruby::IncompatibleAssignment.new(
3008
- node: node,
3009
- lhs_type: expected,
3010
- rhs_type: actual,
3011
- result: result
3012
- )
3013
- end
3014
-
3015
- given_keys = true
3016
- end
3017
- end
2967
+ def inspect
2968
+ "#<#{self.class}>"
2969
+ end
3018
2970
 
3019
- case given_keys
3020
- when Set
3021
- missing_keywords = Set.new(params.required_keywords.keys) - given_keys
3022
- unless missing_keywords.empty?
3023
- return Diagnostic::Ruby::MissingKeyword.new(
3024
- node: node,
3025
- missing_keywords: missing_keywords
3026
- )
3027
- end
2971
+ def with_child_typing(range:)
2972
+ constr = with_new_typing(typing.new_child(range: range))
3028
2973
 
3029
- extra_keywords = given_keys - Set.new(params.required_keywords.keys) - Set.new(params.optional_keywords.keys)
3030
- if extra_keywords.any? && !params.rest_keywords
3031
- return Diagnostic::Ruby::UnexpectedKeyword.new(
3032
- node: node,
3033
- unexpected_keywords: extra_keywords
3034
- )
3035
- end
3036
- end
2974
+ if block_given?
2975
+ yield constr
3037
2976
  else
3038
- if params.rest_keywords
3039
- Steep.logger.warn("Method call with rest keywords type is detected. Rough approximation to be improved.")
3040
-
3041
- value_types = params.required_keywords.values +
3042
- params.optional_keywords.values.map {|type| AST::Types::Union.build(types: [type, AST::Builtin.nil_type])} +
3043
- [params.rest_keywords]
3044
-
3045
- hash_type = AST::Builtin::Hash.instance_type(
3046
- AST::Builtin::Symbol.instance_type,
3047
- AST::Types::Union.build(types: value_types)
3048
- )
3049
- else
3050
- hash_elements = params.required_keywords.merge(
3051
- params.optional_keywords.transform_values do |type|
3052
- AST::Types::Union.build(types: [type, AST::Builtin.nil_type])
3053
- end
3054
- )
3055
-
3056
- hash_type = AST::Types::Record.new(elements: hash_elements)
3057
- end
2977
+ constr
2978
+ end
2979
+ end
3058
2980
 
3059
- node_type = synthesize(node, hint: hash_type).type
2981
+ # Bypass :splat and :kwsplat
2982
+ def bypass_splat(node)
2983
+ splat = node.type == :splat || node.type == :kwsplat
3060
2984
 
3061
- check_relation(sub_type: node_type, super_type: hash_type).else do |result|
3062
- return Diagnostic::Ruby::ArgumentTypeMismatch.new(
3063
- node: node,
3064
- receiver_type: receiver_type,
3065
- expected: hash_type,
3066
- actual: node_type,
3067
- result: result
3068
- )
3069
- end
2985
+ if splat
2986
+ pair = yield(node.children[0])
2987
+ pair.constr.add_typing(node, type: pair.type)
2988
+ pair
2989
+ else
2990
+ yield node
3070
2991
  end
3071
-
3072
- nil
3073
2992
  end
3074
2993
 
3075
- def try_method_type(node, receiver_type:, method_name:, method_type:, args:, arg_pairs:, block_params:, block_body:, topdown_hint:)
2994
+ def try_method_type(node, receiver_type:, method_name:, method_type:, arguments:, block_params:, block_body:, topdown_hint:)
3076
2995
  fresh_types = method_type.type_params.map {|x| AST::Types::Var.fresh(x)}
3077
2996
  fresh_vars = Set.new(fresh_types.map(&:name))
3078
2997
  instantiation = Interface::Substitution.build(method_type.type_params, fresh_types)
@@ -3087,38 +3006,90 @@ module Steep
3087
3006
 
3088
3007
  errors = []
3089
3008
 
3090
- arg_pairs.each do |pair|
3091
- case pair
3092
- when Array
3093
- arg_node, param_type = pair
3094
- param_type = param_type.subst(instantiation)
3009
+ args = TypeInference::SendArgs.new(node: node, arguments: arguments, method_name: method_name, method_type: method_type)
3010
+ es = args.each do |arg|
3011
+ case arg
3012
+ when TypeInference::SendArgs::PositionalArgs::NodeParamPair
3013
+ _, constr = constr.type_check_argument(
3014
+ arg.node,
3015
+ type: arg.param.type,
3016
+ receiver_type: receiver_type,
3017
+ constraints: constraints,
3018
+ errors: errors
3019
+ )
3095
3020
 
3096
- arg_type, constr = if arg_node.type == :splat
3097
- constr.synthesize(arg_node.children[0])
3098
- else
3099
- constr.synthesize(arg_node, hint: topdown_hint ? param_type : nil)
3100
- end
3021
+ when TypeInference::SendArgs::PositionalArgs::NodeTypePair
3022
+ _, constr = bypass_splat(arg.node) do |n|
3023
+ constr.type_check_argument(
3024
+ n,
3025
+ type: arg.node_type,
3026
+ receiver_type: receiver_type,
3027
+ constraints: constraints,
3028
+ report_node: arg.node,
3029
+ errors: errors
3030
+ )
3031
+ end
3101
3032
 
3102
- check_relation(sub_type: arg_type, super_type: param_type, constraints: constraints).else do |result|
3103
- errors << Diagnostic::Ruby::ArgumentTypeMismatch.new(node: arg_node,
3104
- receiver_type: receiver_type,
3105
- expected: param_type,
3106
- actual: arg_type,
3107
- result: result)
3033
+ when TypeInference::SendArgs::PositionalArgs::UnexpectedArg
3034
+ _, constr = bypass_splat(arg.node) do |n|
3035
+ constr.synthesize(n)
3036
+ end
3037
+
3038
+ when TypeInference::SendArgs::PositionalArgs::SplatArg
3039
+ arg_type, _ = constr
3040
+ .with_child_typing(range: arg.node.loc.expression.begin_pos ... arg.node.loc.expression.end_pos)
3041
+ .try_tuple_type!(arg.node.children[0])
3042
+ arg.type = arg_type
3043
+
3044
+ when TypeInference::SendArgs::PositionalArgs::MissingArg
3045
+ # ignore
3046
+
3047
+ when TypeInference::SendArgs::KeywordArgs::ArgTypePairs
3048
+ arg.pairs.each do |node, type|
3049
+ _, constr = bypass_splat(node) do |node|
3050
+ constr.type_check_argument(
3051
+ node,
3052
+ type: type,
3053
+ receiver_type: receiver_type,
3054
+ constraints: constraints,
3055
+ errors: errors
3056
+ )
3057
+ end
3058
+ end
3059
+
3060
+ when TypeInference::SendArgs::KeywordArgs::UnexpectedKeyword
3061
+ if arg.node.type == :pair
3062
+ arg.node.children.each do |nn|
3063
+ _, constr = constr.synthesize(nn)
3064
+ end
3065
+ else
3066
+ _, constr = bypass_splat(arg.node) do |n|
3067
+ constr.synthesize(n)
3068
+ end
3108
3069
  end
3109
- else
3110
- # keyword
3111
- result = constr.check_keyword_arg(receiver_type: receiver_type,
3112
- node: pair,
3113
- method_type: method_type,
3114
- constraints: constraints)
3115
3070
 
3116
- if result.is_a?(Diagnostic::Ruby::Base)
3117
- errors << result
3071
+ when TypeInference::SendArgs::KeywordArgs::SplatArg
3072
+ type, _ = bypass_splat(arg.node) do |sp_node|
3073
+ if sp_node.type == :hash
3074
+ pair = constr.type_hash_record(sp_node, nil) and break pair
3075
+ end
3076
+
3077
+ constr.synthesize(sp_node)
3118
3078
  end
3079
+
3080
+ arg.type = type
3081
+
3082
+ when TypeInference::SendArgs::KeywordArgs::MissingKeyword
3083
+ # ignore
3084
+ else
3085
+ raise arg.inspect
3119
3086
  end
3087
+
3088
+ constr
3120
3089
  end
3121
3090
 
3091
+ errors.push(*es)
3092
+
3122
3093
  if block_params
3123
3094
  # block is given
3124
3095
  block_annotations = source.annotations(block: node, factory: checker.factory, current_module: current_namespace)
@@ -3261,104 +3232,105 @@ module Steep
3261
3232
  )
3262
3233
  end
3263
3234
  else
3264
- # block is not given
3265
- if (!method_type.block || method_type.block.optional?)
3266
- # Method call without block is allowed
3267
- unless args.block_pass_arg
3268
- # OK, without block
3269
- s = constraints.solution(
3235
+ arg = args.block_pass_arg
3236
+
3237
+ case
3238
+ when arg.compatible?
3239
+ if arg.node
3240
+ subst = constraints.solution(
3270
3241
  checker,
3271
- variance: variance,
3272
- variables: fresh_vars,
3273
3242
  self_type: self_type,
3274
3243
  instance_type: module_context.instance_type,
3275
- class_type: module_context.module_type
3244
+ class_type: module_context.module_type,
3245
+ variance: variance,
3246
+ variables: occurence.params
3276
3247
  )
3277
- method_type = method_type.subst(s)
3278
- else
3279
- # &block arg is given
3280
- s = constraints.solution(
3248
+
3249
+ block_type = arg.node_type.subst(subst)
3250
+
3251
+ node_type, constr = constr.synthesize(arg.node, hint: block_type)
3252
+ nil_block =
3253
+ constr.check_relation(sub_type: node_type, super_type: AST::Builtin.nil_type).success? &&
3254
+ !node_type.is_a?(AST::Types::Any)
3255
+
3256
+ unless nil_block
3257
+ constr.check_relation(sub_type: node_type, super_type: block_type, constraints: constraints).else do |result|
3258
+ errors << Diagnostic::Ruby::BlockTypeMismatch.new(
3259
+ node: arg.node,
3260
+ expected: block_type,
3261
+ actual: node_type,
3262
+ result: result
3263
+ )
3264
+ end
3265
+ end
3266
+
3267
+ subst = constraints.solution(
3281
3268
  checker,
3282
- variance: variance,
3283
- variables: fresh_vars,
3284
3269
  self_type: self_type,
3285
3270
  instance_type: module_context.instance_type,
3286
- class_type: module_context.module_type
3271
+ class_type: module_context.module_type,
3272
+ variance: variance,
3273
+ variables: method_type.free_variables
3287
3274
  )
3288
- method_type = method_type.subst(s)
3289
3275
 
3290
- type, constr = constr.synthesize(args.block_pass_arg, hint: AST::Builtin.nil_type)
3291
- type = expand_alias(type)
3292
- unless type.is_a?(AST::Types::Nil)
3293
- errors << Diagnostic::Ruby::UnexpectedBlockGiven.new(
3276
+ method_type = method_type.subst(subst)
3277
+
3278
+ if nil_block && arg.block.required?
3279
+ # Passing no block
3280
+ errors << Diagnostic::Ruby::RequiredBlockMissing.new(
3294
3281
  node: node,
3295
3282
  method_type: method_type
3296
3283
  )
3297
3284
  end
3298
- end
3299
- else
3300
- unless args.block_pass_arg
3301
- # Required block is missing
3302
- errors << Diagnostic::Ruby::RequiredBlockMissing.new(
3303
- node: node,
3304
- method_type: method_type
3305
- )
3306
-
3307
- s = constraints.solution(
3285
+ else
3286
+ subst = constraints.solution(
3308
3287
  checker,
3309
- variance: variance,
3310
- variables: fresh_vars,
3311
3288
  self_type: self_type,
3312
3289
  instance_type: module_context.instance_type,
3313
- class_type: module_context.module_type
3290
+ class_type: module_context.module_type,
3291
+ variance: variance,
3292
+ variables: method_type.free_variables
3314
3293
  )
3315
- method_type = method_type.subst(s)
3316
- else
3317
- begin
3318
- method_type = method_type.subst(
3319
- constraints.solution(
3320
- checker,
3321
- self_type: self_type,
3322
- instance_type: module_context.instance_type,
3323
- class_type: module_context.module_type,
3324
- variance: variance,
3325
- variables: occurence.params
3326
- )
3327
- )
3328
- hint_type = if topdown_hint
3329
- AST::Types::Proc.new(type: method_type.block.type, block: nil)
3330
- end
3331
- given_block_type, constr = constr.synthesize(args.block_pass_arg, hint: hint_type)
3332
- method_block_type = method_type.block.yield_self {|expected_block|
3333
- proc_type = AST::Types::Proc.new(type: expected_block.type, block: nil)
3334
- if expected_block.optional?
3335
- AST::Builtin.optional(proc_type)
3336
- else
3337
- proc_type
3338
- end
3339
- }
3340
3294
 
3341
- result = check_relation(sub_type: given_block_type, super_type: method_block_type, constraints: constraints)
3342
- result.else do |result|
3343
- errors << Diagnostic::Ruby::BlockTypeMismatch.new(
3344
- node: args.block_pass_arg,
3345
- expected: method_block_type,
3346
- actual: given_block_type,
3347
- result: result
3348
- )
3349
- end
3295
+ method_type = method_type.subst(subst)
3296
+ end
3350
3297
 
3351
- method_type = method_type.subst(
3352
- constraints.solution(
3353
- checker,
3354
- self_type: self_type,
3355
- instance_type: module_context.instance_type,
3356
- class_type: module_context.module_type,
3357
- variance: variance,
3358
- variables: method_type.free_variables
3359
- )
3360
- )
3361
- end
3298
+ when arg.block_missing?
3299
+ subst = constraints.solution(
3300
+ checker,
3301
+ self_type: self_type,
3302
+ instance_type: module_context.instance_type,
3303
+ class_type: module_context.module_type,
3304
+ variance: variance,
3305
+ variables: method_type.free_variables
3306
+ )
3307
+
3308
+ method_type = method_type.subst(subst)
3309
+
3310
+ errors << Diagnostic::Ruby::RequiredBlockMissing.new(
3311
+ node: node,
3312
+ method_type: method_type
3313
+ )
3314
+
3315
+ when arg.unexpected_block?
3316
+ subst = constraints.solution(
3317
+ checker,
3318
+ self_type: self_type,
3319
+ instance_type: module_context.instance_type,
3320
+ class_type: module_context.module_type,
3321
+ variance: variance,
3322
+ variables: method_type.free_variables
3323
+ )
3324
+
3325
+ method_type = method_type.subst(subst)
3326
+
3327
+ node_type, constr = constr.synthesize(arg.node)
3328
+
3329
+ unless constr.check_relation(sub_type: node_type, super_type: AST::Builtin.nil_type).success?
3330
+ errors << Diagnostic::Ruby::UnexpectedBlockGiven.new(
3331
+ node: node,
3332
+ method_type: method_type
3333
+ )
3362
3334
  end
3363
3335
  end
3364
3336
  end
@@ -3391,6 +3363,18 @@ module Steep
3391
3363
  ]
3392
3364
  end
3393
3365
 
3366
+ def type_check_argument(node, receiver_type:, type:, constraints:, report_node: node, errors:)
3367
+ check(node, type, constraints: constraints) do |expected, actual, result|
3368
+ errors << Diagnostic::Ruby::ArgumentTypeMismatch.new(
3369
+ node: report_node,
3370
+ receiver_type: receiver_type,
3371
+ expected: expected,
3372
+ actual: actual,
3373
+ result: result
3374
+ )
3375
+ end
3376
+ end
3377
+
3394
3378
  def type_block_without_hint(node:, block_annotations:, block_params:, block_body:, &block)
3395
3379
  unless block_params
3396
3380
  typing.add_error(
@@ -3531,68 +3515,6 @@ module Steep
3531
3515
  end
3532
3516
  end
3533
3517
 
3534
- def self.parameter_types(nodes, type)
3535
- nodes = nodes.dup
3536
-
3537
- env = {}
3538
-
3539
- type.params.required.each do |type|
3540
- a = nodes.first
3541
- if a&.type == :arg
3542
- env[a.children.first] = type
3543
- nodes.shift
3544
- else
3545
- break
3546
- end
3547
- end
3548
-
3549
- type.params.optional.each do |type|
3550
- a = nodes.first
3551
-
3552
- if a&.type == :optarg
3553
- env[a.children.first] = type
3554
- nodes.shift
3555
- else
3556
- break
3557
- end
3558
- end
3559
-
3560
- if type.params.rest
3561
- a = nodes.first
3562
- if a&.type == :restarg
3563
- env[a.children.first] = AST::Builtin::Array.instance_type(type.params.rest)
3564
- nodes.shift
3565
- end
3566
- end
3567
-
3568
- nodes.each do |node|
3569
- if node.type == :kwarg
3570
- name = node.children[0]
3571
- ty = type.params.required_keywords[name]
3572
- env[name] = ty if ty
3573
- end
3574
-
3575
- if node.type == :kwoptarg
3576
- name = node.children[0]
3577
- ty = type.params.optional_keywords[name]
3578
- env[name] = ty if ty
3579
- end
3580
-
3581
- if node.type == :kwrestarg
3582
- ty = type.params.rest_keywords
3583
- if ty
3584
- env[node.children[0]] = AST::Builtin::Hash.instance_type(AST::Builtin::Symbol.instance_type, ty)
3585
- end
3586
- end
3587
- end
3588
-
3589
- env
3590
- end
3591
-
3592
- def self.valid_parameter_env?(env, nodes, params)
3593
- env.size == nodes.size && env.size == params.size
3594
- end
3595
-
3596
3518
  def current_namespace
3597
3519
  module_context&.current_namespace || AST::Namespace.root
3598
3520
  end
@@ -3700,25 +3622,6 @@ module Steep
3700
3622
  end
3701
3623
  end
3702
3624
 
3703
- def flatten_const_name(node)
3704
- path = []
3705
-
3706
- while node
3707
- case node.type
3708
- when :const, :casgn
3709
- path.unshift(node.children[1])
3710
- node = node.children[0]
3711
- when :cbase
3712
- path.unshift("")
3713
- break
3714
- else
3715
- return nil
3716
- end
3717
- end
3718
-
3719
- path.join("::").to_sym
3720
- end
3721
-
3722
3625
  def fallback_to_any(node)
3723
3626
  if block_given?
3724
3627
  typing.add_error yield
@@ -3760,16 +3663,6 @@ module Steep
3760
3663
  Pair.new(type: AST::Builtin.any_type, constr: self)
3761
3664
  end
3762
3665
 
3763
- def fallback_any_rec(node)
3764
- fallback_to_any(node) unless typing.has_type?(node)
3765
-
3766
- each_child_node(node) do |child|
3767
- fallback_any_rec(child)
3768
- end
3769
-
3770
- typing.type_of(node: node)
3771
- end
3772
-
3773
3666
  def unwrap(type)
3774
3667
  expand_alias(type) do |expanded|
3775
3668
  case
@@ -3782,19 +3675,6 @@ module Steep
3782
3675
  end
3783
3676
  end
3784
3677
 
3785
- def self.value_variables(node)
3786
- case node&.type
3787
- when :lvar
3788
- Set.new([node.children.first])
3789
- when :lvasgn
3790
- Set.new([node.children.first]) + value_variables(node.children[1])
3791
- when :begin
3792
- value_variables(node.children.last)
3793
- else
3794
- Set.new
3795
- end
3796
- end
3797
-
3798
3678
  def deep_expand_alias(type, &block)
3799
3679
  checker.factory.deep_expand_alias(type, &block)
3800
3680
  end
@@ -3841,24 +3721,6 @@ module Steep
3841
3721
  end
3842
3722
  end
3843
3723
 
3844
- def select_super_type(sub_type, super_type)
3845
- if super_type
3846
- result = check_relation(sub_type: sub_type, super_type: super_type)
3847
-
3848
- if result.success?
3849
- super_type
3850
- else
3851
- if block_given?
3852
- yield result
3853
- else
3854
- sub_type
3855
- end
3856
- end
3857
- else
3858
- sub_type
3859
- end
3860
- end
3861
-
3862
3724
  def to_instance_type(type, args: nil)
3863
3725
  args = args || case type
3864
3726
  when AST::Types::Name::Singleton
@@ -3870,16 +3732,35 @@ module Steep
3870
3732
  AST::Types::Name::Instance.new(name: type.name, args: args)
3871
3733
  end
3872
3734
 
3735
+ def try_tuple_type!(node, hint: nil)
3736
+ if node.type == :array && (hint.nil? || hint.is_a?(AST::Types::Tuple))
3737
+ node_range = node.loc.expression.yield_self {|l| l.begin_pos..l.end_pos }
3738
+
3739
+ typing.new_child(node_range) do |child_typing|
3740
+ if pair = with_new_typing(child_typing).try_tuple_type(node, hint)
3741
+ return pair.with(constr: pair.constr.save_typing)
3742
+ end
3743
+ end
3744
+ end
3745
+
3746
+ synthesize(node, hint: hint)
3747
+ end
3748
+
3873
3749
  def try_tuple_type(node, hint)
3874
- if node.children.size != hint.types.size
3875
- return
3750
+ if hint
3751
+ if node.children.size != hint.types.size
3752
+ return
3753
+ end
3876
3754
  end
3877
3755
 
3878
3756
  constr = self
3879
3757
  element_types = []
3880
3758
 
3881
3759
  each_child_node(node).with_index do |child, index|
3882
- type, constr = constr.synthesize(child, hint: hint.types[index])
3760
+ child_hint = if hint
3761
+ hint.types[index]
3762
+ end
3763
+ type, constr = constr.synthesize(child, hint: child_hint)
3883
3764
  element_types << type
3884
3765
  end
3885
3766
 
@@ -3911,55 +3792,152 @@ module Steep
3911
3792
  constr.add_typing(node, type: AST::Builtin::Array.instance_type(element_type))
3912
3793
  end
3913
3794
 
3914
- def try_hash_type(node, hint)
3915
- hint = expand_alias(hint)
3795
+ # Try to give record type to hash_node.
3796
+ #
3797
+ # Returns nil when it cannot have a record type.
3798
+ # `record_type` can be nil when the keys are not specified.
3799
+ #
3800
+ def type_hash_record(hash_node, record_type)
3801
+ raise unless hash_node.type == :hash
3802
+
3803
+ constr = self
3804
+
3805
+ if record_type
3806
+ elements = record_type.elements.dup
3807
+ else
3808
+ elements = {}
3809
+ end
3810
+
3811
+ elems = {}
3812
+
3813
+ each_child_node(hash_node) do |child|
3814
+ if child.type == :pair
3815
+ case child.children[0].type
3816
+ when :sym, :str, :int
3817
+ key_node = child.children[0]
3818
+ value_node = child.children[1]
3819
+
3820
+ key = key_node.children[0]
3821
+
3822
+ _, constr = constr.synthesize(key_node, hint: AST::Types::Literal.new(value: key))
3823
+ value_type, constr = constr.synthesize(value_node, hint: elements[key])
3824
+
3825
+ elems[key] = value_type
3826
+ else
3827
+ return
3828
+ end
3829
+ else
3830
+ return
3831
+ end
3832
+ end
3833
+
3834
+ type = AST::Types::Record.new(elements: elems)
3835
+ constr.add_typing(hash_node, type: type)
3836
+ end
3837
+
3838
+ # Give hash_node a type based on hint.
3839
+ #
3840
+ # * When hint is Record type, it may have record type.
3841
+ # * When hint is union type, it tries recursively with the union cases.
3842
+ # * Otherwise, it tries to be a hash instance.
3843
+ #
3844
+ def type_hash(hash_node, hint:)
3845
+ hint = deep_expand_alias(hint)
3846
+ range = hash_node.loc.expression.yield_self {|l| l.begin_pos..l.end_pos }
3916
3847
 
3917
3848
  case hint
3918
3849
  when AST::Types::Record
3919
- typing.new_child(node.loc.expression.yield_self {|l| l.begin_pos..l.end_pos }) do |child_typing|
3920
- new_construction = with_new_typing(child_typing)
3921
- elements = {}
3850
+ with_child_typing(range: range) do |constr|
3851
+ pair = constr.type_hash_record(hash_node, hint)
3852
+ if pair
3853
+ return pair.with(constr: pair.constr.save_typing)
3854
+ end
3855
+ end
3856
+ when AST::Types::Union
3857
+ pair = pick_one_of(hint.types, range: range) do |type, constr|
3858
+ constr.type_hash(hash_node, hint: type)
3859
+ end
3922
3860
 
3923
- each_child_node(node) do |child|
3924
- case child.type
3925
- when :pair
3926
- key, value = child.children
3861
+ if pair
3862
+ return pair
3863
+ end
3864
+ end
3927
3865
 
3928
- key_value = case key.type
3929
- when :str, :int, :sym
3930
- key.children[0]
3931
- else
3932
- return nil
3933
- end
3866
+ key_types = []
3867
+ value_types = []
3934
3868
 
3935
- value_hint = hint.elements[key_value]
3936
- value_type = new_construction.synthesize(value, hint: value_hint).type
3869
+ if AST::Builtin::Hash.instance_type?(hint)
3870
+ key_hint, value_hint = hint.args
3871
+ end
3937
3872
 
3938
- if value_hint
3939
- if check_relation(sub_type: value_type, super_type: value_hint).success?
3940
- value_type = value_hint
3941
- end
3873
+ hint_hash = AST::Builtin::Hash.instance_type(
3874
+ key_hint || AST::Builtin.any_type,
3875
+ value_hint || AST::Builtin.any_type
3876
+ )
3877
+
3878
+ constr = self
3879
+
3880
+ if hash_node.children.empty?
3881
+ key_types << key_hint if key_hint
3882
+ value_types << value_hint if value_hint
3883
+ else
3884
+ hash_node.children.each do |elem|
3885
+ case elem.type
3886
+ when :pair
3887
+ key_node, value_node = elem.children
3888
+ key_type, constr = constr.synthesize(key_node, hint: key_hint)
3889
+ value_type, constr = constr.synthesize(value_node, hint: value_hint)
3890
+
3891
+ key_types << key_type
3892
+ value_types << value_type
3893
+ when :kwsplat
3894
+ bypass_splat(elem) do |elem_|
3895
+ pair = constr.synthesize(elem_, hint: hint_hash)
3896
+
3897
+ if AST::Builtin::Hash.instance_type?(pair.type)
3898
+ key_types << pair.type.args[0]
3899
+ value_types << pair.type.args[1]
3942
3900
  end
3943
3901
 
3944
- elements[key_value] = value_type
3945
- else
3946
- return nil
3902
+ pair
3947
3903
  end
3904
+ else
3905
+ raise
3948
3906
  end
3907
+ end
3908
+ end
3949
3909
 
3950
- child_typing.save!
3910
+ key_types.reject! {|ty| ty.is_a?(AST::Types::Any) }
3911
+ value_types.reject! {|ty| ty.is_a?(AST::Types::Any) }
3951
3912
 
3952
- hash = AST::Types::Record.new(elements: elements)
3953
- add_typing(node, type: hash)
3954
- end
3955
- when AST::Types::Union
3956
- hint.types.each do |type|
3957
- if pair = try_hash_type(node, type)
3958
- return pair
3913
+ key_types << AST::Builtin.any_type if key_types.empty?
3914
+ value_types << AST::Builtin.any_type if value_types.empty?
3915
+
3916
+ hash_type = AST::Builtin::Hash.instance_type(
3917
+ AST::Types::Union.build(types: key_types),
3918
+ AST::Types::Union.build(types: value_types)
3919
+ )
3920
+ constr.add_typing(hash_node, type: hash_type)
3921
+ end
3922
+
3923
+ def pick_one_of(types, range:)
3924
+ types.each do |type|
3925
+ with_child_typing(range: range) do |constr|
3926
+ type_, constr = yield type, constr
3927
+
3928
+ constr.check_relation(sub_type: type_, super_type: type).then do
3929
+ constr = constr.save_typing
3930
+ return Pair.new(type: type, constr: constr)
3959
3931
  end
3960
3932
  end
3961
- nil
3962
3933
  end
3934
+
3935
+ nil
3936
+ end
3937
+
3938
+ def save_typing
3939
+ typing.save!
3940
+ with_new_typing(typing.parent)
3963
3941
  end
3964
3942
  end
3965
3943
  end