literal 1.8.1 → 1.9.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 (53) hide show
  1. checksums.yaml +4 -4
  2. data/lib/literal/array.rb +2 -2
  3. data/lib/literal/data.rb +10 -2
  4. data/lib/literal/data_structure.rb +2 -0
  5. data/lib/literal/enum.rb +17 -5
  6. data/lib/literal/errors/type_error.rb +13 -0
  7. data/lib/literal/failure.rb +79 -1
  8. data/lib/literal/properties/introspection.rb +59 -0
  9. data/lib/literal/properties/schema.rb +2 -2
  10. data/lib/literal/properties.rb +10 -1
  11. data/lib/literal/property.rb +9 -3
  12. data/lib/literal/rails/relation_type.rb +4 -12
  13. data/lib/literal/result.rb +68 -0
  14. data/lib/literal/result_handler.rb +54 -0
  15. data/lib/literal/struct.rb +1 -1
  16. data/lib/literal/subtype_context.rb +33 -0
  17. data/lib/literal/success.rb +97 -1
  18. data/lib/literal/tuple.rb +2 -2
  19. data/lib/literal/type.rb +10 -1
  20. data/lib/literal/types/any_type.rb +1 -1
  21. data/lib/literal/types/array_type.rb +7 -2
  22. data/lib/literal/types/boolean_type.rb +1 -1
  23. data/lib/literal/types/class_type.rb +3 -3
  24. data/lib/literal/types/constraint_type.rb +12 -5
  25. data/lib/literal/types/deferred_type.rb +2 -2
  26. data/lib/literal/types/descendant_type.rb +2 -2
  27. data/lib/literal/types/enumerable_type.rb +2 -2
  28. data/lib/literal/types/falsy_type.rb +1 -1
  29. data/lib/literal/types/frozen_type.rb +4 -4
  30. data/lib/literal/types/hash_type.rb +8 -3
  31. data/lib/literal/types/interface_type.rb +3 -3
  32. data/lib/literal/types/intersection_type.rb +11 -4
  33. data/lib/literal/types/json_data_type.rb +4 -4
  34. data/lib/literal/types/kind_type.rb +18 -0
  35. data/lib/literal/types/map_type.rb +2 -2
  36. data/lib/literal/types/never_type.rb +6 -2
  37. data/lib/literal/types/nilable_type.rb +3 -3
  38. data/lib/literal/types/not_type.rb +4 -4
  39. data/lib/literal/types/range_type.rb +2 -2
  40. data/lib/literal/types/{unit_type.rb → same_object_type.rb} +3 -3
  41. data/lib/literal/types/set_type.rb +2 -2
  42. data/lib/literal/types/tagged_union_type.rb +71 -0
  43. data/lib/literal/types/truthy_type.rb +1 -1
  44. data/lib/literal/types/tuple_type.rb +1 -1
  45. data/lib/literal/types/union_type.rb +44 -13
  46. data/lib/literal/types/void_type.rb +1 -1
  47. data/lib/literal/types.rb +22 -6
  48. data/lib/literal/undefined.rb +21 -0
  49. data/lib/literal/version.rb +1 -1
  50. data/lib/literal.rb +92 -22
  51. data/lib/ruby_lsp/literal/addon.rb +7 -2
  52. metadata +9 -4
  53. data/lib/literal/null.rb +0 -13
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d45b4ed514f637e98bd45cd2ecbf54b3eba3cc8ece8c513cea63258ef11cd842
4
- data.tar.gz: 10486859e1ecb34e9f0af4da5c2a5e6f408e49d1ff8403f75643839df8b10ccb
3
+ metadata.gz: 0bb6bc1253e6b8116aaf174380fb8ea5a0edbaec66d80df5f514a2a3241325b8
4
+ data.tar.gz: f018a260e5c17f101813d1e665f314ecebb80b9f769e59eccc8b67bb196a64b6
5
5
  SHA512:
