steep 0.43.0 → 0.45.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +8 -0
  3. data/.github/workflows/ruby.yml +3 -2
  4. data/.gitignore +0 -1
  5. data/CHANGELOG.md +30 -0
  6. data/Gemfile +0 -1
  7. data/Gemfile.lock +77 -0
  8. data/bin/output_test.rb +8 -2
  9. data/lib/steep.rb +4 -1
  10. data/lib/steep/ast/builtin.rb +7 -1
  11. data/lib/steep/ast/types/factory.rb +19 -25
  12. data/lib/steep/diagnostic/ruby.rb +137 -60
  13. data/lib/steep/diagnostic/signature.rb +34 -0
  14. data/lib/steep/equatable.rb +21 -0
  15. data/lib/steep/index/source_index.rb +55 -5
  16. data/lib/steep/interface/block.rb +4 -0
  17. data/lib/steep/interface/function.rb +798 -579
  18. data/lib/steep/server/interaction_worker.rb +239 -20
  19. data/lib/steep/server/master.rb +40 -19
  20. data/lib/steep/server/type_check_worker.rb +68 -0
  21. data/lib/steep/services/file_loader.rb +26 -19
  22. data/lib/steep/services/goto_service.rb +322 -0
  23. data/lib/steep/services/hover_content.rb +131 -79
  24. data/lib/steep/services/type_check_service.rb +25 -0
  25. data/lib/steep/source.rb +7 -10
  26. data/lib/steep/type_construction.rb +496 -518
  27. data/lib/steep/type_inference/block_params.rb +2 -5
  28. data/lib/steep/type_inference/method_params.rb +483 -0
  29. data/lib/steep/type_inference/send_args.rb +610 -128
  30. data/lib/steep/typing.rb +46 -21
  31. data/lib/steep/version.rb +1 -1
  32. data/sig/steep/type_inference/send_args.rbs +42 -0
  33. data/smoke/array/test_expectations.yml +3 -3
  34. data/smoke/block/c.rb +0 -1
  35. data/smoke/class/test_expectations.yml +12 -15
  36. data/smoke/const/test_expectations.yml +0 -10
  37. data/smoke/diagnostics-rbs/mixin-class-error.rbs +6 -0
  38. data/smoke/diagnostics-rbs/test_expectations.yml +12 -0
  39. data/smoke/diagnostics-ruby-unsat/Steepfile +5 -0
  40. data/smoke/diagnostics-ruby-unsat/a.rbs +3 -0
  41. data/smoke/diagnostics-ruby-unsat/test_expectations.yml +27 -0
  42. data/smoke/{diagnostics → diagnostics-ruby-unsat}/unsatisfiable_constraint.rb +0 -1
  43. data/smoke/diagnostics/a.rbs +0 -4
  44. data/smoke/diagnostics/different_method_parameter_kind.rb +9 -0
  45. data/smoke/diagnostics/method_arity_mismatch.rb +2 -2
  46. data/smoke/diagnostics/method_parameter_mismatch.rb +10 -0
  47. data/smoke/diagnostics/test_expectations.yml +108 -57
  48. data/smoke/ensure/test_expectations.yml +3 -3
  49. data/smoke/enumerator/test_expectations.yml +1 -1
  50. data/smoke/literal/test_expectations.yml +2 -2
  51. data/smoke/method/test_expectations.yml +11 -10
  52. data/smoke/regression/issue_372.rb +8 -0
  53. data/smoke/regression/issue_372.rbs +4 -0
  54. data/smoke/regression/test_expectations.yml +0 -12
  55. data/smoke/rescue/test_expectations.yml +3 -3
  56. data/smoke/toplevel/test_expectations.yml +3 -3
  57. data/smoke/tsort/test_expectations.yml +2 -2
  58. data/steep.gemspec +2 -2
  59. metadata +24 -10
@@ -275,6 +275,34 @@ module Steep
275
275
  end
276
276
  end
277
277
 
278
+ class MixinClassError < Base
279
+ attr_reader :member
280
+ attr_reader :type_name
281
+
282
+ def initialize(location:, member:, type_name:)
283
+ super(location: location)
284
+ @member = member
285
+ @type_name = type_name
286
+ end
287
+
288
+ def header_line
289
+ "Cannot #{mixin_name} a class `#{member.name}` in the definition of `#{type_name}`"
290
+ end
291
+
292
+ private
293
+
294
+ def mixin_name
295
+ case member
296
+ when RBS::AST::Members::Prepend
297
+ "prepend"
298
+ when RBS::AST::Members::Include
299
+ "include"
300
+ when RBS::AST::Members::Extend
301
+ "extend"
302
+ end
303
+ end
304
+ end
305
+
278
306
  class UnexpectedError < Base
279
307
  attr_reader :message
280
308
 
@@ -365,6 +393,12 @@ module Steep
365
393
  param: error.param,
366
394
  location: error.location
367
395
  )
396
+ when RBS::MixinClassError
397
+ Diagnostic::Signature::MixinClassError.new(
398
+ location: error.location,
399
+ type_name: error.type_name,
400
+ member: error.member,
401
+ )
368
402
  else
369
403
  raise error
370
404
  end
@@ -0,0 +1,21 @@
1
+ module Steep
2
+ module Equatable
3
+ def ==(other)
4
+ if other.class == self.class
5
+ instance_variables.all? do |name|
6
+ other.instance_variable_get(name) == instance_variable_get(name)
7
+ end
8
+ end
9
+ end
10
+
11
+ def eql?(other)
12
+ self == other
13
+ end
14
+
15
+ def hash
16
+ instance_variables.inject(self.class.hash) do |hash, name|
17
+ hash ^ instance_variable_get(name).hash
18
+ end
19
+ end
20
+ end
21
+ end
@@ -43,8 +43,51 @@ module Steep
43
43
  end
44
44
  end
45
45
 
46
+ class MethodEntry
47
+ attr_reader :name
48
+
49
+ attr_reader :definitions
50
+ attr_reader :references
51
+
52
+ def initialize(name:)
53
+ @name = name
54
+
55
+ @definitions = Set[].compare_by_identity
56
+ @references = Set[].compare_by_identity
57
+ end
58
+
59
+ def add_definition(node)
60
+ case node.type
61
+ when :def, :defs
62
+ @definitions << node
63
+ else
64
+ raise "Unexpected method definition: #{node.type}"
65
+ end
66
+
67
+ self
68
+ end
69
+
70
+ def add_reference(node)
71
+ case node.type
72
+ when :send, :block
73
+ @references << node
74
+ else
75
+ raise "Unexpected method reference: #{node.type}"
76
+ end
77
+
78
+ self
79
+ end
80
+
81
+ def merge!(other)
82
+ definitions.merge(other.definitions)
83
+ references.merge(other.references)
84
+ self
85
+ end
86
+ end
87
+
46
88
  attr_reader :source
47
89
  attr_reader :constant_index
90
+ attr_reader :method_index
48
91
 
49
92
  attr_reader :parent
50
93
  attr_reader :count
@@ -58,6 +101,7 @@ module Steep
58
101
  @count = @parent_count || 0
59
102
 
60
103
  @constant_index = {}
104
+ @method_index = {}
61
105
  end
62
106
 
63
107
  def new_child
@@ -72,25 +116,31 @@ module Steep
72
116
  entry.merge!(child_entry)
73
117
  end
74
118
 
119
+ method_index.merge!(child.method_index) do |_, entry, child_entry|
120
+ entry.merge!(child_entry)
121
+ end
122
+
75
123
  @count = child.count + 1
76
124
  end
77
125
 
78
- def add_definition(constant:, definition:)
126
+ def add_definition(constant: nil, method: nil, definition:)
79
127
  @count += 1
80
- entry(constant: constant).add_definition(definition)
128
+ entry(constant: constant, method: method).add_definition(definition)
81
129
  self
82
130
  end
83
131
 
84
- def add_reference(constant:, ref:)
132
+ def add_reference(constant: nil, method: nil, ref:)
85
133
  @count += 1
