Subject: | Subtypes of union types have invalid behavior with is_a_type_of and is_subtype_of |
There's a bug in Moose::Meta::TypeConstraint that causes is_a_type_of and is_subtype_of to
return false negatives for subtypes of union types. For example, if I create a
subtype 'Ints', as 'Int|ArrayRef[Int]';
then an attribute
has 'foo' => (is => 'ro', isa => 'Ints');
if I do a
$self->meta->get_attrribute('foo')->type_constraint->is_a_type_of('Ref');
it returns false when it should return true.
I'm fairly certain the problem is that is_subtype_of is doing a $parent->equals when it should be
using $parent->is_a_type_of. I've attached a script that illustrates the problem as well as a
proposed patch.
I've seen this issue in Moose 1.09, 2.0007, and 2.0202 running on perl 5.10.0 on both Debian 5
and MacOS X 10.6.
Subject: | TypeConstraint.patch |
diff --git a/lib/Moose/Meta/TypeConstraint.pm b/lib/Moose/Meta/TypeConstraint.pm
index f66888d..5e2e10b 100644
--- a/lib/Moose/Meta/TypeConstraint.pm
+++ b/lib/Moose/Meta/TypeConstraint.pm
@@ -288,7 +288,7 @@ sub is_subtype_of {
my $current = $self;
while (my $parent = $current->parent) {
- return 1 if $parent->equals($type);
+ return 1 if $parent->is_a_type_of($type);
$current = $parent;
}
Subject: | moosebug.pl |
#!/usr/bin/perl
# declare a custom subtype of a union
package MooseBug::Type;
use Moose::Util::TypeConstraints;
subtype 'Ints',
as 'Int|ArrayRef[Int]';
##################################################
# simple class
package MooseBug::Class;
use Moose;
has 'foo' => (is => 'ro', isa => 'Int|ArrayRef[Int]', default => 1);
has 'bar' => (is => 'ro', isa => 'Ints', default => 1);
##################################################
package main;
my $mb = MooseBug::Class->new();
my $meta = $mb->meta;
foreach my $attr ($meta->get_all_attributes) {
my $tc = $attr->type_constraint;
# both foo and bar should be a type of Ref
if ($tc->is_a_type_of('Ref')) {
print $attr->name . " is a ref type\n";
} else {
print $attr->name . " is NOT a ref type\n";
}
if ($tc->has_parent) {
print $attr->name . " has parent\n";
if ($tc->parent->is_a_type_of('Ref')) {
print $attr->name . "'s PARENT IS a ref type\n";
}
}
}