6
- metadata.gz: 881e25855ffe6931e684eee59030f55fce875fd48092934ad83a76e7270410aba9eb10b774584c6e45b61fc7fecfa6ebea3b400275a326f6ad2464d67a390084
7
- data.tar.gz: 2ef3da3eabc5c3c8db4c71135cae66fed8185007f7583864345dcd476dad528865dd4d7f81bc6045babddf19c9487965845758e2555359e95ae54bb9ed3abf20
6
+ metadata.gz: 79d7771c617d331b8bc6a6cb94cc7949059dbcf5e449162a21c0f502de8081075aeb32810313b77d10a9439ef88c65bf4db3c1815f78eb2771466acdb9a551db
7
+ data.tar.gz: 8b48552cf91a9b474501f906b6bdd1b04fdfc68b0102ec388063c3d8b7dc50b5520a49bb79e00a3ef84aa56899167d416b2911f672522b60c77bde38d5cb09cc
data/lib/literal/array.rb CHANGED
@@ -20,10 +20,10 @@ class Literal::Array
20
20
  Literal::Array === value && Literal.subtype?(value.__type__, @type)
21
21
  end
22
22
 
23
- def >=(other)
23
+ def >=(other, context: nil)
24
24
  case other
25
25
  when Literal::Array::Generic
26
- Literal.subtype?(other.type, @type)
26
+ Literal.subtype?(other.type, @type, context:)
27
27
  else
28
28
  false
29
29
  end
data/lib/literal/data.rb CHANGED
@@ -2,8 +2,16 @@
2
2
 
3
3
  class Literal::Data < Literal::DataStructure
4
4
  class << self
5
- def prop(name, type, kind = :keyword, reader: :public, predicate: false, default: nil)
6
- super(name, type, kind, reader:, writer: false, predicate:, default:)
5
+ def [](...) = new(...)
6
+
7
+ def define(**properties)
8
+ Class.new(self) do
9
+ properties.each { |name, type| prop(name, type) }
10
+ end
11
+ end
12
+
13
+ def prop(name, type, kind = :keyword, reader: :public, predicate: false, default: nil, description: nil)
14
+ super(name, type, kind, reader:, writer: false, predicate:, default:, description:)
7
15
  end
8
16
 
9
17
  def literal_properties
@@ -29,6 +29,7 @@ class Literal::DataStructure
29
29
  marshal_dump
30
30
  end
31
31
 
32
+ # required method for Marshal compatibility
32
33
  def marshal_load(payload)
33
34
  _version, attributes, was_frozen = payload
34
35
 
@@ -39,6 +40,7 @@ class Literal::DataStructure
39
40
  freeze if was_frozen
40
41
  end
41
42
 
43
+ # required method for Marshal compatibility
42
44
  def marshal_dump
43
45
  [1, to_h, frozen?].freeze
44
46
  end
data/lib/literal/enum.rb CHANGED
@@ -11,8 +11,8 @@ class Literal::Enum
11
11
  def values = @values.keys
12
12
  def names = @names
13
13
 
14
- def prop(name, type, kind = :keyword, reader: :public, predicate: false, default: nil)
15
- super(name, type, kind, reader:, writer: false, predicate:, default:)
14
+ def prop(name, type, kind = :keyword, reader: :public, predicate: false, default: nil, description: nil)
15
+ super(name, type, kind, reader:, writer: false, predicate:, default:, description:)
16
16
  end
17
17
 
18
18
  def inherited(subclass)
@@ -55,7 +55,7 @@ class Literal::Enum
55
55
 
56
56
  types = @indexes_definitions.fetch(key)
57
57
  type = types.first
58
- Literal.check(value, type) { |c| raise NotImplementedError }
58
+ Literal.check(value, type)
59
59
 
60
60
  @indexes.fetch(key)[value]
61
61
  end
@@ -125,7 +125,12 @@ class Literal::Enum
125
125
 
126
126
  index.each do |key, values|
127
127
  unless type === key
128
- raise Literal::TypeError.expected(key, to_be_a: type)
128
+ raise Literal::TypeError.new(
129
+ context: Literal::TypeError::Context.new(
130
+ expected: type,
131
+ actual: key,
132
+ )
133
+ )
129
134
  end
130
135
 
131
136
  if unique && values.size > 1
@@ -199,7 +204,14 @@ class Literal::Enum
199
204
  end
200
205
 
201
206
  alias_method :inspect, :name
202
- alias_method :to_s, :name
207
+
208
+ def to_sym
209
+ self.class.names[self]
210
+ end
211
+
212
+ def to_s
213
+ to_sym.to_s
214
+ end
203
215
 
204
216
  def deconstruct
205
217
  [@value]