86
- entry(constant: constant).add_reference(ref)
134
+ entry(constant: constant, method: method).add_reference(ref)
87
135
  self
88
136
  end
89
137
 
90
- def entry(constant:)
138
+ def entry(constant: nil, method: nil)
91
139
  case
92
140
  when constant
93
141
  constant_index[constant] ||= ConstantEntry.new(name: constant)
142
+ when method
143
+ method_index[method] ||= MethodEntry.new(name: method)
94
144
  else
95
145
  raise
96
146
  end
@@ -13,6 +13,10 @@ module Steep
13
13
  @optional
14
14
  end
15
15
 
16
+ def required?
17
+ !optional?
18
+ end
19
+
16
20
  def to_optional
17
21
  self.class.new(
18
22
  type: type,
@@ -2,698 +2,917 @@ module Steep
2
2
  module Interface
3
3
  class Function
4
4
  class Params
5
- attr_reader :required
6
- attr_reader :optional
7
- attr_reader :rest
8
- attr_reader :required_keywords
9
- attr_reader :optional_keywords
10
- attr_reader :rest_keywords
11
-
12
- def initialize(required:, optional:, rest:, required_keywords:, optional_keywords:, rest_keywords:)
13
- @required = required
14
- @optional = optional
15
- @rest = rest
16
- @required_keywords = required_keywords
17
- @optional_keywords = optional_keywords
18
- @rest_keywords = rest_keywords
19
- end
20
-
21
- def update(required: self.required, optional: self.optional, rest: self.rest, required_keywords: self.required_keywords, optional_keywords: self.optional_keywords, rest_keywords: self.rest_keywords)
22
- self.class.new(
23
- required: required,
24
- optional: optional,
25
- rest: rest,
26
- required_keywords: required_keywords,
27
- optional_keywords: optional_keywords,
28
- rest_keywords: rest_keywords,
29
- )
30
- end
31
-
32
- RequiredPositional = Struct.new(:type)
33
- OptionalPositional = Struct.new(:type)
34
- RestPositional = Struct.new(:type)
35
-
36
- def first_param
37
- case
38
- when !required.empty?
39
- RequiredPositional.new(required[0])
40
- when !optional.empty?
41
- OptionalPositional.new(optional[0])
42
- when rest
43
- RestPositional.new(rest)
44
- else
45
- nil
5
+ module Utils
6
+ def union(*types, null: false)
7
+ types << AST::Builtin.nil_type if null
8
+ AST::Types::Union.build(types: types)
46
9
  end
47
- end
48
10
 
49
- def with_first_param(param)
50
- case param
51
- when RequiredPositional
52
- update(required: [param.type] + required)
53
- when OptionalPositional
54
- update(optional: [param.type] + required)
55
- when RestPositional
56
- update(rest: param.type)
57
- else
58
- self
11
+ def intersection(*types)
12
+ AST::Types::Intersection.build(types: types)
59
13
  end
60
14
  end
61
15
 
62
- def has_positional?
63
- first_param
64
- end
16
+ class PositionalParams
17
+ class Base
18
+ attr_reader :type
65
19
 
66
- def self.empty
67
- self.new(
68
- required: [],
69
- optional: [],
70
- rest: nil,
71
- required_keywords: {},
72
- optional_keywords: {},
73
- rest_keywords: nil
74
- )
75
- end
20
+ def initialize(type)
21
+ @type = type
22
+ end
76
23
 
77
- def ==(other)
78
- other.is_a?(self.class) &&
79
- other.required == required &&
80
- other.optional == optional &&
81
- other.rest == rest &&
82
- other.required_keywords == required_keywords &&
83
- other.optional_keywords == optional_keywords &&
84
- other.rest_keywords == rest_keywords
85
- end
24
+ def ==(other)
25
+ other.is_a?(self.class) && other.type == type
26
+ end
86
27
 
87
- alias eql? ==
28
+ alias eql? ==
88
29
 
89
- def hash
90
- required.hash ^ optional.hash ^ rest.hash ^ required_keywords.hash ^ optional_keywords.hash ^ rest_keywords.hash
91
- end
30
+ def hash
31
+ self.class.hash ^ type.hash
32
+ end
92
33
 
93
- def flat_unnamed_params
94
- required.map {|p| [:required, p] } + optional.map {|p| [:optional, p] }
95
- end
34
+ def subst(s)
35
+ ty = type.subst(s)
96
36
 
97
- def flat_keywords
98
- required_keywords.merge optional_keywords
99
- end
37
+ if ty == type
38
+ self
39
+ else
40
+ self.class.new(ty)
41
+ end
42
+ end
100
43
 
101
- def has_keywords?
102
- !required_keywords.empty? || !optional_keywords.empty? || rest_keywords
103
- end
44
+ def var_type
45
+ type
46
+ end
104
47
 
105
- def without_keywords
106
- self.class.new(
107
- required: required,
108
- optional: optional,
109
- rest: rest,
110
- required_keywords: {},
111
- optional_keywords: {},
112
- rest_keywords: nil
113
- )
114
- end
48
+ def map_type(&block)
49
+ if block_given?
50
+ self.class.new(yield type)
51
+ else
52
+ enum_for(:map_type)
53
+ end
54
+ end
55
+ end
115
56
 
116
- def drop_first
117
- case
118
- when required.any? || optional.any? || rest
119
- self.class.new(
120
- required: required.any? ? required.drop(1) : [],
121
- optional: required.empty? && optional.any? ? optional.drop(1) : optional,
122
- rest: required.empty? && optional.empty? ? nil : rest,
123
- required_keywords: required_keywords,
124
- optional_keywords: optional_keywords,
125
- rest_keywords: rest_keywords
126
- )
127
- when has_keywords?
128
- without_keywords
129
- else
130
- raise "Cannot drop from empty params"
57
+ class Required < Base; end
58
+ class Optional < Base; end
59
+ class Rest < Base; end
60
+
61
+ attr_reader :head
62
+ attr_reader :tail
63
+
64
+ def initialize(head:, tail:)
65
+ @head = head
66
+ @tail = tail
131
67
  end
132
- end
133
68
 
134
- def each_missing_argument(args)
135
- required.size.times do |index|
136
- if index >= args.size
137
- yield index
138
- end
69
+ def self.required(type, tail = nil)
70
+ PositionalParams.new(head: Required.new(type), tail: tail)
71
+ end
72
+
73
+ def self.optional(type, tail = nil)
74
+ PositionalParams.new(head: Optional.new(type), tail: tail)
139
75
  end
140
- end
141
76
 
142
- def each_extra_argument(args)
143
- return if rest
77
+ def self.rest(type, tail = nil)
78
+ PositionalParams.new(head: Rest.new(type), tail: tail)
79
+ end
144
80
 
145
- if has_keywords?
146
- args = args.take(args.count - 1) if args.count > 0
81
+ def to_ary
82
+ [head, tail]
147
83
  end
148
84
 
149
- args.size.times do |index|
150
- if index >= required.count + optional.count
151
- yield index
85
+ def map(&block)
86
+ hd = yield(head)
87
+ tl = tail&.map(&block)
88
+
89
+ if head == hd && tail == tl
90
+ self
91
+ else
92
+ PositionalParams.new(head: hd, tail: tl)
93
+ end
94
+ end
95
+
96
+ def map_type(&block)
97
+ if block_given?
98
+ map {|param| param.map_type(&block) }
99
+ else
100
+ enum_for :map_type
152
101
  end
153
102
  end
154
- end
155
103
 
156
- def each_missing_keyword(args)
157
- return unless has_keywords?
104
+ def subst(s)
105
+ map_type do |type|
106
+ ty = type.subst(s)
107
+ if ty == type
108
+ type
109
+ else
110
+ ty
111
+ end
112
+ end
113
+ end
158
114
 
159
- keywords, rest = extract_keywords(args)
115
+ def ==(other)
116
+ other.is_a?(PositionalParams) && other.head == head && other.tail == tail
117
+ end
160
118
 
161
- return unless rest.empty?
119
+ alias eql? ==
162
120
 
163
- required_keywords.each do |keyword, _|
164
- yield keyword unless keywords.key?(keyword)
121
+ def hash
122
+ self.class.hash ^ head.hash ^ tail.hash
165
123
  end
166
- end
167
124
 
168
- def each_extra_keyword(args)
169
- return unless has_keywords?
170
- return if rest_keywords
125
+ def each(&block)
126
+ if block_given?
127
+ yield head
128
+ tail&.each(&block)
129
+ else
130
+ enum_for(:each)
131
+ end
132
+ end
133
+
134
+ def each_type
135
+ if block_given?
136
+ each do |param|
137
+ yield param.type
138
+ end
139
+ else
140
+ enum_for :each_type
141
+ end
142
+ end
171
143
 
172
- keywords, rest = extract_keywords(args)
144
+ def size
145
+ 1 + (tail&.size || 0)
146
+ end
173
147
 
174
- return unless rest.empty?
148
+ def self.build(required:, optional:, rest:)
149
+ params = rest ? self.rest(rest) : nil
150
+ params = optional.reverse_each.inject(params) {|params, type| self.optional(type, params) }
151
+ params = required.reverse_each.inject(params) {|params, type| self.required(type, params) }
175
152
 
176
- all_keywords = flat_keywords
177
- keywords.each do |keyword, _|
178
- yield keyword unless all_keywords.key?(keyword)
153
+ params
179
154
  end
180
- end
181
155
 
182
- def extract_keywords(args)
183
- last_arg = args.last
156
+ extend Utils
184
157
 
185
- keywords = {}
186
- rest = []
158
+ # Calculates xs + ys.
159
+ # Never fails.
160
+ def self.merge_for_overload(xs, ys)
161
+ x = xs&.head
162
+ y = ys&.head
187
163
 
188
- if last_arg&.type == :hash
189
- last_arg.children.each do |element|
190
- case element.type
191
- when :pair
192
- if element.children[0].type == :sym
193
- name = element.children[0].children[0]
194
- keywords[name] = element.children[1]
195
- end
196
- when :kwsplat
197
- rest << element.children[0]
198
- end
164
+ case
165
+ when x.is_a?(Required) && y.is_a?(Required)
166
+ required(
167
+ union(x.type, y.type),
168
+ merge_for_overload(xs.tail, ys.tail)
169
+ )
170
+ when x.is_a?(Required) && y.is_a?(Optional)
171
+ optional(
172
+ union(x.type, y.type, null: true),
173
+ merge_for_overload(xs.tail, ys.tail)
174
+ )
175
+ when x.is_a?(Required) && y.is_a?(Rest)
176
+ optional(
177
+ union(x.type, y.type, null: true),
178
+ merge_for_overload(xs.tail, ys)
179
+ )
180
+ when x.is_a?(Required) && !y
181
+ optional(
182
+ union(x.type, null: true),
183
+ merge_for_overload(xs.tail, nil)
184
+ )
185
+ when x.is_a?(Optional) && y.is_a?(Required)
186
+ optional(
187
+ union(x.type, y.type, null: true),
188
+ merge_for_overload(xs.tail, ys.tail)
189
+ )
190
+ when x.is_a?(Optional) && y.is_a?(Optional)
191
+ optional(
192
+ union(x.type, y.type),
193
+ merge_for_overload(xs.tail, ys.tail)
194
+ )
195
+ when x.is_a?(Optional) && y.is_a?(Rest)
196
+ optional(
197
+ union(x.type, y.type),
198
+ merge_for_overload(xs.tail, ys)
199
+ )
200
+ when x.is_a?(Optional) && !y
201
+ optional(
202
+ x.type,
203
+ merge_for_overload(xs.tail, nil)
204
+ ) # == xs
205
+ when x.is_a?(Rest) && y.is_a?(Required)
206
+ optional(
207
+ union(x.type, y.type, null: true),
208
+ merge_for_overload(xs, ys.tail)
209
+ )
210
+ when x.is_a?(Rest) && y.is_a?(Optional)
211
+ optional(
212
+ union(x.type, y.type),
213
+ merge_for_overload(xs, ys.tail)
214
+ )
215
+ when x.is_a?(Rest) && y.is_a?(Rest)
216
+ rest(union(x.type, y.type))
217
+ when x.is_a?(Rest) && !y
218
+ xs
219
+ when !x && y.is_a?(Required)
220
+ optional(
221
+ union(y.type, null: true),
222
+ merge_for_overload(nil, ys.tail)
223
+ )
224
+ when !x && y.is_a?(Optional)
225
+ optional(
226
+ y.type,
227
+ merge_for_overload(nil, ys.tail)
228
+ ) # == ys
229
+ when !x && y.is_a?(Rest)
230
+ ys
231
+ when !x && !y
232
+ nil
199
233
  end
200
234
  end
201
235
 
202
- [keywords, rest]
203
- end
236
+ # xs | ys
237
+ def self.merge_for_union(xs, ys)
238
+ x = xs&.head
239
+ y = ys&.head
204
240
 
205
- def each_type()
206
- if block_given?
207
- flat_unnamed_params.each do |(_, type)|
208
- yield type
209
- end
210
- flat_keywords.each do |_, type|
211
- yield type
241
+ case
242
+ when x.is_a?(Required) && y.is_a?(Required)
243
+ required(
244
+ union(x.type, y.type),
245
+ merge_for_union(xs.tail, ys.tail)
246
+ )
247
+ when x.is_a?(Required) && !y
248
+ optional(
249
+ x.type,
250
+ merge_for_union(xs.tail, nil)
251
+ )
252
+ when x.is_a?(Required) && y.is_a?(Optional)
253
+ optional(
254
+ union(x.type, y.type),
255
+ merge_for_union(xs.tail, ys.tail)
256
+ )
257
+ when x.is_a?(Required) && y.is_a?(Rest)
258
+ optional(
259
+ union(x.type, y.type),
260
+ merge_for_union(xs.tail, ys)
261
+ )
262
+ when !x && y.is_a?(Required)
263
+ optional(
264
+ y.type,
265
+ merge_for_union(nil, ys.tail)
266
+ )
267
+ when !x && !y
268
+ nil
269
+ when !x && y.is_a?(Optional)
270
+ PositionalParams.new(head: y, tail: merge_for_union(nil, ys.tail))
271
+ when !x && y.is_a?(Rest)
272
+ ys
273
+ when x.is_a?(Optional) && y.is_a?(Required)
274
+ optional(
275
+ union(x.type, y.type),
276
+ merge_for_union(xs.tail, ys.tail)
277
+ )
278
+ when x.is_a?(Optional) && !y
279
+ PositionalParams.new(head: x, tail: merge_for_union(xs.tail, nil)) # == xs
280
+ when x.is_a?(Optional) && y.is_a?(Optional)
281
+ optional(
282
+ union(x.type, y.type),
283
+ merge_for_union(xs.tail, ys.tail)
284
+ )
285
+ when x.is_a?(Optional) && y.is_a?(Rest)
286
+ optional(
287
+ union(x.type, y.type),
288
+ merge_for_union(xs.tail, ys.tail)
289
+ )
290
+ when x.is_a?(Rest) && y.is_a?(Required)
291
+ optional(
292
+ union(x.type, y.type),
293
+ merge_for_union(xs, ys.tail)
294
+ )
295
+ when x.is_a?(Rest) && !y
296
+ xs
297
+ when x.is_a?(Rest) && y.is_a?(Optional)
298
+ optional(
299
+ union(x.type, y.type),
300
+ merge_for_union(xs, ys.tail)
301
+ )
302
+ when x.is_a?(Rest) && y.is_a?(Rest)
303
+ rest(
304
+ union(x.type, y.type)
305
+ )
212
306
  end
213
- rest and yield rest
214
- rest_keywords and yield rest_keywords
215
- else
216
- enum_for :each_type
217
307
  end
218
- end
219
308
 
220
- def free_variables()
221
- @fvs ||= Set.new.tap do |set|
222
- each_type do |type|
223
- set.merge(type.free_variables)
309
+ # Calculates xs & ys.
310
+ # Raises when failed.
311
+ #
312
+ def self.merge_for_intersection(xs, ys)
313
+ x = xs&.head
314
+ y = ys&.head
315
+
316
+ case
317
+ when x.is_a?(Required) && y.is_a?(Required)
318
+ required(
319
+ intersection(x.type, y.type),
320
+ merge_for_intersection(xs.tail, ys.tail)
321
+ )
322
+ when x.is_a?(Required) && !y
323
+ raise
324
+ when x.is_a?(Required) && y.is_a?(Optional)
325
+ required(
326
+ intersection(x.type, y.type),
327
+ merge_for_intersection(xs.tail, ys.tail)
328
+ )
329
+ when x.is_a?(Required) && y.is_a?(Rest)
330
+ required(
331
+ intersection(x.type, y.type),
332
+ merge_for_intersection(xs.tail, ys)
333
+ )
334
+ when !x && y.is_a?(Required)
335
+ raise
336
+ when !x && !y
337
+ nil
338
+ when !x && y.is_a?(Optional)
339
+ nil
340
+ when !x && y.is_a?(Rest)
341
+ nil
342
+ when x.is_a?(Optional) && y.is_a?(Required)
343
+ required(
344
+ intersection(x.type, y.type),
345
+ merge_for_intersection(xs.tail, ys.tail)
346
+ )
347
+ when x.is_a?(Optional) && !y
348
+ nil
349
+ when x.is_a?(Optional) && y.is_a?(Optional)
350
+ optional(
351
+ intersection(x.type, y.type),
352
+ merge_for_intersection(xs.tail, ys.tail)
353
+ )
354
+ when x.is_a?(Optional) && y.is_a?(Rest)
355
+ optional(
356
+ intersection(x.type, y.type),
357
+ merge_for_intersection(xs.tail, ys)
358
+ )
359
+ when x.is_a?(Rest) && y.is_a?(Required)
360
+ required(
361
+ intersection(x.type, y.type),
362
+ merge_for_intersection(xs, ys.tail)
363
+ )
364
+ when x.is_a?(Rest) && !y
365
+ nil
366
+ when x.is_a?(Rest) && y.is_a?(Optional)
367
+ optional(
368
+ intersection(x.type, y.type),
369
+ merge_for_intersection(xs, ys.tail)
370
+ )
371
+ when x.is_a?(Rest) && y.is_a?(Rest)
372
+ rest(intersection(x.type, y.type))
224
373
  end
225
374
  end
226
375
  end
227
376
 
228
- def closed?
229
- required.all?(&:closed?) && optional.all?(&:closed?) && (!rest || rest.closed?) && required_keywords.values.all?(&:closed?) && optional_keywords.values.all?(&:closed?) && (!rest_keywords || rest_keywords.closed?)
230
- end
231
-
232
- def subst(s)
233
- return self if s.empty?
234
- return self if empty?
235
- return self if free_variables.disjoint?(s.domain)
236
-
237
- rs = required.map {|t| t.subst(s) }
238
- os = optional.map {|t| t.subst(s) }
239
- r = rest&.subst(s)
240
- rk = required_keywords.transform_values {|t| t.subst(s) }
241
- ok = optional_keywords.transform_values {|t| t.subst(s) }
242
- k = rest_keywords&.subst(s)
377
+ class KeywordParams
378
+ attr_reader :requireds
379
+ attr_reader :optionals
380
+ attr_reader :rest
243
381
 
244
- if rs == required && os == optional && r == rest && rk == required_keywords && ok == optional_keywords && k == rest_keywords
245
- self
246
- else
247
- self.class.new(
248
- required: required.map {|t| t.subst(s) },
249
- optional: optional.map {|t| t.subst(s) },
250
- rest: rest&.subst(s),
251
- required_keywords: required_keywords.transform_values {|t| t.subst(s) },
252
- optional_keywords: optional_keywords.transform_values {|t| t.subst(s) },
253
- rest_keywords: rest_keywords&.subst(s)
254
- )
382
+ def initialize(requireds: {}, optionals: {}, rest: nil)
383
+ @requireds = requireds
384
+ @optionals = optionals
385
+ @rest = rest
255
386
  end
256
- end
257
387
 
258
- def size
259
- required.size + optional.size + (rest ? 1 : 0) + required_keywords.size + optional_keywords.size + (rest_keywords ? 1 : 0)
260
- end
388
+ def ==(other)
389
+ other.is_a?(KeywordParams) &&
390
+ other.requireds == requireds &&
391
+ other.optionals == optionals &&
392
+ other.rest == rest
393
+ end
261
394
 
262
- def to_s
263
- required = self.required.map {|ty| ty.to_s }
264
- optional = self.optional.map {|ty| "?#{ty}" }
265
- rest = self.rest ? ["*#{self.rest}"] : []
266
- required_keywords = self.required_keywords.map {|name, type| "#{name}: #{type}" }
267
- optional_keywords = self.optional_keywords.map {|name, type| "?#{name}: #{type}"}
268
- rest_keywords = self.rest_keywords ? ["**#{self.rest_keywords}"] : []
269
- "(#{(required + optional + rest + required_keywords + optional_keywords + rest_keywords).join(", ")})"
270
- end
395
+ alias eql? ==
271
396
 
272
- def map_type(&block)
273
- self.class.new(
274
- required: required.map(&block),
275
- optional: optional.map(&block),
276
- rest: rest && yield(rest),
277
- required_keywords: required_keywords.transform_values(&block),
278
- optional_keywords: optional_keywords.transform_values(&block),
279
- rest_keywords: rest_keywords && yield(rest_keywords)
280
- )
281
- end
397
+ def hash
398
+ self.class.hash ^ requireds.hash ^ optionals.hash ^ rest.hash
399
+ end
282
400
 
283
- def empty?
284
- !has_positional? && !has_keywords?
285
- end
401
+ def update(requireds: self.requireds, optionals: self.optionals, rest: self.rest)
402
+ KeywordParams.new(
403
+ requireds: requireds,
404
+ optionals: optionals,
405
+ rest: rest
406
+ )
407
+ end
286
408
 
287
- # self + params returns a new params for overloading.
288
- #
289
- def +(other)
290
- a = first_param
291
- b = other.first_param
409
+ def empty?
410
+ requireds.empty? && optionals.empty? && rest.nil?
411
+ end
292
412
 
293
- case
294
- when a.is_a?(RequiredPositional) && b.is_a?(RequiredPositional)
295
- AST::Types::Union.build(types: [a.type, b.type]).yield_self do |type|
296
- (self.drop_first + other.drop_first).with_first_param(RequiredPositional.new(type))
297
- end
298
- when a.is_a?(RequiredPositional) && b.is_a?(OptionalPositional)
299
- AST::Types::Union.build(types: [a.type, b.type]).yield_self do |type|
300
- (self.drop_first + other.drop_first).with_first_param(OptionalPositional.new(type))
301
- end
302
- when a.is_a?(RequiredPositional) && b.is_a?(RestPositional)
303
- AST::Types::Union.build(types: [a.type, b.type]).yield_self do |type|
304
- (self.drop_first + other).with_first_param(OptionalPositional.new(type))
305
- end
306
- when a.is_a?(RequiredPositional) && b.nil?
307
- (self.drop_first + other).with_first_param(OptionalPositional.new(a.type))
308
- when a.is_a?(OptionalPositional) && b.is_a?(RequiredPositional)
309
- AST::Types::Union.build(types: [a.type, b.type]).yield_self do |type|
310
- (self.drop_first + other.drop_first).with_first_param(OptionalPositional.new(type))
311
- end
312
- when a.is_a?(OptionalPositional) && b.is_a?(OptionalPositional)
313
- AST::Types::Union.build(types: [a.type, b.type]).yield_self do |type|
314
- (self.drop_first + other.drop_first).with_first_param(OptionalPositional.new(type))
315
- end
316
- when a.is_a?(OptionalPositional) && b.is_a?(RestPositional)
317
- AST::Types::Union.build(types: [a.type, b.type]).yield_self do |type|
318
- (self.drop_first + other).with_first_param(OptionalPositional.new(type))
319
- end
320
- when a.is_a?(OptionalPositional) && b.nil?
321
- (self.drop_first + other).with_first_param(OptionalPositional.new(a.type))
322
- when a.is_a?(RestPositional) && b.is_a?(RequiredPositional)
323
- AST::Types::Union.build(types: [a.type, b.type]).yield_self do |type|
324
- (self + other.drop_first).with_first_param(OptionalPositional.new(type))
413
+ def each(&block)
414
+ if block_given?
415
+ requireds.each(&block)
416
+ optionals.each(&block)
417
+ if rest
418
+ yield nil, rest
419
+ end
420
+ else
421
+ enum_for :each
325
422
  end
326
- when a.is_a?(RestPositional) && b.is_a?(OptionalPositional)
327
- AST::Types::Union.build(types: [a.type, b.type]).yield_self do |type|
328
- (self + other.drop_first).with_first_param(OptionalPositional.new(type))
423
+ end
424
+
425
+ def each_type
426
+ if block_given?
427
+ each do |_, type|
428
+ yield type
429
+ end
430
+ else
431
+ enum_for :each_type
329
432
  end
330
- when a.is_a?(RestPositional) && b.is_a?(RestPositional)
331
- AST::Types::Union.build(types: [a.type, b.type]).yield_self do |type|
332
- (self.drop_first + other.drop_first).with_first_param(RestPositional.new(type))
433
+ end
434
+
435
+ def map_type(&block)
436
+ if block_given?
437
+ rs = requireds.transform_values(&block)
438
+ os = optionals.transform_values(&block)
439
+ r = rest&.yield_self(&block)
440
+
441
+ if requireds == rs && optionals == os && rest == r
442
+ self
443
+ else
444
+ update(requireds: rs, optionals: os, rest: r)
445
+ end
446
+ else
447
+ enum_for(:map_type)
333
448
  end
334
- when a.is_a?(RestPositional) && b.nil?
335
- (self.drop_first + other).with_first_param(RestPositional.new(a.type))
336
- when a.nil? && b.is_a?(RequiredPositional)
337
- (self + other.drop_first).with_first_param(OptionalPositional.new(b.type))
338
- when a.nil? && b.is_a?(OptionalPositional)
339
- (self + other.drop_first).with_first_param(OptionalPositional.new(b.type))
340
- when a.nil? && b.is_a?(RestPositional)
341
- (self + other.drop_first).with_first_param(RestPositional.new(b.type))
342
- when a.nil? && b.nil?
343
- required_keywords = {}
344
-
345
- (Set.new(self.required_keywords.keys) & Set.new(other.required_keywords.keys)).each do |keyword|
346
- required_keywords[keyword] = AST::Types::Union.build(
347
- types: [
348
- self.required_keywords[keyword],
349
- other.required_keywords[keyword]
350
- ]
351
- )
449
+ end
450
+
451
+ def subst(s)
452
+ map_type do |type|
453
+ ty = type.subst(s)
454
+ if ty == type
455
+ type
456
+ else
457
+ ty
458
+ end
352
459
  end
460
+ end
461
+
462
+ def size
463
+ requireds.size + optionals.size + (rest ? 1 : 0)
464
+ end
465
+
466
+ def keywords
467
+ Set[] + requireds.keys + optionals.keys
468
+ end
353
469
 
354
- optional_keywords = {}
355
- self.required_keywords.each do |keyword, t|
356
- unless required_keywords.key?(keyword)
470
+ include Utils
471
+
472
+ # For overloading
473
+ def +(other)
474
+ requireds = {}
475
+ optionals = {}
476
+
477
+ all_keys = Set[] + self.requireds.keys + self.optionals.keys + other.requireds.keys + other.optionals.keys
478
+ all_keys.each do |key|
479
+ case
480
+ when t = self.requireds[key]
357
481
  case
358
- when other.optional_keywords.key?(keyword)
359
- optional_keywords[keyword] = AST::Types::Union.build(types: [t, other.optional_keywords[keyword]])
360
- when other.rest_keywords
361
- optional_keywords[keyword] = AST::Types::Union.build(types: [t, other.rest_keywords])
482
+ when s = other.requireds[key]
483
+ requireds[key] = union(t, s)
484
+ when s = other.optionals[key]
485
+ optionals[key] = union(t, s, null: true)
486
+ when s = other.rest
487
+ optionals[key] = union(t, s, null: true)
362
488
  else
363
- optional_keywords[keyword] = t
489
+ optionals[key] = union(t, null: true)
364
490
  end
365
- end
366
- end
367
- other.required_keywords.each do |keyword, t|
368
- unless required_keywords.key?(keyword)
491
+ when t = self.optionals[key]
369
492
  case
370
- when self.optional_keywords.key?(keyword)
371
- optional_keywords[keyword] = AST::Types::Union.build(types: [t, self.optional_keywords[keyword]])
372
- when self.rest_keywords
373
- optional_keywords[keyword] = AST::Types::Union.build(types: [t, self.rest_keywords])
493
+ when s = other.requireds[key]
494
+ optionals[key] = union(t, s, null: true)
495
+ when s = other.optionals[key]
496
+ optionals[key] = union(t, s)
497
+ when s = other.rest
498
+ optionals[key] = union(t, s)
374
499
  else
375
- optional_keywords[keyword] = t
500
+ optionals[key] = t
376
501
  end
377
- end
378
- end
379
- self.optional_keywords.each do |keyword, t|
380
- unless optional_keywords.key?(keyword)
502
+ when t = self.rest
381
503
  case
382
- when other.optional_keywords.key?(keyword)
383
- optional_keywords[keyword] = AST::Types::Union.build(types: [t, other.optional_keywords[keyword]])
384
- when other.rest_keywords
385
- optional_keywords[keyword] = AST::Types::Union.build(types: [t, other.rest_keywords])
504
+ when s = other.requireds[key]
505
+ optionals[key] = union(t, s, null: true)
506
+ when s = other.optionals[key]
507
+ optionals[key] = union(t, s)
508
+ when s = other.rest
509
+ # cannot happen
386
510
  else
387
- optional_keywords[keyword] = t
511
+ # nop
388
512
  end
389
- end
390
- end
391
- other.optional_keywords.each do |keyword, t|
392
- unless optional_keywords.key?(keyword)
513
+ else
393
514
  case
394
- when self.optional_keywords.key?(keyword)
395
- optional_keywords[keyword] = AST::Types::Union.build(types: [t, self.optional_keywords[keyword]])
396
- when self.rest_keywords
397
- optional_keywords[keyword] = AST::Types::Union.build(types: [t, self.rest_keywords])
515
+ when s = other.requireds[key]
516
+ optionals[key] = union(s, null: true)
517
+ when s = other.optionals[key]
518
+ optionals[key] = s
519
+ when s = other.rest
520
+ # nop
398
521
  else
399
- optional_keywords[keyword] = t
522
+ # cannot happen
400
523
  end
401
524
  end
402
525
  end
403
526
 
404
- rest = case
405
- when self.rest_keywords && other.rest_keywords
406
- AST::Types::Union.build(types: [self.rest_keywords, other.rest_keywords])
407
- else
408
- self.rest_keywords || other.rest_keywords
409
- end
527
+ if self.rest && other.rest
528
+ rest = union(self.rest, other.rest)
529
+ else
530
+ rest = self.rest || other.rest
531
+ end
410
532
 
411
- Params.new(
412
- required: [],
413
- optional: [],
414
- rest: nil,
415
- required_keywords: required_keywords,
416
- optional_keywords: optional_keywords,
417
- rest_keywords: rest)
533
+ KeywordParams.new(requireds: requireds, optionals: optionals, rest: rest)
418
534
  end
419
- end
420
-
421
- # Returns the intersection between self and other.
422
- # Returns nil if the intersection cannot be computed.
423
- #
424
- def &(other)
425
- a = first_param
426
- b = other.first_param
427
535
 
428
- case
429
- when a.is_a?(RequiredPositional) && b.is_a?(RequiredPositional)
430
- AST::Types::Intersection.build(types: [a.type, b.type]).yield_self do |type|
431
- (self.drop_first & other.drop_first)&.with_first_param(RequiredPositional.new(type))
432
- end
433
- when a.is_a?(RequiredPositional) && b.is_a?(OptionalPositional)
434
- AST::Types::Intersection.build(types: [a.type, b.type]).yield_self do |type|
435
- (self.drop_first & other.drop_first)&.with_first_param(RequiredPositional.new(type))
436
- end
437
- when a.is_a?(RequiredPositional) && b.is_a?(RestPositional)
438
- AST::Types::Intersection.build(types: [a.type, b.type]).yield_self do |type|
439
- (self.drop_first & other)&.with_first_param(RequiredPositional.new(type))
440
- end
441
- when a.is_a?(RequiredPositional) && b.nil?
442
- nil
443
- when a.is_a?(OptionalPositional) && b.is_a?(RequiredPositional)
444
- AST::Types::Intersection.build(types: [a.type, b.type]).yield_self do |type|
445
- (self.drop_first & other.drop_first)&.with_first_param(RequiredPositional.new(type))
446
- end
447
- when a.is_a?(OptionalPositional) && b.is_a?(OptionalPositional)
448
- AST::Types::Intersection.build(types: [a.type, b.type]).yield_self do |type|
449
- (self.drop_first & other.drop_first)&.with_first_param(OptionalPositional.new(type))
450
- end
451
- when a.is_a?(OptionalPositional) && b.is_a?(RestPositional)
452
- AST::Types::Intersection.build(types: [a.type, b.type]).yield_self do |type|
453
- (self.drop_first & other)&.with_first_param(OptionalPositional.new(type))
454
- end
455
- when a.is_a?(OptionalPositional) && b.nil?
456
- self.drop_first & other
457
- when a.is_a?(RestPositional) && b.is_a?(RequiredPositional)
458
- AST::Types::Intersection.build(types: [a.type, b.type]).yield_self do |type|
459
- (self & other.drop_first)&.with_first_param(RequiredPositional.new(type))
460
- end
461
- when a.is_a?(RestPositional) && b.is_a?(OptionalPositional)
462
- AST::Types::Intersection.build(types: [a.type, b.type]).yield_self do |type|
463
- (self & other.drop_first)&.with_first_param(OptionalPositional.new(type))
464
- end
465
- when a.is_a?(RestPositional) && b.is_a?(RestPositional)
466
- AST::Types::Intersection.build(types: [a.type, b.type]).yield_self do |type|
467
- (self.drop_first & other.drop_first)&.with_first_param(RestPositional.new(type))
468
- end
469
- when a.is_a?(RestPositional) && b.nil?
470
- self.drop_first & other
471
- when a.nil? && b.is_a?(RequiredPositional)
472
- nil
473
- when a.nil? && b.is_a?(OptionalPositional)
474
- self & other.drop_first
475
- when a.nil? && b.is_a?(RestPositional)
476
- self & other.drop_first
477
- when a.nil? && b.nil?
478
- optional_keywords = {}
479
-
480
- (Set.new(self.optional_keywords.keys) & Set.new(other.optional_keywords.keys)).each do |keyword|
481
- optional_keywords[keyword] = AST::Types::Intersection.build(
482
- types: [
483
- self.optional_keywords[keyword],
484
- other.optional_keywords[keyword]
485
- ]
486
- )
487
- end
536
+ # For union
537
+ def |(other)
538
+ requireds = {}
539
+ optionals = {}
488
540
 
489
- required_keywords = {}
490
- self.optional_keywords.each do |keyword, t|
491
- unless optional_keywords.key?(keyword)
541
+ all_keys = Set[] + self.requireds.keys + self.optionals.keys + other.requireds.keys + other.optionals.keys
542
+ all_keys.each do |key|
543
+ case
544
+ when t = self.requireds[key]
492
545
  case
493
- when other.required_keywords.key?(keyword)
494
- required_keywords[keyword] = AST::Types::Intersection.build(types: [t, other.required_keywords[keyword]])
495
- when other.rest_keywords
496
- optional_keywords[keyword] = AST::Types::Intersection.build(types: [t, other.rest_keywords])
546
+ when s = other.requireds[key]
547
+ requireds[key] = union(t, s)
548
+ when s = other.optionals[key]
549
+ optionals[key] = union(t, s)
550
+ when s = other.rest
551
+ optionals[key] = union(t, s)
552
+ else
553
+ optionals[key] = t
497
554
  end
498
- end
499
- end
500
- other.optional_keywords.each do |keyword, t|
501
- unless optional_keywords.key?(keyword)
555
+ when t = self.optionals[key]
502
556
  case
503
- when self.required_keywords.key?(keyword)
504
- required_keywords[keyword] = AST::Types::Intersection.build(types: [t, self.required_keywords[keyword]])
505
- when self.rest_keywords
506
- optional_keywords[keyword] = AST::Types::Intersection.build(types: [t, self.rest_keywords])
557
+ when s = other.requireds[key]
558
+ optionals[key] = union(t, s)
559
+ when s = other.optionals[key]
560
+ optionals[key] = union(t, s)
561
+ when s = other.rest
562
+ optionals[key] = union(t, s)
563
+ else
564
+ optionals[key] = t
507
565
  end
508
- end
509
- end
510
- self.required_keywords.each do |keyword, t|
511
- unless required_keywords.key?(keyword)
566
+ when t = self.rest
512
567
  case
513
- when other.required_keywords.key?(keyword)
514
- required_keywords[keyword] = AST::Types::Intersection.build(types: [t, other.required_keywords[keyword]])
515
- when other.rest_keywords
516
- required_keywords[keyword] = AST::Types::Intersection.build(types: [t, other.rest_keywords])
568
+ when s = other.requireds[key]
569
+ optionals[key] = union(t, s)
570
+ when s = other.optionals[key]
571
+ optionals[key] = union(t, s)
572
+ when s = other.rest
573
+ # cannot happen
517
574
  else
518
- return
575
+ # nop
519
576
  end
520
- end
521
- end
522
- other.required_keywords.each do |keyword, t|
523
- unless required_keywords.key?(keyword)
577
+ else
524
578
  case
525
- when self.required_keywords.key?(keyword)
526
- required_keywords[keyword] = AST::Types::Intersection.build(types: [t, self.required_keywords[keyword]])
527
- when self.rest_keywords
528
- required_keywords[keyword] = AST::Types::Intersection.build(types: [t, self.rest_keywords])
579
+ when s = other.requireds[key]
580
+ optionals[key] = s
581
+ when s = other.optionals[key]
582
+ optionals[key] = s
583
+ when s = other.rest
584
+ # nop
529
585
  else
530
- return
586
+ # cannot happen
531
587
  end
532
588
  end
533
589
  end
534
590
 
535
- rest = case
536
- when self.rest_keywords && other.rest_keywords
537
- AST::Types::Intersection.build(types: [self.rest_keywords, other.rest_keywords])
538
- else
539
- nil
540
- end
591
+ rest =
592
+ if self.rest && other.rest
593
+ union(self.rest, other.rest)
594
+ else
595
+ self.rest || other.rest
596
+ end
541
597
 
542
- Params.new(
543
- required: [],
544
- optional: [],
545
- rest: nil,
546
- required_keywords: required_keywords,
547
- optional_keywords: optional_keywords,
548
- rest_keywords: rest)
598
+ KeywordParams.new(requireds: requireds, optionals: optionals, rest: rest)
549
599
  end
550
- end
551
-
552
- # Returns the union between self and other.
553
- #
554
- def |(other)
555
- a = first_param
556
- b = other.first_param
557
600
 
558
- case
559
- when a.is_a?(RequiredPositional) && b.is_a?(RequiredPositional)
560
- AST::Types::Union.build(types: [a.type, b.type]).yield_self do |type|
561
- (self.drop_first | other.drop_first)&.with_first_param(RequiredPositional.new(type))
562
- end
563
- when a.is_a?(RequiredPositional) && b.is_a?(OptionalPositional)
564
- AST::Types::Union.build(types: [a.type, b.type]).yield_self do |type|
565
- (self.drop_first | other.drop_first)&.with_first_param(OptionalPositional.new(type))
566
- end
567
- when a.is_a?(RequiredPositional) && b.is_a?(RestPositional)
568
- AST::Types::Union.build(types: [a.type, b.type]).yield_self do |type|
569
- (self.drop_first | other.drop_first)&.with_first_param(OptionalPositional.new(type))
570
- end
571
- when a.is_a?(RequiredPositional) && b.nil?
572
- self.drop_first&.with_first_param(OptionalPositional.new(a.type))
573
- when a.is_a?(OptionalPositional) && b.is_a?(RequiredPositional)
574
- AST::Types::Union.build(types: [a.type, b.type]).yield_self do |type|
575
- (self.drop_first | other.drop_first)&.with_first_param(OptionalPositional.new(type))
576
- end
577
- when a.is_a?(OptionalPositional) && b.is_a?(OptionalPositional)
578
- AST::Types::Union.build(types: [a.type, b.type]).yield_self do |type|
579
- (self.drop_first | other.drop_first)&.with_first_param(OptionalPositional.new(type))
580
- end
581
- when a.is_a?(OptionalPositional) && b.is_a?(RestPositional)
582
- AST::Types::Union.build(types: [a.type, b.type]).yield_self do |type|
583
- (self.drop_first | other.drop_first)&.with_first_param(OptionalPositional.new(type))
584
- end
585
- when a.is_a?(OptionalPositional) && b.nil?
586
- (self.drop_first | other)&.with_first_param(a)
587
- when a.is_a?(RestPositional) && b.is_a?(RequiredPositional)
588
- AST::Types::Union.build(types: [a.type, b.type]).yield_self do |type|
589
- (self.drop_first | other.drop_first)&.with_first_param(OptionalPositional.new(type))
590
- end
591
- when a.is_a?(RestPositional) && b.is_a?(OptionalPositional)
592
- AST::Types::Union.build(types: [a.type, b.type]).yield_self do |type|
593
- (self | other.drop_first)&.with_first_param(OptionalPositional.new(type))
594
- end
595
- when a.is_a?(RestPositional) && b.is_a?(RestPositional)
596
- AST::Types::Union.build(types: [a.type, b.type]).yield_self do |type|
597
- (self.drop_first | other.drop_first)&.with_first_param(RestPositional.new(type))
598
- end
599
- when a.is_a?(RestPositional) && b.nil?
600
- (self.drop_first | other)&.with_first_param(a)
601
- when a.nil? && b.is_a?(RequiredPositional)
602
- other.drop_first&.with_first_param(OptionalPositional.new(b.type))
603
- when a.nil? && b.is_a?(OptionalPositional)
604
- (self | other.drop_first)&.with_first_param(b)
605
- when a.nil? && b.is_a?(RestPositional)
606
- (self | other.drop_first)&.with_first_param(b)
607
- when a.nil? && b.nil?
608
- required_keywords = {}
609
- optional_keywords = {}
610
-
611
- (Set.new(self.required_keywords.keys) & Set.new(other.required_keywords.keys)).each do |keyword|
612
- required_keywords[keyword] = AST::Types::Union.build(
613
- types: [
614
- self.required_keywords[keyword],
615
- other.required_keywords[keyword]
616
- ]
617
- )
618
- end
601
+ # For intersection
602
+ def &(other)
603
+ requireds = {}
604
+ optionals = {}
619
605
 
620
- self.optional_keywords.each do |keyword, t|
621
- unless optional_keywords.key?(keyword) || required_keywords.key?(keyword)
606
+ all_keys = Set[] + self.requireds.keys + self.optionals.keys + other.requireds.keys + other.optionals.keys
607
+ all_keys.each do |key|
608
+ case
609
+ when t = self.requireds[key]
622
610
  case
623
- when s = other.required_keywords[keyword]
624
- optional_keywords[keyword] = AST::Types::Union.build(types: [t, s])
625
- when s = other.optional_keywords[keyword]
626
- optional_keywords[keyword] = AST::Types::Union.build(types: [t, s])
627
- when r = other.rest_keywords
628
- optional_keywords[keyword] = AST::Types::Union.build(types: [t, r])
611
+ when s = other.requireds[key]
612
+ requireds[key] = intersection(t, s)
613
+ when s = other.optionals[key]
614
+ requireds[key] = intersection(t, s)
615
+ when s = other.rest
616
+ requireds[key] = intersection(t, s)
629
617
  else
630
- optional_keywords[keyword] = t
618
+ return nil
631
619
  end
632
- end
633
- end
634
- other.optional_keywords.each do |keyword, t|
635
- unless optional_keywords.key?(keyword) || required_keywords.key?(keyword)
620
+ when t = self.optionals[key]
636
621
  case
637
- when s = self.required_keywords[keyword]
638
- optional_keywords[keyword] = AST::Types::Union.build(types: [t, s])
639
- when s = self.optional_keywords[keyword]
640
- optional_keywords[keyword] = AST::Types::Union.build(types: [t, s])
641
- when r = self.rest_keywords
642
- optional_keywords[keyword] = AST::Types::Union.build(types: [t, r])
622
+ when s = other.requireds[key]
623
+ requireds[key] = intersection(t, s)
624
+ when s = other.optionals[key]
625
+ optionals[key] = intersection(t, s)
626
+ when s = other.rest
627
+ optionals[key] = intersection(t, s)
643
628
  else
644
- optional_keywords[keyword] = t
629
+ # nop
645
630
  end
646
- end
647
- end
648
- self.required_keywords.each do |keyword, t|
649
- unless optional_keywords.key?(keyword) || required_keywords.key?(keyword)
631
+ when t = self.rest
650
632
  case
651
- when s = other.optional_keywords[keyword]
652
- optional_keywords[keyword] = AST::Types::Union.build(types: [t, s])
653
- when r = other.rest_keywords
654
- optional_keywords[keyword] = AST::Types::Union.build(types: [t, r])
633
+ when s = other.requireds[key]
634
+ requireds[key] = intersection(t, s)
635
+ when s = other.optionals[key]
636
+ optionals[key] = intersection(t, s)
637
+ when s = other.rest
638
+ # cannot happen
655
639
  else
656
- optional_keywords[keyword] = t
640
+ # nop
657
641
  end
658
- end
659
- end
660
- other.required_keywords.each do |keyword, t|
661
- unless optional_keywords.key?(keyword) || required_keywords.key?(keyword)
642
+ else
662
643
  case
663
- when s = self.optional_keywords[keyword]
664
- optional_keywords[keyword] = AST::Types::Union.build(types: [t, s])
665
- when r = self.rest_keywords
666
- optional_keywords[keyword] = AST::Types::Union.build(types: [t, r])
644
+ when s = other.requireds[key]
645
+ return nil
646
+ when s = other.optionals[key]
647
+ # nop
648
+ when s = other.rest
649
+ # nop
667
650
  else
668
- optional_keywords[keyword] = t
651
+ # cannot happen
669
652
  end
670
653
  end
671
654
  end
672
655
 
673
- rest = case
674
- when self.rest_keywords && other.rest_keywords
675
- AST::Types::Union.build(types: [self.rest_keywords, other.rest_keywords])
676
- when self.rest_keywords
677
- if required_keywords.empty? && optional_keywords.empty?
678
- self.rest_keywords
679
- end
680
- when other.rest_keywords
681
- if required_keywords.empty? && optional_keywords.empty?
682
- other.rest_keywords
683
- end
684
- else
685
- nil
686
- end
687
-
688
- Params.new(
689
- required: [],
690
- optional: [],
691
- rest: nil,
692
- required_keywords: required_keywords,
693
- optional_keywords: optional_keywords,
694
- rest_keywords: rest)
656
+ rest =
657
+ if self.rest && other.rest
658
+ intersection(self.rest, other.rest)
659
+ else
660
+ nil
661
+ end
662
+
663
+ KeywordParams.new(requireds: requireds, optionals: optionals, rest: rest)
664
+ end
665
+ end
666
+
667
+ def required
668
+ array = []
669
+
670
+ positional_params&.each do |param|
671
+ case param
672
+ when PositionalParams::Required
673
+ array << param.type
674
+ else
675
+ break
676
+ end
677
+ end
678
+
679
+ array
680
+ end
681
+
682
+ def optional
683
+ array = []
684
+
685
+ positional_params&.each do |param|
686
+ case param
687
+ when PositionalParams::Required
688
+ # skip
689
+ when PositionalParams::Optional
690
+ array << param.type
691
+ else
692
+ break
693
+ end
694
+ end
695
+
696
+ array
697
+ end
698
+
699
+ def rest
700
+ positional_params&.each do |param|
701
+ case param
702
+ when PositionalParams::Required, PositionalParams::Optional
703
+ # skip
704
+ when PositionalParams::Rest
705
+ return param.type
706
+ end
707
+ end
708
+ end
709
+
710
+ attr_reader :positional_params
711
+ attr_reader :keyword_params
712
+
713
+ def self.build(required: [], optional: [], rest: nil, required_keywords: {}, optional_keywords: {}, rest_keywords: nil)
714
+ positional_params = PositionalParams.build(required: required, optional: optional, rest: rest)
715
+ keyword_params = KeywordParams.new(requireds: required_keywords, optionals: optional_keywords, rest: rest_keywords)
716
+ new(positional_params: positional_params, keyword_params: keyword_params)
717
+ end
718
+
719
+ def initialize(positional_params:, keyword_params:)
720
+ @positional_params = positional_params
721
+ @keyword_params = keyword_params
722
+ end
723
+
724
+ def update(positional_params: self.positional_params, keyword_params: self.keyword_params)
725
+ self.class.new(positional_params: positional_params, keyword_params: keyword_params)
726
+ end
727
+
728
+ def first_param
729
+ positional_params&.head
730
+ end
731
+
732
+ def with_first_param(param)
733
+ update(
734
+ positional_params: PositionalParams.new(
735
+ head: param,
736
+ tail: positional_params
737
+ )
738
+ )
739
+ end
740
+
741
+ def has_positional?
742
+ positional_params ? true : false
743
+ end
744
+
745
+ def self.empty
746
+ self.new(positional_params: nil, keyword_params: KeywordParams.new)
747
+ end
748
+
749
+ def ==(other)
750
+ other.is_a?(self.class) &&
751
+ other.positional_params == positional_params &&
752
+ other.keyword_params == keyword_params
753
+ end
754
+
755
+ alias eql? ==
756
+
757
+ def hash
758
+ self.class.hash ^ positional_params.hash ^ keyword_params.hash
759
+ end
760
+
761
+ def flat_unnamed_params
762
+ if positional_params
763
+ positional_params.each.with_object([]) do |param, types|
764
+ case param
765
+ when PositionalParams::Required
766
+ types << [:required, param.type]
767
+ when PositionalParams::Optional
768
+ types << [:optional, param.type]
769
+ end
770
+ end
771
+ else
772
+ []
773
+ end
774
+ end
775
+
776
+ def flat_keywords
777
+ required_keywords.merge(optional_keywords)
778
+ end
779
+
780
+ def required_keywords
781
+ keyword_params.requireds
782
+ end
783
+
784
+ def optional_keywords
785
+ keyword_params.optionals
786
+ end
787
+
788
+ def rest_keywords
789
+ keyword_params.rest
790
+ end
791
+
792
+ def has_keywords?
793
+ !keyword_params.empty?
794
+ end
795
+
796
+ def each_positional_param(&block)
797
+ if block_given?
798
+ if positional_params
799
+ positional_params.each(&block)
800
+ end
801
+ else
802
+ enum_for :each_positional_param
803
+ end
804
+ end
805
+
806
+ def without_keywords
807
+ update(keyword_params: KeywordParams.new)
808
+ end
809
+
810
+ def drop_first
811
+ case
812
+ when positional_params
813
+ update(positional_params: positional_params.tail)
814
+ when has_keywords?
815
+ without_keywords()
816
+ else
817
+ raise "Cannot drop from empty params"
818
+ end
819
+ end
820
+
821
+ def each_type(&block)
822
+ if block_given?
823
+ positional_params&.each_type(&block)
824
+ keyword_params.each_type(&block)
825
+ else
826
+ enum_for :each_type
827
+ end
828
+ end
829
+
830
+ def free_variables()
831
+ @fvs ||= Set.new.tap do |set|
832
+ each_type do |type|
833
+ set.merge(type.free_variables)
834
+ end
835
+ end
836
+ end
837
+
838
+ def closed?
839
+ each_type.all?(&:closed?)
840
+ end
841
+
842
+ def subst(s)
843
+ return self if s.empty?
844
+ return self if empty?
845
+ return self if free_variables.disjoint?(s.domain)
846
+
847
+ pp = positional_params&.subst(s)
848
+ kp = keyword_params.subst(s)
849
+
850
+ if positional_params == pp && keyword_params == kp
851
+ self
852
+ else
853
+ self.class.new(positional_params: pp, keyword_params: kp)
695
854
  end
696
855
  end
856
+
857
+ def size
858
+ (positional_params&.size || 0) + keyword_params.size
859
+ end
860
+
861
+ def to_s
862
+ required = self.required.map {|ty| ty.to_s }
863
+ optional = self.optional.map {|ty| "?#{ty}" }
864
+ rest = self.rest ? ["*#{self.rest}"] : []
865
+ required_keywords = keyword_params.requireds.map {|name, type| "#{name}: #{type}" }
866
+ optional_keywords = keyword_params.optionals.map {|name, type| "?#{name}: #{type}"}
867
+ rest_keywords = keyword_params.rest ? ["**#{keyword_params.rest}"] : []
868
+ "(#{(required + optional + rest + required_keywords + optional_keywords + rest_keywords).join(", ")})"
869
+ end
870
+
871
+ def map_type(&block)
872
+ self.class.new(
873
+ positional_params: positional_params&.map_type(&block),
874
+ keyword_params: keyword_params.map_type(&block)
875
+ )
876
+ end
877
+
878
+ def empty?
879
+ !has_positional? && !has_keywords?
880
+ end
881
+
882
+ # self + params returns a new params for overloading.
883
+ #
884
+ def +(other)
885
+ pp = PositionalParams.merge_for_overload(positional_params, other.positional_params)
886
+ kp = keyword_params + other.keyword_params
887
+ Params.new(positional_params: pp, keyword_params: kp)
888
+ end
889
+
890
+ # Returns the intersection between self and other.
891
+ # Returns nil if the intersection cannot be computed.
892
+ #
893
+ # (self & other) <: self
894
+ # (self & other) <: other
895
+ #
896
+ # `self & other` accept `arg` if `arg` is acceptable for both of `self` and `other`.
897
+ #
898
+ def &(other)
899
+ pp = PositionalParams.merge_for_intersection(positional_params, other.positional_params) rescue return
900
+ kp = keyword_params & other.keyword_params or return
901
+ Params.new(positional_params: pp, keyword_params: kp)
902
+ end
903
+
904
+ # Returns the union between self and other.
905
+ #
906
+ # self <: (self | other)
907
+ # other <: (self | other)
908
+ #
909
+ # `self | other` accept `arg` if `self` accepts `arg` or `other` accepts `arg`.
910
+ #
911
+ def |(other)
912
+ pp = PositionalParams.merge_for_union(positional_params, other.positional_params) rescue return
913
+ kp = keyword_params | other.keyword_params or return
914
+ Params.new(positional_params: pp, keyword_params: kp)
915
+ end
697
916
  end
698
917
 
699
918
  attr_reader :params