Subject: | a Dict with optional values and custom coercions can fail to validate |
If a Dict has some optional elements, and some non-optional ones, and some of them have non-inlineable coercions, it may randomly fail to validate.
The issue is that C<is_strictly_a_type_of> will return either a true value, or the empty list. Since it's used in a C<map> to build the C<%is_optional> hash, that empty list messes up the hash.
The attached patch provides a fix and a test case.
Subject: | type-tiny-dict-optional-coerce.patch |
diff --git i/lib/Types/Standard/Dict.pm w/lib/Types/Standard/Dict.pm
index 8657fd3..4bec45f 100644
--- i/lib/Types/Standard/Dict.pm
+++ w/lib/Types/Standard/Dict.pm
@@ -247,8 +247,8 @@ sub __coercion_generator
else
{
my %is_optional = map {
- ; $_ => $dict{$_}->is_strictly_a_type_of($_optional)
- } keys %dict;
+ ; $_ => !!$dict{$_}->is_strictly_a_type_of($_optional)
+ } sort keys %dict;
$C->add_type_coercions(
$parent => sub {
my $value = @_ ? $_[0] : $_;
diff --git i/t/20-unit/Types-Standard/deep-coercions.t w/t/20-unit/Types-Standard/deep-coercions.t
index b28b30e..080abe7 100644
--- i/t/20-unit/Types-Standard/deep-coercions.t
+++ w/t/20-unit/Types-Standard/deep-coercions.t
@@ -365,6 +365,28 @@ DICT_PLUS_SLURPY: {
);
};
+DICT_PLUS_OPTIONAL: {
+ my $IntFromStr = declare IntFromStr => as Int;
+ coerce $IntFromStr, from Str, sub { length($_) };
+ $IntFromStr->coercion->freeze;
+
+ my $Dict1 = Dict[ a => $IntFromStr, b => Optional[Int], c => Optional[Int] ];
+ ok(
+ $Dict1->has_coercion && !$Dict1->coercion->can_be_inlined,
+ "$Dict1 has a non-inlinable coercion",
+ );
+ is_deeply(
+ $Dict1->coerce({ a => "Hello", b => 1, c => 2 }),
+ { a => 5, b => 1, c => 2 },
+ "Coercion (A) to $Dict1",
+ );
+ is_deeply(
+ $Dict1->coerce({ a => "Hello", b => 1 }),
+ { a => 5, b => 1 },
+ "Coercion (B) to $Dict1",
+ );
+};
+
TUPLE: {
my $IntFromStr = declare IntFromStr => as Int;
coerce $IntFromStr, from Str, q{ length($_) };