@@ -41,6 +41,19 @@ class Literal::TypeError < TypeError
41
41
  expected.record_literal_type_errors(child) if expected.respond_to?(:record_literal_type_errors)
42
42
  @children << child
43
43
  end
44
+
45
+ def to_h
46
+ {
47
+ receiver: @receiver,
48
+ method: @method,
49
+ label: @label,
50
+ expected: @expected,
51
+ actual: @actual,
52
+ children: @children.map(&:to_h),
53
+ }
54
+ end
55
+
56
+ alias to_hash to_h
44
57
  end
45
58
 
46
59
  def initialize(context:)
@@ -1,7 +1,85 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Literal::Failure < Literal::Result
4
- def initialize(error)
4
+ class Generic
5
+ include Literal::Type
6
+
7
+ def initialize(type)
8
+ @type = type
9
+ freeze
10
+ end
11
+
12
+ attr_reader :type
13
+
14
+ def ===(object)
15
+ Literal::Failure === object && @type === object.error!
16
+ end
17
+
18
+ def inspect
19
+ "Literal::Failure(#{@type.inspect})"
20
+ end
21
+
22
+ freeze
23
+ end
24
+
25
+ def initialize(error, success_type:, failure_type:)
5
26
  @error = error
27
+
28
+ @success_type = success_type
29
+ @failure_type = failure_type
30
+
31
+ Literal.check(error, failure_type)
32
+
33
+ freeze
34
+ end
35
+
36
+ attr_reader :success_type, :failure_type
37
+
38
+ def success?
39
+ false
40
+ end
41
+
42
+ def failure?
43
+ true
44
+ end
45
+
46
+ def value!
47
+ raise Literal::ArgumentError.new("Failure has no value")
48
+ end
49
+
50
+ def deconstruct
51
+ [@error]
52
+ end
53
+
54
+ def deconstruct_keys(keys)
55
+ if @error.respond_to?(:deconstruct_keys)
56
+ @error.deconstruct_keys(keys)
57
+ else
58
+ {}
59
+ end
60
+ end
61
+
62
+ def error!
63
+ @error
64
+ end
65
+
66
+ def map(type)
67
+ raise ArgumentError unless block_given?
68
+
69
+ Literal::Failure.new(
70
+ @error,
71
+ success_type: type,
72
+ failure_type: @failure_type
73
+ )
74
+ end
75
+
76
+ def then
77
+ raise ArgumentError unless block_given?
78
+ self
79
+ end
80
+
81
+ def value_or
82
+ raise ArgumentError unless block_given?
83
+ yield(@error)
6
84
  end
7
85
  end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Literal::Properties::Introspection
4
+ def positional_properties
5
+ literal_properties.filter(&:positional?)
6
+ end
7
+
8
+ def keyword_properties
9
+ literal_properties.filter(&:keyword?)
10
+ end
11
+
12
+ def required_properties
13
+ literal_properties.filter(&:required?)
14
+ end
15
+
16
+ def required_positional_properties
17
+ required_properties.filter(&:positional?)
18
+ end
19
+
20
+ def required_keyword_properties
21
+ required_properties.filter(&:keyword?)
22
+ end
23
+
24
+ def optional_positional_properties
25
+ positional_properties - required_positional_properties
26
+ end
27
+
28
+ def optional_keyword_properties
29
+ keyword_properties - required_keyword_properties
30
+ end
31
+
32
+ def positional_property_names
33
+ positional_properties.map(&:name)
34
+ end
35
+
36
+ def keyword_property_names
37
+ keyword_properties.map(&:name)
38
+ end
39
+
40
+ def required_property_names
41
+ required_properties.map(&:name)
42
+ end
43
+
44
+ def required_positional_property_names
45
+ required_positional_properties.map(&:name)
46
+ end
47
+
48
+ def required_keyword_property_names
49
+ required_keyword_properties.map(&:name)
50
+ end
51
+
52
+ def optional_positional_property_names
53
+ optional_positional_properties.map(&:name)
54
+ end
55
+
56
+ def optional_keyword_property_names
57
+ optional_keyword_properties.map(&:name)
58
+ end
59
+ end
@@ -127,7 +127,7 @@ class Literal::Properties::Schema
127
127
  buffer << "&" << property.escaped_name
128
128
  when :positional
