Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Valid coercions reported as invalid if unrelated data fails #81

Open
Ovid opened this issue Sep 7, 2021 · 1 comment
Open

Valid coercions reported as invalid if unrelated data fails #81

Ovid opened this issue Sep 7, 2021 · 1 comment
Milestone

Comments

@Ovid
Copy link

Ovid commented Sep 7, 2021

I'm assuming I'm doing something horribly wrong, but here's a tiny type library (I've tried to pare it down to a minimal test case). Note that the YAMLBool type coerces true and false to 1 and 0, respectively:

package MyTypes {
    use Type::Library -base, -declare => qw(
      YAMLBool
    );
    use Type::Params 'compile';
    use Type::Utils -all;
    use Types::Standard qw(Bool Enum Dict Optional HashRef);

    our @EXPORT_OK = 'compile';

    BEGIN {
        extends qw(
          Types::Standard
          Types::Common::Numeric
          Types::Common::String
        );
    }
    declare '_TrueFalse', as Enum [qw/true false/];
    declare 'YAMLBool',   as Bool;
    coerce 'YAMLBool',
      from '_TrueFalse', via { 'true' eq $_ ? 1 : 0 };
}

1;

And here's a program that succeeds:

use 5.26.0;
use warnings;
use lib '.';
use MyTypes qw/Dict YAMLBool Optional HashRef compile/;

my $check = compile(
    Dict [
        maybe_true    => YAMLBool,
        not_a_hashref => Optional [HashRef],
    ]
);

my $minimal = {
    maybe_true    => 'true',
    not_a_hashref => {},
};

$check->($minimal);

But as soon as I change the not_a_hashref value to a string, I get the following error:

Reference {"maybe_true" => "true","not_a_hashref" => "asdf"} did not pass type constraint "Dict[maybe_true=>YAMLBool,not_a_hashref=>Optional[HashRef]]" (in $_[0]) at fail.pl line 18
    Reference {"maybe_true" => "true","not_a_hashref" => "asdf"} did not pass type constraint "Dict[maybe_true=>YAMLBool,not_a_hashref=>Optional[HashRef]]" (in $_[0])
    "Dict[maybe_true=>YAMLBool,not_a_hashref=>Optional[HashRef]]" constrains value at key "maybe_true" of hash with "YAMLBool"
    "YAMLBool" is a subtype of "Bool"
    Value "true" did not pass type constraint "Bool" (in $_[0]->{"maybe_true"})
    "Bool" is defined as: (!ref $_ and (!defined $_ or $_ eq q() or $_ eq '0' or $_ eq '1'))

So we see the coercion is valid. However, as soon as I change something other than the coerced value to an invalid state, the coercion doesn't happen and this otherwise valid value is reported as being the source of the problem. The actual type I compiled was about 40 lines long, so this was rather hard to chase down.

  • Types::Standard version 1.012001
  • Perl 5.26.2

I've also had this happen on Linux boxes with newer Perls and older versions of Types::Standard (1.010006), so it appears that I can reliably produce it.

@tobyink
Copy link
Owner

tobyink commented Sep 21, 2021

Coercions are treated as atomic, so either the entire coercion succeeds or the entire coercion fails.

Once the failure occurs, the error is reported against the pre-coerced value. I am pretty sure the same would happen with Moose attributes using Moose's built in type constraints, though I haven't checked.

I agree it's a counter-intuitive message though, so I'll see if there are any ways it can be improved.

@tobyink tobyink added this to the bluesky milestone Jun 6, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants