From e6d5e016f032495fd1f5b918b195befe019bf582 Mon Sep 17 00:00:00 2001 From: Joel Drapper Date: Thu, 28 Nov 2024 19:26:49 +0000 Subject: [PATCH] Final type comparisons --- lib/literal/types/truthy_type.rb | 21 ++++++++++++++++++--- lib/literal/types/tuple_type.rb | 19 ++++++++++++++++++- lib/literal/types/union_type.rb | 23 +++++++++++++++++++---- test/types.test.rb | 10 ++++++++++ 4 files changed, 65 insertions(+), 8 deletions(-) diff --git a/lib/literal/types/truthy_type.rb b/lib/literal/types/truthy_type.rb index a7cf3ae8..e7026653 100644 --- a/lib/literal/types/truthy_type.rb +++ b/lib/literal/types/truthy_type.rb @@ -1,12 +1,27 @@ # frozen_string_literal: true # @api private -module Literal::Types::TruthyType - def self.inspect = "_Truthy" +class Literal::Types::TruthyTypeClass + include Literal::Type - def self.===(value) + def inspect + "_Truthy" + end + + def ===(value) !!value end + def >=(other) + case other + when Literal::Types::TruthyType, true + true + else + false + end + end + freeze end + +Literal::Types::TruthyType = Literal::Types::TruthyTypeClass.new.freeze diff --git a/lib/literal/types/tuple_type.rb b/lib/literal/types/tuple_type.rb index 6ea36a6d..080715c4 100644 --- a/lib/literal/types/tuple_type.rb +++ b/lib/literal/types/tuple_type.rb @@ -2,13 +2,19 @@ # @api private class Literal::Types::TupleType + include Literal::Type + def initialize(*types) raise Literal::ArgumentError.new("_Tuple type must have at least one type.") if types.size < 1 @types = types end - def inspect = "_Tuple(#{@types.map(&:inspect).join(', ')})" + attr_reader :types + + def inspect + "_Tuple(#{@types.map(&:inspect).join(', ')})" + end def ===(value) return false unless Array === value @@ -39,4 +45,15 @@ def record_literal_type_errors(context) i += 1 end end + + def >=(other) + case other + when Literal::Types::TupleType + @types == other.types + else + false + end + end + + freeze end diff --git a/lib/literal/types/union_type.rb b/lib/literal/types/union_type.rb index c0409319..78ad2626 100644 --- a/lib/literal/types/union_type.rb +++ b/lib/literal/types/union_type.rb @@ -12,7 +12,11 @@ def initialize(*types) @types.freeze end - def inspect = "_Union(#{@types.inspect})" + attr_reader :types + + def inspect + "_Union(#{@types.inspect})" + end def ===(value) types = @types @@ -46,9 +50,20 @@ def record_literal_type_errors(ctx) ctx.children.clear if ctx.children.none? { |c| c.children.any? } end - protected - - attr_reader :types + def >=(other) + case other + when Literal::Types::UnionType + other.types.all? do |other_type| + @types.any? do |type| + Literal.subtype?(type, of: other_type) + end + end + else + @types.any? do |type| + Literal.subtype?(other, of: type) + end + end + end private diff --git a/test/types.test.rb b/test/types.test.rb index ca25a3af..8170397c 100644 --- a/test/types.test.rb +++ b/test/types.test.rb @@ -592,6 +592,10 @@ def expect_type_error(expected:, actual:, message:) refute _Tuple(String, Integer) === ["a"] refute _Tuple(String, Integer) === nil + assert _Tuple(String, Integer) >= _Tuple(String, Integer) + refute _Tuple(String, Integer) >= _Tuple(String, Float) + refute _Tuple(String, Integer) >= [String, Float] + expect_type_error(expected: _Tuple(String, Integer), actual: [1, "a"], message: <<~ERROR) Type mismatch @@ -630,6 +634,12 @@ def expect_type_error(expected:, actual:, message:) refute type === [] refute type === nil + assert _Union(String, Integer) >= _Union(String, Integer) + refute _Union(String, Integer) >= _Union(String, Float) + assert _Union(String, Integer) >= String + refute _Union(String, Integer) >= Numeric + assert _Union(String, Numeric) >= Float + expect_type_error(expected: type, actual: :symbol, message: <<~ERROR) Type mismatch