diff --git a/lib/dry/types/compiler.rb b/lib/dry/types/compiler.rb index 39a254ef..9f8f74b2 100644 --- a/lib/dry/types/compiler.rb +++ b/lib/dry/types/compiler.rb @@ -113,6 +113,16 @@ def visit_any(meta) registry["any"].meta(meta) end + def visit_intersection(node) + *types, meta = node + types.map { |type| visit(type) }.reduce(:&).meta(meta) + end + + def visit_implication(node) + *types, meta = node + types.map { |type| visit(type) }.reduce(:>).meta(meta) + end + def compile_fn(fn) type, *node = fn diff --git a/spec/dry/types/compiler_spec.rb b/spec/dry/types/compiler_spec.rb index 48cb126d..58d28e94 100644 --- a/spec/dry/types/compiler_spec.rb +++ b/spec/dry/types/compiler_spec.rb @@ -377,4 +377,40 @@ expect(type).to eql(source) end end + + context "composites" do + let(:strict_nil_ast) do + [:constrained, + [[:nominal, [NilClass, {}]], + [:predicate, [:type?, [[:type, NilClass], [:input, Undefined]]]]]] + end + + let(:strict_integer_ast) do + [:constrained, + [[:nominal, [Integer, {}]], + [:predicate, [:type?, [[:type, Integer], [:input, Undefined]]]]]] + end + + let(:any_numeric_ast) do + [:constrained, [[:any, {}], [:predicate, [:type?, [[:type, Numeric], [:input, Undefined]]]]]] + end + + it 'builds a sum' do + ast = [:sum, [strict_nil_ast, strict_integer_ast, {}]] + type = compiler.(ast) + expect(type).to eql(Dry::Types['integer'].optional) + end + + it 'builds an implication' do + ast = [:implication, [any_numeric_ast, strict_integer_ast, {}]] + type = compiler.(ast) + expect(type).to eql(Dry::Types['any'].constrained(type: Numeric) > Dry::Types['integer']) + end + + it 'builds an intersection' do + ast = [:intersection, [any_numeric_ast, strict_integer_ast, {}]] + type = compiler.(ast) + expect(type).to eql(Dry::Types['any'].constrained(type: Numeric) & Dry::Types['integer']) + end + end end diff --git a/spec/dry/types/implication_spec.rb b/spec/dry/types/implication_spec.rb index 5170949e..0a80b443 100644 --- a/spec/dry/types/implication_spec.rb +++ b/spec/dry/types/implication_spec.rb @@ -216,15 +216,14 @@ end describe "#meta" do - context "optional types" do - let(:meta) { {foo: :bar} } + let(:meta) { {foo: :bar} } - subject(:type) { t::Nominal::String.optional } + subject(:type) { t::Nominal::Hash > t.Hash(foo: t::Nominal::Integer) } - it "uses meta from the right branch" do - expect(type.meta(meta).meta).to eql(meta) - expect(type.meta(meta).right.meta).to eql(meta) - end + it "has no special meta handling" do + expect(type.meta(meta).meta).to eql(meta) + expect(type.meta(meta).left.meta).to eql({}) + expect(type.meta(meta).right.meta).to eql({}) end end end diff --git a/spec/dry/types/intersection_spec.rb b/spec/dry/types/intersection_spec.rb index 10ceba2b..9c44faf2 100644 --- a/spec/dry/types/intersection_spec.rb +++ b/spec/dry/types/intersection_spec.rb @@ -231,15 +231,14 @@ end describe "#meta" do - context "optional types" do - let(:meta) { {foo: :bar} } + let(:meta) { {foo: :bar} } - subject(:type) { Dry::Types["string"].optional } + subject(:type) { t::Nominal::Hash & t.Hash(foo: t::Nominal::Integer) } - it "uses meta from the right branch" do - expect(type.meta(meta).meta).to eql(meta) - expect(type.meta(meta).right.meta).to eql(meta) - end + it "has no special meta handling" do + expect(type.meta(meta).meta).to eql(meta) + expect(type.meta(meta).left.meta).to eql({}) + expect(type.meta(meta).right.meta).to eql({}) end end end