129
129
  if property.default?
130
- buffer << property.escaped_name << " = Literal::Null"
130
+ buffer << property.escaped_name << " = Literal::Undefined"
131
131
  elsif property.type === nil # optional
132
132
  buffer << property.escaped_name << " = nil"
133
133
  else # required
@@ -135,7 +135,7 @@ class Literal::Properties::Schema
135
135
  end
136
136
  when :keyword
137
137
  if property.default?
138
- buffer << property.name.name << ": Literal::Null"
138
+ buffer << property.name.name << ": Literal::Undefined"
139
139
  elsif property.type === nil
140
140
  buffer << property.name.name << ": nil" # optional
141
141
  else # required
@@ -13,7 +13,11 @@ module Literal::Properties
13
13
  base.include(base.__send__(:__literal_extension__))
14
14
  end
15
15
 
16
- def prop(name, type, kind = :keyword, reader: false, writer: false, predicate: false, default: nil, &coercion)
16
+ def prop?(name, type, kind = :keyword, reader: false, writer: false, predicate: false, &coercion)
17
+ prop(name, _Union(type, Literal::Undefined), kind, reader:, writer:, predicate:, default: Literal::Undefined, description: nil, &coercion)
18
+ end
19
+
20
+ def prop(name, type, kind = :keyword, reader: false, writer: false, predicate: false, default: nil, description: nil, &coercion)
17
21
  if default && !(Proc === default || default.frozen?)
18
22
  raise Literal::ArgumentError.new("The default must be a frozen object or a Proc.")
19
23
  end
@@ -40,6 +44,10 @@ module Literal::Properties
40
44
  raise Literal::ArgumentError.new("The kind must be one of #{Literal::Property::KIND_OPTIONS.map(&:inspect).join(', ')}.")
41
45
  end
42
46
 
47
+ unless description.nil? || String === description
48
+ raise Literal::ArgumentError.new("The description must be a String or nil.")
49
+ end
50
+
43
51
  property = __literal_property_class__.new(
44
52
  name:,
45
53
  type:,
@@ -48,6 +56,7 @@ module Literal::Properties
48
56
  writer:,
49
57
  predicate:,
50
58
  default:,
59
+ description:,
51
60
  coercion:,
52
61
  )
53
62
 
@@ -9,7 +9,7 @@ class Literal::Property
9
9
 
10
10
  include Comparable
11
11
 
12
- def initialize(name:, type:, kind:, reader:, writer:, predicate:, default:, coercion:)
12
+ def initialize(name:, type:, kind:, reader:, writer:, predicate:, default:, description:, coercion:)
13
13
  @name = name
14
14
  @type = type
15
15
  @kind = kind
@@ -17,10 +17,11 @@ class Literal::Property
17
17
  @writer = writer
18
18
  @predicate = predicate
19
19
  @default = default
20
+ @description = description
20
21
  @coercion = coercion
21
22
  end
22
23
 
23
- attr_reader :name, :type, :kind, :reader, :writer, :predicate, :default, :coercion
24
+ attr_reader :name, :type, :kind, :reader, :writer, :predicate, :default, :description, :coercion
24
25
 
25
26
  def optional?
26
27
  default? || @type === nil
@@ -51,9 +52,14 @@ class Literal::Property
51
52
  end
52
53
 
53
54
  def default?
55
+ return true if splat? || double_splat?
54
56
  nil != @default
55
57
  end
56
58
 
59
+ def description?
60
+ !!@description
61
+ end
62
+
57
63
  def param
58
64
  case @kind
59
65
  when :*
@@ -183,7 +189,7 @@ class Literal::Property
183
189
  private def generate_initializer_assign_default(buffer = +"")
184
190
  buffer <<
185
191
  " if " <<
186
- ((@kind == :&) ? "nil" : "Literal::Null") <<
192
+ ((@kind == :&) ? "nil" : "Literal::Undefined") <<
187
193
  " == " <<
188
194
  escaped_name <<
189
195
  "\n " <<
@@ -3,14 +3,6 @@
3
3
  module Literal::Rails
4
4
  class RelationType
5
5
  def initialize(model_class)
6
- unless Class === model_class && model_class < ActiveRecord::Base
7
- raise Literal::TypeError.new(
8
- context: Literal::TypeError::Context.new(
9
- expected: ActiveRecord::Base, actual: model_class
10
- )
11
- )
12
- end
13
-
14
6
  @model_class = model_class
