A possible fix is attached.
From 84f9012c5c4b4fc92e1d994a2b33ae547d509008 Mon Sep 17 00:00:00 2001
From: Graham Knop <haarg@haarg.org>
Date: Thu, 18 May 2017 13:40:58 +0200
Subject: [PATCH] Fix chained union overloads on perl < 5.14
With a type like ArrayRef[Str] | Undef, the overload operation would be
between [Str] and Undef. This would be result in a "half op", an
incomplete overload operation. When ArrayRef would be parameterized
with that half op, it would unwrap it, use [Str] to parameterize itself,
then trigger the overload between itself and the Undef type.
Using ArrayRef[Str] | Undef | Str will first generate the half op of
[Str] | Undef, then trigger the overload with Str. This needs to unwrap
the half op, union the types, then generate a new half op between the
unwrapped [Str] and the union.
---
lib/Type/Tiny.pm | 38 ++++++++++++++++++++++++++++++++------
1 file changed, 32 insertions(+), 6 deletions(-)
diff --git a/lib/Type/Tiny.pm b/lib/Type/Tiny.pm
index 8c5d2fc8..d163d3cd 100644
--- a/lib/Type/Tiny.pm
+++ b/lib/Type/Tiny.pm
@@ -59,18 +59,44 @@ BEGIN
q(&{}) => "_overload_coderef",
q(|) => sub {
my @tc = _swap @_;
- if (!_FIXED_PRECEDENCE && !blessed $tc[0] && ref $tc[0] eq 'ARRAY') {
- require Type::Tiny::_HalfOp;
- return "Type::Tiny::_HalfOp"->new('|', @tc);
+ if (!_FIXED_PRECEDENCE && $_[2]) {
+ if (blessed $tc[0]) {
+ if (blessed $tc[0] eq "Type::Tiny::_HalfOp") {
+ my $type = $tc[0]->{type};
+ my $params = $tc[0]->{params};
+ my $op = $tc[0]->{op};
+ require Type::Tiny::Union;
+ $tc[1] = "Type::Tiny::Union"->new(type_constraints => [$type, $tc[1]]);
+ Type::Tiny::_HalfOp->new($op, @tc);
+ return $tc[0];
+ }
+ }
+ elsif (ref $tc[0] eq 'ARRAY') {
+ require Type::Tiny::_HalfOp;
+ return "Type::Tiny::_HalfOp"->new('|', @tc);
+ }
}
require Type::Tiny::Union;
"Type::Tiny::Union"->new(type_constraints => \@tc)
},
q(&) => sub {
my @tc = _swap @_;
- if (!_FIXED_PRECEDENCE && !blessed $tc[0] && ref $tc[0] eq 'ARRAY') {
- require Type::Tiny::_HalfOp;
- return "Type::Tiny::_HalfOp"->new('&', @tc);
+ if (!_FIXED_PRECEDENCE && $_[2]) {
+ if (blessed $tc[0]) {
+ if (blessed $tc[0] eq "Type::Tiny::_HalfOp") {
+ my $type = $tc[0]->{type};
+ my $params = $tc[0]->{params};
+ my $op = $tc[0]->{op};
+ require Type::Tiny::Intersection;
+ $tc[1] = "Type::Tiny::Intersection"->new(type_constraints => [$type, $tc[1]]);
+ Type::Tiny::_HalfOp->new($op, @tc);
+ return $tc[0];
+ }
+ }
+ elsif (ref $tc[0] eq 'ARRAY') {
+ require Type::Tiny::_HalfOp;
+ return "Type::Tiny::_HalfOp"->new('&', @tc);
+ }
}
require Type::Tiny::Intersection;
"Type::Tiny::Intersection"->new(type_constraints => \@tc)
--
2.12.2