File Coverage

blib/lib/Dios/Types.pm
Criterion Covered Total %
statement 545 651 83.7
branch 226 310 72.9
condition 113 198 57.0
subroutine 71 85 83.5
pod 2 2 100.0
total 957 1246 76.8


line stmt bran cond sub pod time code
1             package Dios::Types;
2             our $VERSION = '0.000001';
3              
4 60     60   790097 use 5.014; use warnings;
  60     60   224  
  60         450  
  60         4136  
  60         3767  
5 60     60   476 use Carp;
  60         228  
  60         6210  
6 60     60   456 use Scalar::Util qw< reftype blessed looks_like_number openhandle >;
  60         127  
  60         8859  
7 60     60   50411 use overload;
  60         129351  
  60         501  
8 60     60   36618 use Sub::Uplevel;
  60         88265  
  60         469  
9              
10             $Carp::CarpInternal{'Dios::Types'}=1;
11              
12             ### IF KEYWORDS {
13 60     60   72083 use Keyword::Declare;
  60         11310986  
  60         806  
14              
15             ### IF KEYWORDS }
16              
17             my %exportable = ( validate => 1, validator_for => 1 );
18 0         0 sub import {
19              
20             # Throw away the package name...
21 63     63   866 shift @_;
22              
23             # Cycle through each SUB => AS pair...
24 63         549 while (my ($exported, $export_as) = splice(@_, 0, 2)) {
25             # If it's not a rename, don't change the name...
26 4 50 66     25 if ($export_as && $exportable{$export_as}) {
27 0         0 unshift @_, $export_as;
28 0         0 undef $export_as;
29             }
30              
31             # If it's not exported, don't export it...
32 4 50       16 croak "Can't export $exported" if !$exportable{$exported};
33              
34             # Unrenamed exports are exported under their own names...
35 4   66     22 $export_as //= $exported;
36              
37             # Do the export...
38 60     60   27873 no strict 'refs';
  60         144  
  60         14130  
39 4         7 *{caller.'::'.$export_as} = \&{$exported};
  4         22  
  4         16  
40             }
41              
42             ### IF KEYWORDS {
43 63         270  
44 60     60   4203778 keytype TypeSpec is /
45             (?&PerlIdentifier) (?: \[ (?>(?&PPR_balanced_squares)) \])?+
46             (?:
47             (?&PerlOWS) [&|] (?&PerlOWS)
48             (?&PerlIdentifier) (?: \[ (?>(?&PPR_balanced_squares)) \])?+
49             )*+
50             /x;
51 63         105  
52 60     60   4231661 keytype TypeParams is / \[ (?>(?&PPR_balanced_squares)) \] /x;
53              
54 63         133 # Create a new subtype of a known type, adding a constraint...
55 0 50 50 5   0 keyword subtype (
  0         0  
  0         0  
  63         381  
  5         1210051  
  5         15  
  5         14  
56 0         0 Ident $new_type,
  63         2653  
  5         16  
57 0         0 TypeParams $new_type_params = q{},
  5         187  
58             'of',
59 0         0 TypeSpec $known_type,
  0         0  
  5         214  
  5         16  
60 0         0 'where',
  5         16  
61 0         0 Block $constraint
  5         139  
62             ) {
63 0         0 my $subtype_defn
  0         0  
  0         0  
  5         139  
  5         12  
  5         156  
64 0         0 = qq{Dios::Types::_define_subtype('$new_type', '$new_type_params', 'Is', '[$known_type]', sub $constraint) };
  5         13  
65 0         0 qq{if (((caller 0)[3]//q{}) =~ /\\b(?:un)?import\\Z/) { $subtype_defn }; BEGIN{ $subtype_defn }};
  5         134  
66             }
67 0         0  
  0         0  
  0         0  
  5         293  
  5         10  
  5         32  
68 0         0  
  5         30  
69 0         0 # Alias a new subtype to a known type...
  5         193  
  63         1920  
70 0 50 50 4   0 keyword subtype (
  0         0  
  0         0  
  63         298  
  4         893723  
  4         9  
  4         10  
71 0         0 Ident $new_type,
  0         0  
  5         135  
  63         1801  
  4         13  
72 0         0 TypeParams $new_type_params = q{},
  0         0  
  5         98  
  4         117  
73             'of',
74 0         0 TypeSpec $known_type,
  0         0  
  0         0  
  5         314  
  4         166  
  4         32  
75 60         551 ) {
  0         0  
  63         802  
  4         13  
76 0         0 my $subtype_defn
  63         3902  
  4         127  
77 60     60   4200145 = qq{Dios::Types::_define_subtype('$new_type', '$new_type_params', 'Is', '[$known_type]') };
78 0         0 qq{if (((caller 0)[3]//q{}) =~ /\\b(?:un)?import\\Z/) { $subtype_defn }; BEGIN{ $subtype_defn }};
  0         0  
  0         0  
  4         99  
  4         10  
  4         8  
79 0         0 }
  4         12  
80 0         0  
  4         137  
81             ### IF KEYWORDS }
82 0         0  
  4         274  
83 0         0 }
  4         235  
84              
85 0         0 my @user_defined_type;
  4         95  
86 60         559  
  63         612  
87 63         2590 ### IF KEYWORDS {
88 60     60   4559609  
89             sub _define_subtype {
90 11     11   3605 my ($new_typename, $new_type_params, $old_typename, $old_type_params, $constraint) = @_;
91 11   66 10   127 $constraint //= sub{1};
  10         30  
92              
93 11   50     66 local $Dios::Types::lexical_hints = (caller 0)[10] // {};
94              
95             # Reassemble the complete base type...
96 11         428 $old_typename .= $old_type_params;
97              
98             # We are building a sub that builds type handlers...
99 11         23 my $new_type_handler_generator;
100              
101             # The simple case (where the new type is not parameterized)...
102 11 100       44 if (!length($new_type_params)) {
103 9         37 my $old_type_handler = _build_handler_for($old_typename);
104              
105             $new_type_handler_generator = sub {
106             return sub {
107 21         68 my $okay = $old_type_handler->($_[0]);
108 21 100       82 return _error_near($_[0], $new_typename, $okay) if !$okay;
109 17 100       81 return _error_near($_[0], $new_typename ) if !$constraint->(local $_ = $_[0]);
110 13         177 return 1;
111             }
112 9     21   53 };
  21         145  
113             }
114              
115             # The more complex case, where the new type has parameters...
116             else {
117             # Extract the new parameter names...
118 2         29 my @new_type_param_names = split /\s*,\s*/, $new_type_params =~ s{\A\[\s*+|\s*+\]\Z}{}grx;
119              
120             $new_type_handler_generator = sub {
121 10     10   22 my ($typename) = @_;
122 10         135 my @params = split /\s*,\s*/, $typename =~ s{\A \w++ \[ \s*+ | \s*+ \] \Z}{}grx;
123 10         29 my $substituted_typename = $old_typename;
124 10         59 for my $n (0..$#params) {
125 12         168 $substituted_typename =~ s{$new_type_param_names[$n]}{$params[$n]}gxms;
126             }
127              
128 10         43 my $old_type_handler
129             = _build_handler_for($substituted_typename,
130             "generated by parameterized subtype: $typename\n");
131              
132             return sub {
133 9         26 my $okay = $old_type_handler->($_[0]);
134 9 100       24 return _error_near($_[0], $typename, $okay) if !$okay;
135 7 100       14 if (! eval{ local $SIG{__WARN__} = sub{}; $constraint->(local $_ = $_[0]) }) {
  7         60  
  7         34  
136 3         39 my $constraint_desc = _describe_constraint($_[0], undef, $constraint, $@);
137 3         26 return _error_near(
138             $_[0], qq{Value ($_[0]) did not satisfy the constraint: $constraint_desc\n }
139             );
140             }
141 4         165 return 1;
142             }
143 2         20 };
  9         71  
144             }
145              
146 11         130 $^H{"Dios::Types subtype=$new_typename"} = @user_defined_type;
147 11         7250 push @user_defined_type, $new_type_handler_generator;
148             }
149              
150             ### IF KEYWORDS }
151              
152             sub _error_near ($$;$) {
153 98     98   406 my ($where, $what, $previous_errors) = @_;
154              
155 0         0 { package Dios::Types::Error;
156 60     60   60598 use overload 'bool' => sub{0}, fallback => 1;
  60     209   145  
  60         921  
  209         827  
157             sub msg {
158 0     0   0 my $self = shift;
159 0 0       0 return $self->[0] ne $self->[-1] ? "$self->[-1]\n(because $self->[0])" : $self->[0];
160             }
161             }
162              
163 98 100 100     209 $previous_errors = bless [], 'Dios::Types::Error' if (reftype($previous_errors)//q{}) ne 'ARRAY';
  98         740  
164 98         163 push @{$previous_errors}, _perl($where) . " isn't of type $what";
  98         610  
165              
166 98         26714 return $previous_errors;
167             }
168              
169             # Standard type checking...
170             my %handler_for = (
171             # Any Perl value or ref...
172             Slurpy => sub { 1 },
173             Any => sub { 1 },
174              
175             # Anything that is true or false (and that's everything in Perl!)
176             Bool => sub { 1 },
177              
178             # Anything defined, or not...
179             Def => sub { defined $_[0] },
180             Undef => sub { !defined $_[0] },
181             Void => sub { !defined $_[0] || ref $_[0] eq 'ARRAY' && !@{$_[0]} },
182              
183             # Values, references, and filehandles...
184             Value => sub { defined($_[0]) && !ref($_[0]) },
185             Ref => sub { ref $_[0] },
186             IO => \&openhandle,
187             Glob => sub { ref($_[0]) eq 'GLOB' },
188              
189             # An integer...
190             Int => sub {
191             # If it's an object, must have a warning-less numeric overloading...
192             if (ref($_[0])) {
193             # Normal references aren't integers...
194             return 0 if !blessed($_[0]);
195              
196             # Is there an overloading???
197             my $converter = overload::Method($_[0],'0+')
198             or return 0;
199              
200             # Does this object convert to a number without complaint???
201             my $warned;
202             local $SIG{__WARN__} = sub { $warned = 1 };
203             my $value = eval{ $converter->($_[0],undef,undef) }
204             // return 0;
205             return 0 if $warned;
206             return $value =~ m{\A \s*+ [+-]?+ (?: \d++ (\.0*+)?+ | inf(?:inity)?+ ) \s*+ \Z}ixms;
207             }
208              
209             # Value must be defined, non-reference, looks like an integer...
210             return defined($_[0])
211             && $_[0] =~ m{\A \s*+ [+-]?+ (?: \d++ (\.0*+)?+ | inf(?:inity)?+ ) \s*+ \Z}ixms;
212             },
213              
214             # A number
215             Num => sub {
216             return 0 if !defined $_[0] || lc($_[0]) eq 'nan';
217             &looks_like_number
218             },
219              
220             # A string, or stringifiable object, or array ref, or hash ref, that is empty...
221             Empty => sub {
222             my $value = shift;
223              
224             # Must be defined...
225             return 0 if !defined($value);
226              
227             # May be an empty array or hash...
228             my $reftype = ref($value);
229             return 1 if $reftype eq 'ARRAY' && !@{$value};
230             return 1 if $reftype eq 'HASH' && !keys %{$value};
231              
232             # May be an object that overloads stringification...
233             my $converter = $reftype && overload::Method($value, q{""});
234             return 1 if $converter && $converter->($value,undef,undef) eq q{};
235              
236             # Otherwise, has to be an empty string...
237             return $value eq q{};
238             },
239              
240             # A string, or stringifiable object...
241             Str => sub { defined($_[0]) && (ref($_[0]) ? defined overload::Method(shift,q{""}) : 1) },
242              
243             # A blessed object...
244             Obj => \&blessed,
245              
246             # Any loaded class (must have @ISA or $VERSION or at least one method defined)...
247             Class => sub {
248             return 0 if ref $_[0] || not $_[0];
249             my $stash = \%main::;
250             for my $partial_name (split /::/, $_[0]) {
251             return 0 if !exists $stash->{$partial_name.'::'};
252             $stash = $stash->{$partial_name.'::'};
253             }
254             return 1 if exists $stash->{'ISA'};
255             return 1 if exists $stash->{'VERSION'};
256             for my $globref (values %$stash) {
257             return 1 if *{$globref}{CODE};
258             }
259             return 0;
260             },
261             );
262              
263             # Built-in type checking...
264             for my $type (qw< SCALAR ARRAY HASH CODE GLOB >) {
265             $handler_for{ ucfirst(lc($type)) } = sub { (reftype($_[0]) // q{}) eq $type };
266             }
267             $handler_for{ Regex } = sub { (reftype($_[0]) // q{}) eq 'REGEXP' };
268             $handler_for{ List } = $handler_for{ Array };
269              
270             # Standard type hierrachy...
271             my %BASIC_NARROWER = (
272             Slurpy => { },
273             Any => { map {$_=>1} qw< Slurpy >},
274             Bool => { map {$_=>1} qw< Slurpy Any >},
275             Undef => { map {$_=>1} qw< Slurpy Any Bool >},
276             Def => { map {$_=>1} qw< Slurpy Any Bool >},
277             Value => { map {$_=>1} qw< Slurpy Any Bool Def >},
278             Num => { map {$_=>1} qw< Slurpy Any Bool Def Value Str >},
279             Int => { map {$_=>1} qw< Slurpy Any Bool Def Value Str Num >},
280             Str => { map {$_=>1} qw< Slurpy Any Bool Def Value >},
281             Class => { map {$_=>1} qw< Slurpy Any Bool Def Value Str >},
282             Empty => { map {$_=>1} qw< Slurpy Any Bool Def Value Str Ref Array List Hash >},
283             Ref => { map {$_=>1} qw< Slurpy Any Bool Def >},
284             Scalar => { map {$_=>1} qw< Slurpy Any Bool Def Ref >},
285             Regex => { map {$_=>1} qw< Slurpy Any Bool Def Ref >},
286             Code => { map {$_=>1} qw< Slurpy Any Bool Def Ref >},
287             Glob => { map {$_=>1} qw< Slurpy Any Bool Def Ref >},
288             IO => { map {$_=>1} qw< Slurpy Any Bool Def Ref >},
289             Obj => { map {$_=>1} qw< Slurpy Any Bool Def Ref >},
290             Array => { map {$_=>1} qw< Slurpy Any Bool Def Ref >},
291             List => { map {$_=>1} qw< Slurpy Any Bool Def Ref Array >},
292             Empty => { map {$_=>1} qw< Slurpy Any Bool Def Value Str Ref Array Hash List >},
293             Hash => { map {$_=>1} qw< Slurpy Any Bool Def Ref >},
294             Empty => { map {$_=>1} qw< Slurpy Any Bool Def Value Str Ref Array Hash List >},
295             );
296              
297             # This is the full typename syntax...
298             my $BASIC_TYPES = join('|', keys %handler_for);
299              
300             my $TYPED_OR_PURE_ETC = qr{ \s*+ ,? \s*+ \.\.\.}xms;
301             my $TYPED_ETC = qr{ \s*+ \.\.\.}xms;
302             my $PURE_ETC = qr{ \s*+ , \s*+ \.\.\.}xms;
303              
304             my $KEYED_TYPENAME = q{
305             \\s*
306             (?: ' (? [^'\\\\]*+ (?: \\\\. [^'\\\\]*+ )*+ ) '
307             | (? (?&IDENT) )
308             )
309             (? \\s* [?] )?
310             (?: \\s* => \\s* (? (?&CONJ_TYPENAME) ) )?
311             };
312              
313             my $TYPENAME_GRAMMAR = qr{
314              
315             (?
316             (? (?&QUAL_IDENT) )
317             | Is \[ (? \s*+ (?&DISJ_TYPENAME_BAR) \s*+ ) \]
318             | Is \[ (? \s*+ (?&CONJ_TYPENAME) \s*+ ) \]
319             | Not \[ (? \s*+ (?&DISJ_TYPENAME) \s*+ ) \]
320             | List \[ (? \s*+ (?&DISJ_TYPENAME) \s*+ ) \]
321             | Array \[ (? \s*+ (?&DISJ_TYPENAME) \s*+ ) \]
322             | Tuple \[ (? \s*+ (?&TUPLE_FORMAT) \s*+ ) \]
323             | Hash \[ (? \s*+ (?&DISJ_TYPENAME) (?: \s*+ => \s*+ (?&DISJ_TYPENAME) )?+ \s*+ ) \]
324             | Dict \[ (? \s*+ (?&DICT_FORMAT) \s*+ ) \]
325             | Ref \[ (? \s*+ (?&DISJ_TYPENAME) \s*+ ) \]
326             | Eq \[ (? \s*+ (?&STR_SPEC) \s*+ ) \]
327             | Match \[ (? \s*+ (?®EX_SPEC) \s*+ ) \]
328             | Can \[ (? \s*+ (?&OPT_QUAL_IDENT) \s*+ (?: , \s*+ (?&OPT_QUAL_IDENT) \s*+ )*+ ) \]
329             | Overloads \[ (? [^]]++ ) \]
330             | (? (?&BASIC) )
331             | (? (?!(?&BASIC)) (?&IDENT) (?: \s*+ \[ \s*+ (?&TYPE_LIST) \s*+ \] )?+ )
332             )
333              
334             (?(DEFINE)
335              
336             (? (?&CONJ_TYPENAME) (?: \s* [|] \s* (?&CONJ_TYPENAME) )++ )
337             (? (?&CONJ_TYPENAME) (?: \s* [|] \s* (?&CONJ_TYPENAME) )*+ )
338             (? (?&ATOM_TYPENAME) (?: \s* [&] \s* (?&ATOM_TYPENAME) )*+ )
339              
340             (?
341             (?&CONJ_TYPENAME) (?: \s* [|] \s* (?&CONJ_TYPENAME) )++
342             | (?&ATOM_TYPENAME) (?: \s* [&] \s* (?&ATOM_TYPENAME) )++
343             )
344              
345             (?
346             (?&TYPE_LIST) (?: \s*+ ,? \s*+ \.\.\. )?
347             )
348              
349             (?
350             (?&CONJ_TYPENAME) (?: \s*,\s* (?&CONJ_TYPENAME) )*+
351             )
352              
353             (?
354             (?&KEYED_TYPENAME) (?: \s*,\s* (?&KEYED_TYPENAME) )*+ $PURE_ETC?
355             )
356              
357             (?
358             $KEYED_TYPENAME
359             )
360              
361             (? (?: [^][\\]++ | \\[][\\] )*+ )
362              
363             (? (?: [^][\\]++ | \\\S | \[ \^? \]? [^]]*+ \] )*+ )
364              
365             (? \b (?: $BASIC_TYPES ) \b )
366              
367             (? (?&IDENT) (?: :: (?&IDENT) )++ )
368              
369             (? (?&IDENT) (?: :: (?&IDENT) )*+ )
370              
371             (? [^\W\d] \w*+ )
372             )
373             }xms;
374              
375             my $FROM_TYPENAME_GRAMMAR = qr{ (?(DEFINE) $TYPENAME_GRAMMAR ) }xms;
376              
377             my $IS_REF_TYPE
378             = qr/\A (?: List | Array | Hash | Code | Scalar | Regex | Tuple | Dict | Glob | IO | Obj ) \b/x;
379              
380             # Complex types are built on the fly...
381             sub _build_handler_for {
382 250     250   752 my ($type, $context, $level) = @_;
383              
384             # Reformat conjunctions and disjunctions to avoid left recursion...
385 250 100       40045 if ($type =~ m{\A \s*+ ((?&NON_ATOM_TYPENAME)) \s*+ \Z $FROM_TYPENAME_GRAMMAR }xms) {
386 18         118 $type = "Is[$1]";
387             }
388              
389             # Parse the type specification...
390 250 50       26054 $type =~ m{\A \s*+ $TYPENAME_GRAMMAR \s*+ \Z }xms
    100          
391             or croak "Incomprehensible type name: $type\n",
392             (defined $context ? $context : q{});
393              
394 249         4885 my %type_is = %+;
395              
396             # Conjunction handlers test each component type and fail if any fails...
397 249 100       1102 if ( exists $type_is{conj} ) { my @types = grep {defined} $type_is{conj} =~ m{ ((?&ATOM_TYPENAME))
  22         7890  
  972         2037  
398             $FROM_TYPENAME_GRAMMAR
399             }gxms;
400 22         287 my @handlers = map {_build_handler_for($_)} @types;
  27         261  
401             return sub {
402 34     34   84 for (@handlers) {
403 39         145 my $okay = $_->($_[0]);
404 39 100       131 return _error_near($_[0], join(' or ', @types), $okay)
405             if !$okay;
406             }
407 27         59 return 1;
408             }
409 22         153 }
410              
411             # Disjunction handlers test each component type and fail if all of them fail...
412 227 100       582 if ( exists $type_is{disj} ) { my @types = grep {defined} $type_is{disj} =~ m{ ((?&CONJ_TYPENAME))
  14         14891  
  1044         1690  
413             $FROM_TYPENAME_GRAMMAR
414             }gxms;
415 14         441 my @handlers = map {_build_handler_for($_)} @types;
  29         165  
416             return sub {
417 25     25   96 for (@handlers) {
418 43 100       158 return 1 if $_->($_[0]);
419             }
420 3         21 return _error_near($_[0], join(' or ', @types));
421             }
422 14         163 }
423              
424             # Basic types, just use the built-in handler...
425 213 100       922 if ( exists $type_is{basic} ) { return $handler_for{$type_is{basic}}; }
  102         585  
426              
427             # User defined types match an object of that type...
428 111 100       415 if ( exists $type_is{user} ) { my $typename = $type_is{user};
  13         41  
429 13         71 my $root_name = $typename =~ s{\[.*}{}rxms;
430 13         115 my $idx = $Dios::Types::lexical_hints->{"Dios::Types subtype=$root_name"};
431             return sub {
432             # Is it user-defined???
433 33 100   33   93 if (defined $idx) {
434 31         74 for ($_[0]) {
435 31   66     122 return $user_defined_type[$idx]($typename)($_)
436             || _error_near($_[0], $typename);
437             }
438             }
439              
440 2   33     24 return blessed($_[0]) && $_[0]->isa($typename)
441             || _error_near($_[0], $typename);
442             }
443 13         189 }
444              
445             # Array[T] types require an array ref, whose every element is of type T...
446 98 100       291 if ( exists $type_is{array} ) { my $value_handler = _build_handler_for($type_is{array});
  31         419  
447             return sub {
448 75 100 100 75   378 return _error_near($_[0], "Array[$type_is{array}]")
449             if (reftype($_[0]) // q{}) ne 'ARRAY';
450              
451 73         120 for (@{$_[0]}) {
  73         235  
452 164 100       371 next if my $okay = $value_handler->($_);
453 21         102 return _error_near($_, $type_is{array}, $okay);
454             }
455              
456 52         277 return 1;
457             }
458 31         339 }
459              
460             # List[T] types require an array ref, whose every element is of type T...
461 67 100       239 if ( exists $type_is{list} ) { my $value_handler = _build_handler_for($type_is{list});
  3         23  
462             return sub {
463 4 100 100 4   39 return _error_near($_[0], "List[$type_is{list}]")
464             if (reftype($_[0]) // q{}) ne 'ARRAY';
465              
466 3         7 for (@{$_[0]}) {
  3         10  
467 7 50       20 next if my $okay = $value_handler->($_);
468 0         0 return _error_near($_, $type_is{list}, $okay);
469             }
470              
471 3         11 return 1;
472             }
473 3         28 }
474              
475 64 100       157 if ( exists $type_is{tuple} ) { my @types
476 72         126 = grep {defined}
477 1         1428 $type_is{tuple} =~ m{ ((?&CONJ_TYPENAME) | $TYPED_OR_PURE_ETC )
478             $FROM_TYPENAME_GRAMMAR
479             }gxms;
480             # Build type handlers for sequence...
481 1         45 my ($final_any, $final_handler);
482 1 50 33     67 if (@types > 1 && $types[-1] =~ /^$TYPED_ETC$/) {
    50 33        
483 0         0 pop @types;
484 0         0 $final_handler = _build_handler_for(pop @types);
485             }
486             elsif (@types > 0 && $types[-1] =~ /^$PURE_ETC$/) {
487 0         0 pop @types;
488 0         0 $final_any = 1;
489 0         0 $final_handler = _build_handler_for('Any');
490             }
491 1         6 my @value_handlers = map {_build_handler_for($_)} @types;
  2         7  
492              
493             return sub {
494 2     2   5 my $array_ref = shift;
495             # Tuples must be array refs the same length as their specifications...
496             return _error_near($array_ref, "Dict[$type_is{tuple}]")
497             if (reftype($array_ref) // q{}) ne 'ARRAY'
498 2 100 50     18 || !$final_handler && @{$array_ref} != @types;
  1   33     6  
      66        
499              
500             # The first N values must match the N types specified...
501 1         5 for my $n (0..$#types) {
502 2         7 my $okay = $value_handlers[$n]($array_ref->[$n]);
503 2 50       7 return _error_near($array_ref, "Dict[$type_is{tuple}]", $okay)
504             if !$okay;
505             }
506              
507             # Succeed at once if no etcetera to test, or it etcetera guaranteed...
508 1 50 33     7 return 1 if $final_any || @{$array_ref} == @types;
  1         8  
509              
510             # Any extra values must match the "et cetera" handler specified...
511 0         0 for my $n ($#types+1..$#{$array_ref}) {
  0         0  
512 0         0 my $okay = $final_handler->($array_ref->[$n]);
513 0 0       0 return _error_near($array_ref, "Dict[$type_is{tuple}]", $okay)
514             if !$okay;
515             }
516              
517 0         0 return 1;
518             }
519 1         28 }
520              
521             # Hash[T] and Hash[T=>T] types require a hash ref, whose every value is of type T...
522 63         357 my $HASH_KV_SPEC = qr{
523             \A
524             ((?&BalancedSquareBrackets))
525             (?: (=>) (.*) )?+
526             \Z
527              
528             (?(DEFINE)
529             (?
530             (?: [^][] | \[ (?&BalancedSquareBrackets) \] )*?
531             )
532             )
533             }xms;
534 63 100       187 if ( exists $type_is{hash} ) { my ($type_k, $arrow, $type_v) = $type_is{hash} =~ $HASH_KV_SPEC;
  21         327  
535             # Only value type specified...
536 21 100       105 if (!$arrow) {
537 12         74 $type_k =~ s/\A\s+|\s+\Z//g;
538 12         75 my $value_handler = _build_handler_for($type_k);
539             return sub {
540 42 100 100 42   283 return _error_near($_[0], "Hash[$type_is{hash}]")
541             if (reftype($_[0]) // q{}) ne 'HASH';
542              
543 38         83 for (values %{$_[0]}) {
  38         153  
544 39         165 my $okay = $value_handler->($_);
545 39 100       136 return _error_near($_, $type_is{hash}, $okay)
546             if !$okay;
547             }
548              
549 34         213 return 1;
550             }
551 12         133 }
552             # Both key and value type specified...
553             else {
554 9         51 $type_k =~ s/\A\s+|\s+\Z//g;
555 9         38 $type_v =~ s/\A\s+|\s+\Z//g;
556 9         30 my $key_handler = _build_handler_for($type_k);
557 9         17 my $value_handler = _build_handler_for($type_v);
558             return sub {
559 18 50 50 18   94 return _error_near($_[0], "Hash[$type_is{hash}]")
560             if (reftype($_[0]) // q{}) ne 'HASH';
561              
562 18         23 for (keys %{$_[0]}) {
  18         56  
563 38         63 my $okay = $key_handler->($_);
564 38 100       98 return _error_near($_, $type_is{hash}, $okay)
565             if !$okay;
566             }
567              
568 11         18 for (values %{$_[0]}) {
  11         26  
569 27         50 my $okay = $value_handler->($_);
570 27 100       56 return _error_near($_, $type_is{hash}, $okay)
571             if !$okay;
572             }
573              
574 9         22 return 1;
575             }
576 9         95 }
577             }
578              
579             # Dict[ k => T, k => T, ... ] requires a hash key, with the specified keys type-matched too...
580 42 100       172 if ( exists $type_is{dict} ) { my (%handler_for, @required_keys, $extra_keys_allowed);
  2         5  
581 2         1504 while ($type_is{dict} =~ m{ (? $KEYED_TYPENAME)|(? $PURE_ETC)
582             $FROM_TYPENAME_GRAMMAR}gxms
583             ) {
584             # Create a type checker for each specified key (once!)...
585 6 100       83 if (exists $+{keyed}) {
586 4         53 my ($key, $valtype, $optional) = @+{qw< key valtype optional >};
587             croak qq{Two type specifications for key '$key' },
588             qq{in Dict[$type_is{dict}]}
589 4 50       20 if exists $handler_for{$key};
590 4   50     77 $handler_for{$key}
591             = _build_handler_for($valtype // 'Any');
592 4 50       66 push @required_keys, $key if !$optional;
593             }
594             # And remember whether other keys are allowed...
595             else {
596 2         14 $extra_keys_allowed = 1;
597             }
598             }
599              
600             # Build type handlers for sequence...
601             return sub {
602 4     4   10 my $hash_ref = shift;
603             # It has to be a hash reference...
604 4 100 50     24 return _error_near($hash_ref, "Dict[$type_is{dict}]")
605             if (reftype($hash_ref) // q{}) ne 'HASH';
606              
607             # With all the required keys...
608 3         8 for my $key (@required_keys) {
609             return _error_near($_, "Dict[$type_is{dict}]")
610 5 100       22 if !exists $hash_ref->{$key};
611             }
612              
613             # Each entry has to have a permitted key and the right type of value...
614 2         3 while (my ($key, $value) = each %{$hash_ref}) {
  10         30  
615 8 100       19 if (exists $handler_for{$key}) {
616 4         11 my $okay = $handler_for{$key}($value);
617 4 50       12 return _error_near($_, "Dict[$type_is{dict}]", $okay)
618             if !$okay;
619             }
620             else {
621 4 50       10 return _error_near($_, "Dict[$type_is{dict}]")
622             if !$extra_keys_allowed;
623             }
624             }
625              
626 2         6 return 1;
627             }
628 2         26 }
629              
630             # Ref[T] types require a reference, whose dereferenced value is of type T...
631             # but with special magic if T is already itself a reference type
632 40 100       97 if ( exists $type_is{ref} ) { my $value_handler = _build_handler_for($type_is{ref});
  14         56  
633 14 100       106 return $value_handler if $type_is{ref} =~ $IS_REF_TYPE;
634             return sub {
635 26     26   85 my $reftype = reftype($_[0]);
636 26 50 66     155 return _error_near($_[0], "Ref[$type_is{ref}]")
      33        
637             if !$reftype || $reftype ne 'REF' && $reftype ne 'SCALAR';
638 26         64 my $okay = $value_handler->(${$_[0]});
  26         97  
639 26 100       110 return $okay ? 1 : _error_near($_[0], "Ref[$type_is{ref}]", $okay)
640             }
641 10         124 }
642              
643             # Not[T] negates the usual test...
644 26 100       79 if ( exists $type_is{not} ) { my $negated_handler = _build_handler_for($type_is{not});
  2         6  
645             return sub {
646 12     12   23 my $not_okay = $negated_handler->($_[0]);
647 12 100       29 return _error_near($_[0], "Not[$type_is{not}]", $not_okay)
648             if $not_okay;
649 10         15 return 1;
650             }
651 2         16 }
652              
653             # Eq[S] types require a stringifiable, that matches 'S'...
654 24 50       73 if ( exists $type_is{eq} ) { my $str = eval "q[$type_is{eq}]";
  0         0  
655             return sub {
656             return 1 if defined $_[0]
657             && (!blessed($_[0]) || overload::Method($_[0],q{""}))
658 0 0 0 0   0 && eval{ "$_[0]" eq $str };
  0   0     0  
      0        
659 0         0 return _error_near($_[0], "Eq[$type_is{eq}]");
660             }
661 0         0 }
662              
663             # Match[R] types require a stringifiable, that matches /R/x...
664 24 100       54 if ( exists $type_is{match} ) {
665 6         13 my $regex = eval { qr{$type_is{match}}x };
  6         213  
666 6 50       42 croak "Invalid regex syntax in Match[$type_is{match}]:\n $@" if $@;
667             return sub {
668             return 1 if defined $_[0]
669             && (!blessed($_[0]) || overload::Method($_[0],q{""}))
670 24 100 33 24   128 && eval{ "$_[0]" =~ $regex };
  24   33     164  
      66        
671 4         33 return _error_near($_[0], "Match[$type_is{match}]");
672             }
673 6         57 }
674              
675             # Can[M] types require a class or object with the specified methods...
676 18 100       42 if ( exists $type_is{can} ) { my @method_names = split q{,}, $type_is{can};
  8         27  
677 8         143 s{\s*}{}g for @method_names;
678             return sub {
679 8 50 33 8   27 return 0 if !blessed($_[0]) && !$handler_for{Class}($_[0]);
680 8         11 for my $method_name (@method_names) {
681             return _error_near($_[0], "Can[$type_is{can}]")
682 12 100       16 if !eval{ $_[0]->can($method_name) };
  12         79  
683             }
684 6         10 return 1
685             }
686 8         66 }
687              
688             # Overloads[O] types require a class or object with the specified overloads...
689 10 50       22 if ( exists $type_is{overloads} ) { my @ops = split q{,}, $type_is{overloads};
  10         38  
690 10         126 s{\s*}{}g for @ops;
691             return sub {
692 60     60   346847 use overload;
  60         336  
  60         541  
693 10 50 33 10   46 return 0 if !blessed($_[0]) && !$handler_for{Class}($_[0]);
694 10         18 for my $op (@ops) {
695 24 100       434 return _error_near($_[0], "Can[$type_is{overloads}]")
696             if !overload::Method($_[0], $op);
697             }
698 6         225 return 1
699             }
700 10         98 }
701              
702 0         0 die "Internal error: could not generate a type from '$type'. Please report this as a bug."
703             }
704              
705             sub _complete_desc {
706 558     558   1364 my ($desc, $value) = @_;
707 558   100     2545 $desc //= q{Value (%s)};
708 558         1328 my $value_perl = _perl($value);
709 558         92558 return $desc =~ s{(?
710             }
711              
712             sub validate {
713 757     757 1 2320978 my ($typename, $value) = splice(@_,0,2);
714 757         1454 my ($value_desc, @constraints);
715 757         1538 for my $arg (@_) {
716             # Subs are undescribed constraints...
717 682 100       2135 if (ref($arg) eq 'CODE') {
    50          
718 60         130 push @constraints, $arg;
719             }
720              
721             # Anything else is part of the value description...
722             elsif (defined $arg) {
723 622         1557 $value_desc .= $arg;
724             }
725             }
726              
727             # What's happening in the caller's lexical scope???
728 757   50     2143 local $Dios::Types::lexical_hints = (caller 0)[10] // {};
729              
730             # All but the basic handlers are built late, as needed...
731 757 100       18661 if (!exists $handler_for{$typename}) {
732 44 50       152 $handler_for{$typename} = _build_handler_for($typename)
733             or die 'Internal error: unable to build type checker. Please report this as a bug.';
734             }
735              
736             # Either the type matches or we die...
737 757 100       2323 if (!$handler_for{$typename}($value)) {
738 314         952 $value_desc = _complete_desc($value_desc, $value);
739 314 50       5364 croak qq{\u$value_desc}
740             . ($value_desc =~ /\s$/ ? q{} : q{ })
741             . qq{is not of type $typename};
742             }
743 442 100       2231 return 1 if !@constraints;
744              
745             # Either every constraint matches or we die...
746 58         93 for my $test (@constraints) {
747 58         74 local $@;
748              
749             # If it fails to match...
750 58 100   0   92 if (! eval{ local $SIG{__WARN__} = sub{}; $test->(local $_ = $value) }) {
  58         366  
  58         177  
751 33         309 $value_desc = _complete_desc($value_desc, $value);
752 33         97 my $constraint_desc = _describe_constraint($value, $value_desc, $test, $@);
753 33 50       652 croak qq{\u$value_desc}
754             . ($value_desc =~ /\s$/ ? q{} : q{ })
755             . qq{did not satisfy the constraint: $constraint_desc\n }
756             }
757             }
758              
759 25         288 return 1;
760             }
761              
762             sub _up_validate {
763 118     118   4759 my ($uplevels, $typename, $value) = splice(@_,0,3);
764 118         209 my ($value_desc, @constraints);
765 118         383 for my $arg (@_) {
766             # Subs are undescribed constraints...
767 166 100       640 if (ref($arg) eq 'CODE') {
    50          
768 50         107 push @constraints, $arg;
769             }
770              
771             # Anything else is part of the value description...
772             elsif (defined $arg) {
773 116         318 $value_desc .= $arg;
774             }
775             }
776              
777             # What's happening in the caller's lexical scope???
778 118   100     357 local $Dios::Types::lexical_hints = (caller $uplevels)[10] // {};
779              
780             # All but the basic handlers are built late, as needed...
781 118 100       3431 if (!exists $handler_for{$typename}) {
782 2 50       7 $handler_for{$typename} = _build_handler_for($typename)
783             or die 'Internal error: unable to build type checker. Please report this as a bug.';
784             }
785              
786             # Either the type matches or we die...
787 118 100       381 if (!$handler_for{$typename}($value)) {
788 13         43 $value_desc = _complete_desc($value_desc, $value);
789 13 100       332 croak qq{\u$value_desc}
790             . ($value_desc =~ /\s$/ ? q{} : q{ })
791             . qq{is not of type $typename};
792             }
793 105 100       562 return 1 if !@constraints;
794              
795             # Either every constraint matches or we die...
796 42         87 for my $test (@constraints) {
797 42         68 local $@;
798              
799             # If it fails to match...
800 42 100   0   89 if (! eval{ local $SIG{__WARN__} = sub{}; $test->(local $_ = $value) }) {
  42         376  
  42         153  
801 4         41 $value_desc = _complete_desc($value_desc, $value);
802 4         19 my $constraint_desc = _describe_constraint($value, $value_desc, $test, $@);
803 4 50       109 croak qq{\u$value_desc}
804             . ($value_desc =~ /\s$/ ? q{} : q{ })
805             . qq{did not satisfy the constraint: $constraint_desc\n }
806             }
807             }
808              
809 38         306 return 1;
810             }
811              
812             sub validator_for {
813 281     281 1 2708437 my $typename = shift;
814 281         596 my ($value_desc, @constraints);
815 281         1269 for my $arg (@_) {
816             # Subs are undescribed constraints...
817 168 100       1757 if (ref($arg) eq 'CODE') {
    50          
818 1         3 push @constraints, $arg;
819             }
820              
821             # Anything else is part of the value description...
822             elsif (defined $arg) {
823 167         558 $value_desc .= $arg;
824             }
825             }
826              
827             # What's happening in the caller's lexical scope???
828 281   50     988 local $Dios::Types::lexical_hints = (caller 0)[10] // {};
829              
830             # All but the basic handlers are built late, as needed...
831 281 100       8819 if (!exists $handler_for{$typename}) {
832 43 50       182 $handler_for{$typename} = _build_handler_for($typename)
833             or die 'Internal error: unable to build type checker. Please report this as a bug.';
834             }
835              
836             # Return the smallest sub that validates the type...
837 281         534 my $handler = $handler_for{$typename};
838              
839 281 50 66     1136 return $handler if !$value_desc && !@constraints;
840              
841             return sub {
842 198 100   198   113108 return 1 if $handler->($_[0]);
843              
844 152         548 my $desc = _complete_desc($value_desc, $_[0]);
845 152 50       2499 croak qq{\u$desc}
846             . ($desc =~ /\s$/ ? q{} : q{ })
847             . qq{is not of type $typename};
848 167 100       1610 } if !@constraints;
849              
850             return sub {
851             # Either the type matches or we die...
852 10 100   10   45660 if (!$handler_for{$typename}($_[0])) {
853 2         13 my $desc = _complete_desc($value_desc, $_[0]);
854 2 50       51 croak qq{\u$desc}
855             . ($desc =~ /\s$/ ? q{} : q{ })
856             . qq{is not of type $typename};
857             }
858 8 50       31 return 1 if !@constraints;
859              
860             # Either every constraint matches or we die...
861 8         20 for my $test (@constraints) {
862 8         13 local $@;
863              
864             # If it fails to match...
865 8 50       14 if (! eval{ local $SIG{__WARN__} = sub{}; $test->(local $_ = $_[0]) }) {
  8         76  
  8         45  
866 0         0 my $desc = _complete_desc($value_desc, $_[0]);
867 0         0 my $constraint_desc = _describe_constraint($_[0], $desc, $test, $@);
868 0 0       0 croak qq{\u$desc}
869             . ($desc =~ /\s$/ ? q{} : q{ })
870             . qq{did not satisfy the constraint: $constraint_desc\n }
871             }
872             }
873              
874 8         97 return 1;
875             }
876 1         11 }
877              
878             package Dios::Types::TypedArray {
879             our @CARP_NOT = ('Dios::Types');
880 8     8   46 sub TIEARRAY { bless [$_[1]], $_[0] }
881 64     64   28364 sub FETCHSIZE { @{$_[0]} - 1 }
  64         169  
882 0     0   0 sub STORESIZE { $#{$_[0]} = $_[1] + 1 }
  0         0  
883 38     38   2153 sub STORE { my ($type, $desc, @constraint) = @{$_[0][0]};
  38         108  
884 38         130 Dios::Types::_up_validate(1, $type, $_[2], $desc, @constraint);
885 34         177 $_[0]->[$_[1]+1] = $_[2];
886             }
887 53     53   815 sub FETCH { $_[0]->[$_[1]+1] }
888 12     12   8124 sub CLEAR { @{$_[0]} = $_[0][0] }
  12         92  
889 0 0   0   0 sub POP { @{$_[0]} > 1 ? pop(@{$_[0]}) : undef }
  0         0  
  0         0  
890 0     0   0 sub PUSH { my $o = shift; push(@{$o}, @_) }
  0         0  
  0         0  
891 0     0   0 sub SHIFT { splice(@{$_[0]},1,1) }
  0         0  
892 0     0   0 sub UNSHIFT { my $o = shift; splice(@$o,1,0,@_) }
  0         0  
893 0     0   0 sub EXISTS { exists $_[0]->[$_[1]+1] }
894 0     0   0 sub DELETE { delete $_[0]->[$_[1]+1] }
895       12     sub EXTEND { }
896              
897             sub SPLICE
898             {
899 0     0   0 my $ob = shift;
900 0         0 my $sz = @{$ob} - 1;
  0         0  
901 0 0       0 my $off = @_ ? shift : 0;
902 0 0       0 $off += $sz if $off < 0;
903 0 0       0 my $len = @_ ? shift : $sz-$off;
904 0         0 return splice(@$ob,$off+1,$len,@_);
905             }
906             }
907              
908             package Dios::Types::TypedHash {
909             our @CARP_NOT = ('Dios::Types');
910 8     8   47 sub TIEHASH { bless [$_[1], {}], $_[0] }
911 24     24   1056 sub STORE { my ($type, $desc, @constraint) = @{$_[0][0]};
  24         76  
912 24         90 Dios::Types::_up_validate(1, $type, $_[2], $desc, @constraint);
913 22         129 $_[0][1]{$_[1]} = $_[2]
914             }
915 35     35   783 sub FETCH { $_[0][1]{$_[1]} }
916 16     16   13053 sub FIRSTKEY { my $a = scalar keys %{$_[0][1]}; each %{$_[0][1]} }
  16         69  
  16         33  
  16         158  
917 32     32   57 sub NEXTKEY { each %{$_[0][1]} }
  32         127  
918 34     34   615 sub EXISTS { exists $_[0][1]{$_[1]} }
919 0     0   0 sub DELETE { delete $_[0][1]{$_[1]} }
920 12     12   10632 sub CLEAR { %{$_[0][1]} = () }
  12         110  
921 0     0   0 sub SCALAR { scalar %{$_[0][1]} }
  0         0  
922             }
923              
924             sub _set_var_type {
925 51     51   571196 my ($type, $varref, $value_desc, @constraint) = @_;
926 51         128 my $vartype = ref $varref;
927              
928 51 100 100     341 if ($vartype ne 'ARRAY' && $vartype ne 'HASH') {
    100          
    50          
929             croak 'Typed attributes require the Variable::Magic module, which could not be loaded'
930 21 50       50 if !eval{ require Variable::Magic };
  21         254  
931              
932 21         276 Variable::Magic::cast( ${$varref}, Variable::Magic::wizard( set => sub {
933             # Code around awkward Object::Insideout behaviour...
934 42 100 100 42   65083 return if ((caller 3)[3]//"") eq 'Object::InsideOut::DESTROY';
935              
936             # Code around more awkward Object::Insideout behaviour...
937 60     60   198172 no warnings 'redefine';
  60         243  
  60         156908  
938 23         537 local *croak = *confess{CODE};
939 23 100       49 return if eval { _up_validate(+2, $type, ${$_[0]}, $value_desc, @constraint) };
  23         118  
  23         114  
940 4         2301 die $@ =~ s{\s+at .*}{}r
941             =~ s{[\h\S]*Dios.*}{}gr
942             =~ s{.*\(eval .*}{}gr
943             =~ s{\s*[\h\S]*called at}{ at}r
944             =~ s{.*called at.*}{}gr;
945 21         55 }));
946             }
947             elsif ($vartype eq 'ARRAY') {
948 15 100       30 return if tied @{$varref};
  15         103  
949 8         28 tie @{$varref}, 'Dios::Types::TypedArray', [$type, $value_desc, @constraint];
  8         104  
950             }
951             elsif ($vartype eq 'HASH') {
952 15 100       29 return if tied %{$varref};
  15         75  
953 8         16 tie %{$varref}, 'Dios::Types::TypedHash', [$type, $value_desc, @constraint];
  8         77  
954             }
955             else {
956 0         0 die 'Internal error: argument to _set_var_type() must be scalar, array ref, or hash ref';
957             }
958             }
959              
960             # Implement return-type checking...
961             sub _validate_return_type {
962              
963             # Type info is first arg (an arrayref), subroutine body is final arg (a sub ref)...
964 33     33   258873 my ($name, $type, $where) = @{shift()};
  33         97  
965 33   33 26   240 $where //= sub{1};
  26         168  
966 33         58 my $function = pop;
967              
968             # List return context...
969 33 100       98 if (wantarray) {
    100          
970             # Tidy up type...
971 1         10 $type =~ s{\A Void \| | \| Void \Z}{}xmsg;
972 1         8 my $void_warning = vec((caller 1)[9], $warnings::Offsets{'void'}, 1);
973 1 50 33     39 warn sprintf "Call to $name() not in void context at %s line %d\n", (caller 1)[1,2]
974             if $void_warning && $type eq 'Void';
975              
976             # Execute the subroutine body in (apparently) the right context...
977 1         6 my @retvals = uplevel 2, $function, @_;
978              
979             # Adapt the constraint to produce a more appropriate error message...
980             my $listwhere = sub {
981 1     1   2 for (@{shift()}) {
  1         4  
982 3 50       5 die _describe_constraint($_,undef,$where) if !$where->($_)
983             }
984 1         10 return 1;
985 1         583 };
986              
987             # Validate the return values...
988             eval {
989 1 50       6 if (@retvals == 1) {
990 0         0 _up_validate(+1,
991             $type, $retvals[0], $where,
992             "Return value (" . (_perl(@retvals)=~s/^\(|\)$//gr) . ") of call to $name()\n"
993             );
994             }
995             else {
996 1         6 undef;
997             }
998             }
999             //
1000 1   33     3 eval {
      50        
1001 1         5 _up_validate(+1,
1002             $type, \@retvals, $listwhere,
1003             "List of return values (" . (_perl(@retvals)=~s/^\(|\)$//gr) . ") of call to $name()\n"
1004             )
1005             }
1006              
1007             # ..or convert the error message to report from the correct line number...
1008 0         0 // die $@ =~ s{\s*+at \S+ line \d++.*+}{sprintf "\nat %s line %d\n", (caller 1)[1,2]}ser;
1009              
1010             # If the return values are valid, return them...
1011 1         15 return @retvals;
1012             }
1013              
1014             # Scalar context...
1015             elsif (defined wantarray) {
1016             # Tidy up type...
1017 30         93 $type =~ s{\A Void \| | \| Void \Z}{}xmsg;
1018 30         98 my $void_warning = vec((caller 1)[9], $warnings::Offsets{'void'}, 1);
1019 30 50 33     1102 warn sprintf "Call to $name() not in void context at %s line %d\n", (caller 1)[1,2]
1020             if $void_warning && $type eq 'Void';
1021              
1022             # Execute the subroutine body in (apparently) the right context...
1023 30         89 my $retval = uplevel 2, $function, @_;
1024              
1025             # Validate the return value...
1026 30   100     1305 eval {
1027 30         88 _up_validate(+1,
1028             $type, $retval, $where,
1029             "Scalar return value (" . _perl($retval) . ") of call to $name()\n"
1030             )
1031             }
1032             # ...or convert the error message to report from the correct line number...
1033 7         2610 // die $@ =~ s{\s*at \S+ line \d+.*}{sprintf "\nat %s line %d\n", (caller 1)[1,2]}er;
1034              
1035             # If the return value is valid, return it...
1036 23         145 return $retval;
1037             }
1038              
1039             # Void context...
1040             else {
1041             # Execute the subroutine body in (apparently) the right context...
1042 2         11 uplevel 2, $function, @_;
1043              
1044             # Warn about explicit return types in void context, unless return type implies void is okay...
1045 2         557 my $void_warning = vec((caller 1)[9], $warnings::Offsets{'void'}, 1);
1046             warn sprintf
1047             "Useless call to $name() with explicit return type $type\nin void context at %s line %d\n",
1048             (caller 1)[1,2]
1049 2 50 33     68 if $void_warning && !eval{ _up_validate(+1, $type, undef) };
  2         8  
1050              
1051             }
1052             }
1053              
1054              
1055              
1056              
1057             # Compare two types...
1058             sub _is_narrower {
1059 136     136   449 my ($type_a, $type_b, $unnormalized) = @_;
1060              
1061             # Short-circuit on identity...
1062 136 100       296 return 0 if $type_a eq $type_b;
1063              
1064             # Otherwise, normalize and decompose...
1065 110 100 100     6643 if (!$unnormalized && $type_a =~ m{\A (?: Ref ) \Z }xms) {
    50 66        
    100 100        
    50          
1066 24         56 $type_a = "Ref[Any]";
1067             }
1068             elsif (!$unnormalized && $type_a =~ m{\A (?: Array | List ) \Z }xms) {
1069 0         0 $type_a = "Ref[Array[Any]]";
1070             }
1071             elsif (!$unnormalized && $type_a eq 'Hash') {
1072 4         13 $type_a = "Ref[Hash[Any]]";
1073             }
1074             elsif ($type_a =~ m{\A \s*+ ((?&NON_ATOM_TYPENAME)) \s*+ \Z $FROM_TYPENAME_GRAMMAR }xms) {
1075 0         0 $type_a = "Is[$1]";
1076             }
1077 110         4274 $type_a =~ m{\A \s*+ $TYPENAME_GRAMMAR \s*+ \Z }xms; my %type_a_is = %+;
  110         1528  
1078              
1079 110 50 66     5464 if (!$unnormalized && $type_b =~ m{\A (?: Ref ) \Z }xms) {
    50 66        
    100 100        
    50          
1080 0         0 $type_b = "Ref[Any]";
1081             }
1082             elsif (!$unnormalized && $type_b =~ m{\A (?: Array | List ) \Z }xms) {
1083 0         0 $type_b = "Ref[Array[Any]]";
1084             }
1085             elsif (!$unnormalized && $type_b eq 'Hash') {
1086 20         40 $type_b = "Ref[Hash[Any]]";
1087             }
1088             elsif ($type_b =~ m{\A \s*+ ((?&NON_ATOM_TYPENAME)) \s*+ \Z $FROM_TYPENAME_GRAMMAR }xms) {
1089 0         0 $type_b = "Is[$1]";
1090             }
1091 110         4176 $type_b =~ m{\A \s*+ $TYPENAME_GRAMMAR \s*+ \Z }xms; my %type_b_is = %+;
  110         1361  
1092              
1093             # If both are basic types, use the standard comparisons...
1094 110 100 100     682 if (exists $type_a_is{basic} && exists $type_b_is{basic}) {
1095 62 100       337 return +1 if $BASIC_NARROWER{$type_b}->{$type_a};
1096 30 50       184 return -1 if $BASIC_NARROWER{$type_a}->{$type_b};
1097             }
1098              
1099             # If both are array or hash or reference types, use the standard comparisons on their element-types...
1100 48         99 for my $elem_type (qw< array hash ref >) {
1101 144 100 100     420 if (exists $type_a_is{$elem_type} && exists $type_b_is{$elem_type}) {
1102 16         142 return _is_narrower($type_a_is{$elem_type}, $type_b_is{$elem_type}, 'unnormalized');
1103             }
1104             }
1105              
1106             # If either type is parameterized, try the generic unparameterized version...
1107 32 50 66     268 if ($type_a =~ s{\A(?:List|Array|Hash|Ref|Match|Eq)\K\[.*}{}xms
1108             || $type_b =~ s{\A(?:List|Array|Hash|Ref|Match|Eq)\K\[.*}{}xms) {
1109 32 0 33     114 return -1 if $type_a =~ m{\A(?:Match|Eq)\Z} && $BASIC_NARROWER{Class}->{$type_b};
1110 32 0 33     98 return +1 if $type_b =~ m{\A(?:Match|Eq)\Z} && $BASIC_NARROWER{Class}->{$type_a};
1111 32         96 return _is_narrower($type_a, $type_b, 'unnormalized');
1112             }
1113              
1114             # If both are user-defined types, try the standard inheritance hierarchy rules...
1115 0 0 0     0 if (exists $type_a_is{user} && exists $type_b_is{user}) {
1116 0 0       0 return +1 if $type_b->isa($type_a);
1117 0 0       0 return -1 if $type_a->isa($type_b);
1118             }
1119              
1120             # Otherwise, unable to compare...
1121 0         0 return 0;
1122             }
1123              
1124             # Compare two type signatures (of equal length)...
1125             sub _cmp_signatures {
1126 46     46   108 my ($sig_a, $sig_b) = @_;
1127              
1128             # Extract named parameters of B...
1129 46         97 state %named_B_for;
1130             my $named_B =
1131 46 100 100     202 $named_B_for{$sig_b} //= { map { $_->{named} ? ($_->{named} => $_) : () } @{$sig_b} };
  34         174  
  18         50  
1132              
1133             # Track relative ordering parameter-by-parameter...
1134 46         102 my $partial_ordering = 0;
1135 46         315 for my $n (0 .. max($#$sig_a, $#$sig_b)) {
1136             # Unpack the next parameter types...
1137 88   50     276 my $sig_a_n = $sig_a->[$n] // {};
1138 88         214 my $sig_a_name = $sig_a_n->{named};
1139 88 100 50     284 my $sig_b_n = ($sig_a_name ? $named_B->{$sig_a_name} : $sig_b->[$n]) // {};
1140 88   50     411 my ($type_a, $type_b) = ($sig_a_n->{type} // 'Any', $sig_b_n->{type} // 'Any');
      50        
1141              
1142             # Find the ordering of the next parameter pair from the two signatures...
1143 88         186 my $is_narrower = _is_narrower($type_a, $type_b);
1144              
1145             # Tie-break in favour of the type with more constraints...
1146 88 100 66     251 if (!$is_narrower && $type_a eq $type_b) {
1147 26   50     95 my $where_a = $sig_a_n->{where} // 0;
1148 26   50     104 my $where_b = $sig_b_n->{where} // 0;
1149 26 50       91 $is_narrower = $where_a > $where_b ? -1
    50          
1150             : $where_a < $where_b ? +1
1151             : 0;
1152             }
1153              
1154             # If this pair's ordering contradicts the ordering so far, there is no ordering...
1155 88 100 100     337 return 0 if $is_narrower && $is_narrower == -$partial_ordering;
1156              
1157             # Otherwise if there's an ordering, it becomes the "ordering so far"...
1158 72   100     244 $partial_ordering ||= $is_narrower;
1159             }
1160              
1161             # If we make it through the entire list, return the resulting ordering...
1162 30         130 return $partial_ordering;
1163             }
1164              
1165             # Resolve ambiguous argument lists using Perl6-ish multiple dispatch rules...
1166 60     60   652 use List::Util qw< max first >;
  60         130  
  60         78878  
1167             sub _resolve_signatures {
1168 27     27   38 state %narrowness_for;
1169 27         118 my ($kind, @sigs) = @_;
1170              
1171             # Track narrownesses...
1172 27         112 my %narrower = map { $_ => [] } 0..$#sigs;
  78         284  
1173              
1174             # Compare all signatures, recording definitive differences in narrowness...
1175 27         118 for my $index_1 (0 .. $#sigs) {
1176 78         217 for my $index_2 ($index_1+1 .. $#sigs) {
1177 91         184 my $sig1 = $sigs[$index_1]{sig};
1178 91         182 my $sig2 = $sigs[$index_2]{sig};
1179             my $narrowness =
1180 91   100     512 $narrowness_for{$sig1,$sig2} //= _cmp_signatures($sig1, $sig2);
1181              
1182 91 100       284 if ($narrowness < 0) { push @{$narrower{$index_1}}, $index_2; }
  35 100       50  
  35         138  
1183 24         40 elsif ($narrowness > 0) { push @{$narrower{$index_2}}, $index_1; }
  24         103  
1184             }
1185             }
1186              
1187             # Find the narrowest signature(s)...
1188 27         84 my $max_narrower = max map { scalar @{$_} } values %narrower;
  78         92  
  78         207  
1189              
1190             # If they're not sufficiently narrow, weed out the non-contenders...
1191 27 100       82 if ($max_narrower < @sigs-1) {
1192 6         17 @sigs = @sigs[ sort grep { @{$narrower{$_}} } keys %narrower ];
  22         40  
  22         98  
1193             }
1194             # Otherwise, locate the narrowest...
1195             else {
1196 21     38   168 @sigs = @sigs[ first { @{$narrower{$_}} >= $max_narrower } keys %narrower ];
  38         44  
  38         122  
1197             }
1198              
1199             # Tie-break methods on the class of the variants...
1200 27 100 100     178 if ($kind eq 'method' && @sigs > 1) {
1201 4         30 @sigs = sort { $a->{class} eq $b->{class} ? 0
1202             : $a->{class}->isa($b->{class}) ? -1
1203 4 50       38 : $b->{class}->isa($a->{class}) ? +1
    50          
    100          
1204             : 0
1205             } @sigs;
1206 4         78 @sigs = grep { $_->{class} eq $sigs[0]{class} } @sigs;
  8         24  
1207             }
1208              
1209 27         136 return @sigs;
1210             }
1211              
1212              
1213             sub _describe_constraint {
1214 40     40   116 my ($value, $value_desc, $constraint, $constraint_desc) = @_;
1215              
1216             # Did the exception provide a constraint description???
1217 40 50       104 if ($constraint_desc) {
1218 0         0 $constraint_desc =~ s{\b at .* line .*+ \s*+}{}gx;
1219             }
1220              
1221             # Describe the value that failed...
1222 40         192 $value_desc = _complete_desc($value_desc, $value);
1223              
1224             # Try to describe the constraint by name, if it was a named sub...
1225 40 50 50     286 if (!length($constraint_desc//q{}) && eval{ require B }) {
  40   33     394  
1226 40         363 my $sub_name = B::svref_2object($constraint)->GV->NAME;
1227 40 50 33     394 if ($sub_name && $sub_name ne '__ANON__') {
1228 0         0 $sub_name =~ s/[:_]++/ /g;
1229 0         0 $constraint_desc = $sub_name;
1230             }
1231             }
1232              
1233             # Deparse the constraint sub (if necessary and possible)...
1234 40 50 50     128 if (!length($constraint_desc//q{}) && eval{ require B::Deparse }) {
  40   33     242  
1235 40         397 state $deparser = B::Deparse->new;
1236 40         131 my ($hint_bits, $warning_bits) = (caller 0)[8,9];
1237 40         1468 $deparser->ambient_pragmas(
1238             hint_bits => $hint_bits, warning_bits => $warning_bits, # '$[' => 0 + $[
1239             );
1240 40         47436 $constraint_desc = $deparser->coderef2text($constraint);
1241 40         1789 $constraint_desc =~ s{\s*+ BEGIN \s*+ \{ (?&CODE) \}
1242             (?(DEFINE) (? [^{}]*+ (\{ (?&CODE) \} [^{}]*+ )*+ ))}{}gxms;
1243 40         670 $constraint_desc =~ s{(?: (?:use|no) \s*+ (?: feature | warnings | strict ) | die \s*+ sprintf ) [^;]* ;}{}gxms;
1244 40         191 $constraint_desc =~ s{package \s*+ \S+ \s*+ ;}{}gxms;
1245 40         271 $constraint_desc =~ s{\s++}{ }g;
1246             }
1247 40   33     227 return $constraint_desc // "$constraint";
1248             }
1249              
1250             sub _perl {
1251 60     60   40411 use Data::Dump 'dump';
  60         386592  
  60         25608  
1252             dump( map {
1253 1471 50   1471   446462 if (my $tiedclass = tied $_) { $tiedclass =~ s/=.*//; "<$tiedclass tie>" }
  1473 100       5137  
  0         0  
  0         0  
1254 2         10 elsif (my $classname = blessed $_) { "<$classname object>" }
1255 1471         6083 else { $_ }
1256             } @_ )
1257             =~ s{" (< \S++ \s (?:object|tie) >) "}{$1}xgmsr;
1258              
1259             }
1260              
1261              
1262              
1263             1; # Magic true value required at end of module
1264             __END__