15
7
  end
16
8
 
@@ -18,10 +10,10 @@ module Literal::Rails
18
10
 
19
11
  def ===(value)
20
12
  case value
21
- when ActiveRecord::Relation, ActiveRecord::Associations::CollectionProxy, ActiveRecord::AssociationRelation
22
- @model_class == value.model || value.model < @model_class
23
- else
24
- false
13
+ when ActiveRecord::Relation, ActiveRecord::Associations::CollectionProxy, ActiveRecord::AssociationRelation
14
+ @model_class == value.model || value.model < @model_class
15
+ else
16
+ false
25
17
  end
26
18
  end
27
19
  end
@@ -1,4 +1,72 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Literal::Result
4
+ class Thrown
5
+ def initialize(result)
6
+ @result = result
7
+ freeze
8
+ end
9
+
10
+ attr_reader :result
11
+ end
12
+
13
+ class Emitter
14
+ def initialize(type:, ball:)
15
+ @type = type
16
+ @ball = ball
17
+ freeze
18
+ end
19
+
20
+ def success(value)
21
+ throw(@ball, Thrown.new(@type.success(value)))
22
+ end
23
+
24
+ def failure(error)
25
+ throw(@ball, Thrown.new(@type.failure(error)))
26
+ end
27
+ end
28
+
29
+ class Generic
30
+ include Literal::Type
31
+
32
+ def initialize(success_type, failure_type)
33
+ @success_type = success_type
34
+ @failure_type = failure_type
35
+
36
+ freeze
37
+ end
38
+
39
+ attr_reader :success_type, :failure_type
40
+
41
+ def ===(object)
42
+ case object
43
+ when Literal::Success
44
+ @success_type === object.value!
45
+ when Literal::Failure
46
+ @failure_type === object.error!
47
+ end
48
+ end
49
+
50
+ def success(value)
51
+ Literal::Success.new(
52
+ value,
53
+ success_type: @success_type,
54
+ failure_type: @failure_type
55
+ )
56
+ end
57
+
58
+ def failure(error)
59
+ Literal::Failure.new(
60
+ error,
61
+ success_type: @success_type,
62
+ failure_type: @failure_type
63
+ )
64
+ end
65
+
66
+ freeze
67
+ end
68
+
69
+ def handle(&)
70
+ Literal::ResultHandler.new(self).handle(&)
71
+ end
4
72
  end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Literal::ResultHandler
4
+ def initialize(result)
5
+ @result = result
6
+ @success_cases = []
7
+ @failure_cases = []
8
+ end
9
+
10
+ def handle
11
+ return @result unless block_given?
12
+
13
+ yield(self)
14
+
15
+ unless Literal.subtype?(@result.success_type, covered_type(@success_cases))
16
+ raise Literal::ArgumentError.new("No success handler covers #{@result.success_type.inspect}")
17
+ end
18
+
19
+ unless Literal.subtype?(@result.failure_type, covered_type(@failure_cases))
20
+ raise Literal::ArgumentError.new("No failure handler covers #{@result.failure_type.inspect}")
21
+ end
22
+
23
+ case @result
24
+ when Literal::Success
25
+ @success_cases.each do |type, block|
26
+ if type === @result.value!
27
+ return block&.call(@result.value!)
28
+ end
29
+ end
30
+ when Literal::Failure
31
+ @failure_cases.each do |type, block|
32
+ if type === @result.error!
33
+ return block&.call(@result.error!)
34
+ end
35
+ end
36
+ end
37
+
38
+ raise Literal::ArgumentError.new("Unhandled result type: #{@result.class}")
39
+ end
40
+
41
+ def success(type = Literal::Types::_Any?, &block)
42
+ @success_cases << [type, block]
43
+ end
44
+
45
+ def failure(type = Literal::Types::_Any?, &block)
46
+ @failure_cases << [type, block]
47
+ end
48
+
49
+ private def covered_type(cases)
50
+ return Literal::Types::NeverType::Instance if cases.empty?
51
+
52
+ Literal::Types::_Union(*cases.map(&:first))
53
+ end
54
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  class Literal::Struct < Literal::DataStructure
4
4
  class << self
