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
@@ -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
@@ -8,6 +8,7 @@ module Steep
8
8
  attr_reader :command_line_patterns
9
9
  attr_accessor :with_expectations_path
10
10
  attr_accessor :save_expectations_path
11
+ attr_accessor :severity_level
11
12
 
12
13
  include Utils::DriverHelper
13
14
  include Utils::JobsCount
@@ -16,6 +17,7 @@ module Steep
16
17
  @stdout = stdout
17
18
  @stderr = stderr
18
19
  @command_line_patterns = []
20
+ @severity_level = :warning
19
21
  end
20
22
 
21
23
  def run
@@ -70,6 +72,7 @@ module Steep
70
72
  case
71
73
  when response[:method] == "textDocument/publishDiagnostics"
72
74
  ds = response[:params][:diagnostics]
75
+ ds.select! {|d| keep_diagnostic?(d) }
73
76
  if ds.empty?
74
77
  stdout.print "."
75
78
  else
@@ -8,6 +8,8 @@ module Steep
8
8
  include Utils::DriverHelper
9
9
 
10
10
  TEMPLATE = <<~EOF
11
+ # D = Steep::Diagnostic
12
+ #
11
13
  # target :lib do
12
14
  # signature "sig"
13
15
  #
@@ -18,15 +20,20 @@ module Steep
18
20
  #
19
21
  # # library "pathname", "set" # Standard libraries
20
22
  # # library "strong_json" # Gems
23
+ #
24
+ # # configure_code_diagnostics(D::Ruby.strict) # `strict` diagnostics setting
25
+ # # configure_code_diagnostics(D::Ruby.lenient) # `lenient` diagnostics setting
26
+ # # configure_code_diagnostics do |hash| # You can setup everything yourself
27
+ # # hash[D::Ruby::NoMethod] = :information
28
+ # # end
21
29
  # end
22
30
 
23
- # target :spec do
31
+ # target :test do
24
32
  # signature "sig", "sig-private"
25
33
  #
26
- # check "spec"
34
+ # check "test"
27
35
  #
28
36
  # # library "pathname", "set" # Standard libraries
29
- # # library "rspec"
30
37
  # end
31
38
  EOF
32
39
 
@@ -55,6 +55,21 @@ module Steep
55
55
  end
56
56
  end
57
57
  end
58
+
59
+ def keep_diagnostic?(diagnostic)
60
+ severity = diagnostic[:severity]
61
+
62
+ case self.severity_level
63
+ when nil, :hint
64
+ true
65
+ when :error
66
+ severity <= LanguageServer::Protocol::Constant::DiagnosticSeverity::ERROR
67
+ when :warning
68
+ severity <= LanguageServer::Protocol::Constant::DiagnosticSeverity::WARNING
69
+ when :information
70
+ severity <= LanguageServer::Protocol::Constant::DiagnosticSeverity::INFORMATION
71
+ end
72
+ end
58
73
  end
59
74
  end
60
75
  end
@@ -36,7 +36,7 @@ module Steep
36
36
 
37
37
  any_error ||= !errors.empty?
38
38
 
39
- formatter = Diagnostic::LSPFormatter.new
39
+ formatter = Diagnostic::LSPFormatter.new({})
40
40
  diagnostics = errors.group_by {|e| e.location.buffer }.transform_values do |errors|
41
41
  errors.map {|error| formatter.format(error) }
42
42
  end
@@ -5,6 +5,7 @@ module Steep
5
5
  attr_reader :stdout
6
6
  attr_reader :stderr
7
7
  attr_reader :queue
8
+ attr_accessor :severity_level
8
9
 
9
10
  include Utils::DriverHelper
10
11
  include Utils::JobsCount
@@ -16,6 +17,7 @@ module Steep
16
17
  @stdout = stdout
17
18
  @stderr = stderr
18
19
  @queue = Thread::Queue.new
20
+ @severity_level = :warning
19
21
  end
20
22
 
21
23
  def watching?(changed_path, files:, dirs:)
@@ -126,6 +128,7 @@ module Steep
126
128
  printer = DiagnosticPrinter.new(stdout: stdout, buffer: buffer)
127
129
 
128
130
  diagnostics = response[:params][:diagnostics]
131
+ diagnostics.filter! {|d| keep_diagnostic?(d) }
129
132
 
130
133
  unless diagnostics.empty?
131
134
  diagnostics.each do |diagnostic|
@@ -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