5
- def prop(name, type, kind = :keyword, reader: :public, writer: :public, default: nil)
5
+ def prop(name, type, kind = :keyword, reader: :public, writer: :public, default: nil, description: nil)
6
6
  super
7
7
  end
8
8
  end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Literal::SubtypeContext
4
+ def initialize
5
+ @memo = {}
6
+ @in_progress = {}
7
+ end
8
+
9
+ attr_reader :memo, :in_progress
10
+
11
+ def memoized?(key)
12
+ @memo.key?(key)
13
+ end
14
+
15
+ def fetch(key)
16
+ @memo[key]
17
+ end
18
+
19
+ def store(key, result)
20
+ @memo[key] = result
21
+ end
22
+
23
+ def acquire(key)
24
+ return false if @in_progress.key?(key)
25
+
26
+ @in_progress[key] = true
27
+ true
28
+ end
29
+
30
+ def release(key)
31
+ @in_progress.delete(key)
32
+ end
33
+ end
@@ -1,7 +1,103 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Literal::Success < Literal::Result
4
- def initialize(value)
4
+ class Generic
5
+ include Literal::Type
6
+
7
+ def initialize(type)
8
+ @type = type
9
+ freeze
10
+ end
11
+
12
+ attr_reader :type
13
+
14
+ def ===(object)
15
+ Literal::Success === object && @type === object.value!
16
+ end
17
+
18
+ def inspect
19
+ "Literal::Success(#{@type.inspect})"
20
+ end
21
+
22
+ freeze
23
+ end
24
+
25
+ def initialize(value, success_type:, failure_type:)
5
26
  @value = value
27
+
28
+ @success_type = success_type
29
+ @failure_type = failure_type
30
+
31
+ Literal.check(@value, success_type)
32
+
33
+ freeze
34
+ end
35
+
36
+ attr_reader :success_type, :failure_type
37
+
38
+ def success?
39
+ true
40
+ end
41
+
42
+ def failure?
43
+ false
44
+ end
45
+
46
+ def value!
47
+ @value
48
+ end
49
+
50
+ def deconstruct
51
+ [@value]
52
+ end
53
+
54
+ def deconstruct_keys(keys)
55
+ if @value.respond_to?(:deconstruct_keys)
56
+ @value.deconstruct_keys(keys)
57
+ else
58
+ {}
59
+ end
60
+ end
61
+
62
+ def error!
63
+ raise Literal::ArgumentError.new("Success has no error")
64
+ end
65
+
66
+ def map(type)
67
+ raise ArgumentError unless block_given?
68
+ result = yield(@value)
69
+
70
+ Literal::Success.new(
71
+ result,
72
+ success_type: type,
73
+ failure_type: @failure_type
74
+ )
75
+ end
76
+
77
+ def then
78
+ raise ArgumentError unless block_given?
79
+ result = yield(@value)
80
+
81
+ case result
82
+ when Literal::Failure
83
+ Literal::Failure.new(
84
+ result.error!,
85
+ success_type: result.success_type,
86
+ failure_type: Literal::Types::_Union(@failure_type, result.failure_type)
87
+ )
88
+ when Literal::Success
89
+ Literal::Success.new(
90
+ result.value!,
91
+ success_type: result.success_type,
92
+ failure_type: Literal::Types::_Union(@failure_type, result.failure_type)
93
+ )
94
+ else
95
+ raise Literal::ArgumentError.new("Expected block to return a Literal::Result, got #{result.class.inspect}")
96
+ end
97
+ end
98
+
99
+ def value_or
100
+ raise ArgumentError unless block_given?
101
+ @value
6
102
  end
7
103
  end
data/lib/literal/tuple.rb CHANGED
@@ -26,7 +26,7 @@ class Literal::Tuple
26
26
  true
27
27
  end
28
28
 
29
- def >=(other)
29
+ def >=(other, context: nil)
30
30
  case other
31
31
  when Literal::Tuple::Generic
32
32
  types = @types
@@ -36,7 +36,7 @@ class Literal::Tuple
36
36
 
37
37
  i, len = 0, types.size
38
38
  while i < len
39
- return false unless Literal.subtype?(other_types[i], types[i])
39
+ return false unless Literal.subtype?(other_types[i], types[i], context:)
40
40
  i += 1
41
41
  end
42
42