X-Git-Url: https://perl5.git.perl.org/perl5.git/blobdiff_plain/d37a953848a8a5e776efddc4a0591621effaf5f1..80e09529483332d99472e6944c1f7b1abc89c89c:/t/comp/proto.t diff --git a/t/comp/proto.t b/t/comp/proto.t old mode 100755 new mode 100644 index 32b1fad..51d1463 --- a/t/comp/proto.t +++ b/t/comp/proto.t @@ -14,9 +14,11 @@ BEGIN { @INC = '../lib'; } +# We need this, as in places we're testing the interaction of prototypes with +# strict use strict; -print "1..135\n"; +print "1..186\n"; my $i = 1; @@ -407,10 +409,26 @@ print "ok ", $i++, "\n"; print "# CORE::open => ($p)\nnot " if ($p = prototype('CORE::open')) ne '*;$@'; print "ok ", $i++, "\n"; -print "# CORE:Foo => ($p), \$@ => `$@'\nnot " +print "# CORE::Foo => ($p), \$@ => '$@'\nnot " if defined ($p = eval { prototype('CORE::Foo') or 1 }) or $@ !~ /^Can't find an opnumber/; print "ok ", $i++, "\n"; +eval { prototype("CORE::a\0b") }; +print "# CORE::a\\0b: \$@ => '$@'\nnot " + if $@ !~ /^Can't find an opnumber for "a\0b"/; +print "ok ", $i++, "\n"; + +eval { prototype("CORE::\x{100}") }; +print "# CORE::\\x{100}: => ($p), \$@ => '$@'\nnot " + if $@ !~ /^Can't find an opnumber for "\x{100}"/; +print "ok ", $i++, "\n"; + +"CORE::Foo" =~ /(.*)/; +print "# \$1 containing CORE::Foo => ($p), \$@ => '$@'\nnot " + if defined ($p = eval { prototype($1) or 1 }) + or $@ !~ /^Can't find an opnumber/; +print "ok ", $i++, " - \$1 containing CORE::Foo\n"; + # correctly note too-short parameter lists that don't end with '$', # a possible regression. @@ -441,50 +459,139 @@ sub star2 (**&) { &{$_[2]} } sub BAR { "quux" } sub Bar::BAZ { "quuz" } my $star = 'FOO'; -star FOO, sub { print "ok $i\n" if $_[0] eq 'FOO' }; $i++; -star(FOO, sub { print "ok $i\n" if $_[0] eq 'FOO' }); $i++; -star "FOO", sub { print "ok $i\n" if $_[0] eq 'FOO' }; $i++; -star("FOO", sub { print "ok $i\n" if $_[0] eq 'FOO' }); $i++; -star $star, sub { print "ok $i\n" if $_[0] eq 'FOO' }; $i++; -star($star, sub { print "ok $i\n" if $_[0] eq 'FOO' }); $i++; -star *FOO, sub { print "ok $i\n" if $_[0] eq \*FOO }; $i++; -star(*FOO, sub { print "ok $i\n" if $_[0] eq \*FOO }); $i++; -star \*FOO, sub { print "ok $i\n" if $_[0] eq \*FOO }; $i++; -star(\*FOO, sub { print "ok $i\n" if $_[0] eq \*FOO }); $i++; -star2 FOO, BAR, sub { print "ok $i\n" - if $_[0] eq 'FOO' and $_[1] eq 'BAR' }; $i++; -star2(Bar::BAZ, FOO, sub { print "ok $i\n" - if $_[0] eq 'Bar::BAZ' and $_[1] eq 'FOO' }); $i++; -star2 BAR(), FOO, sub { print "ok $i\n" - if $_[0] eq 'quux' and $_[1] eq 'FOO' }; $i++; -star2(FOO, BAR(), sub { print "ok $i\n" - if $_[0] eq 'FOO' and $_[1] eq 'quux' }); $i++; -star2 "FOO", "BAR", sub { print "ok $i\n" - if $_[0] eq 'FOO' and $_[1] eq 'BAR' }; $i++; -star2("FOO", "BAR", sub { print "ok $i\n" - if $_[0] eq 'FOO' and $_[1] eq 'BAR' }); $i++; -star2 $star, $star, sub { print "ok $i\n" - if $_[0] eq 'FOO' and $_[1] eq 'FOO' }; $i++; -star2($star, $star, sub { print "ok $i\n" - if $_[0] eq 'FOO' and $_[1] eq 'FOO' }); $i++; -star2 *FOO, *BAR, sub { print "ok $i\n" - if $_[0] eq \*FOO and $_[1] eq \*BAR }; $i++; -star2(*FOO, *BAR, sub { print "ok $i\n" - if $_[0] eq \*FOO and $_[1] eq \*BAR }); $i++; -star2 \*FOO, \*BAR, sub { no strict 'refs'; print "ok $i\n" - if $_[0] eq \*{'FOO'} and $_[1] eq \*{'BAR'} }; $i++; -star2(\*FOO, \*BAR, sub { no strict 'refs'; print "ok $i\n" - if $_[0] eq \*{'FOO'} and $_[1] eq \*{'BAR'} }); $i++; +star FOO, sub { + print "not " unless $_[0] eq 'FOO'; + print "ok $i - star FOO\n"; +}; $i++; +star(FOO, sub { + print "not " unless $_[0] eq 'FOO'; + print "ok $i - star(FOO)\n"; + }); $i++; +star "FOO", sub { + print "not " unless $_[0] eq 'FOO'; + print qq/ok $i - star "FOO"\n/; +}; $i++; +star("FOO", sub { + print "not " unless $_[0] eq 'FOO'; + print qq/ok $i - star("FOO")\n/; + }); $i++; +star $star, sub { + print "not " unless $_[0] eq 'FOO'; + print "ok $i - star \$star\n"; +}; $i++; +star($star, sub { + print "not " unless $_[0] eq 'FOO'; + print "ok $i - star(\$star)\n"; + }); $i++; +star *FOO, sub { + print "not " unless $_[0] eq \*FOO; + print "ok $i - star *FOO\n"; +}; $i++; +star(*FOO, sub { + print "not " unless $_[0] eq \*FOO; + print "ok $i - star(*FOO)\n"; + }); $i++; +star \*FOO, sub { + print "not " unless $_[0] eq \*FOO; + print "ok $i - star \\*FOO\n"; +}; $i++; +star(\*FOO, sub { + print "not " unless $_[0] eq \*FOO; + print "ok $i - star(\\*FOO)\n"; + }); $i++; +star2 FOO, BAR, sub { + print "not " unless $_[0] eq 'FOO' and $_[1] eq 'BAR'; + print "ok $i - star2 FOO, BAR\n"; +}; $i++; +star2(Bar::BAZ, FOO, sub { + print "not " unless $_[0] eq 'Bar::BAZ' and $_[1] eq 'FOO'; + print "ok $i - star2(Bar::BAZ, FOO)\n" + }); $i++; +star2 BAR(), FOO, sub { + print "not " unless $_[0] eq 'quux' and $_[1] eq 'FOO'; + print "ok $i - star2 BAR(), FOO\n" +}; $i++; +star2(FOO, BAR(), sub { + print "not " unless $_[0] eq 'FOO' and $_[1] eq 'quux'; + print "ok $i - star2(FOO, BAR())\n"; + }); $i++; +star2 "FOO", "BAR", sub { + print "not " unless $_[0] eq 'FOO' and $_[1] eq 'BAR'; + print qq/ok $i - star2 "FOO", "BAR"\n/; +}; $i++; +star2("FOO", "BAR", sub { + print "not " unless $_[0] eq 'FOO' and $_[1] eq 'BAR'; + print qq/ok $i - star2("FOO", "BAR")\n/; + }); $i++; +star2 $star, $star, sub { + print "not " unless $_[0] eq 'FOO' and $_[1] eq 'FOO'; + print "ok $i - star2 \$star, \$star\n"; +}; $i++; +star2($star, $star, sub { + print "not " unless $_[0] eq 'FOO' and $_[1] eq 'FOO'; + print "ok $i - star2(\$star, \$star)\n"; + }); $i++; +star2 *FOO, *BAR, sub { + print "not " unless $_[0] eq \*FOO and $_[1] eq \*BAR; + print "ok $i - star2 *FOO, *BAR\n"; +}; $i++; +star2(*FOO, *BAR, sub { + print "not " unless $_[0] eq \*FOO and $_[1] eq \*BAR; + print "ok $i - star2(*FOO, *BAR)\n"; + }); $i++; +star2 \*FOO, \*BAR, sub { + no strict 'refs'; + print "not " unless $_[0] eq \*{'FOO'} and $_[1] eq \*{'BAR'}; + print "ok $i - star2 \*FOO, \*BAR\n"; +}; $i++; +star2(\*FOO, \*BAR, sub { + no strict 'refs'; + print "not " unless $_[0] eq \*{'FOO'} and $_[1] eq \*{'BAR'}; + print "ok $i - star2(\*FOO, \*BAR)\n"; + }); $i++; + +# [perl #118585] +# Test that multiple semicolons are treated as one with * +sub star3(;;;*){} +sub star4( ; ; ; ; *){} +print "not " unless eval 'star3 STDERR; 1'; +print "ok ", $i++, " star3 STDERR\n"; +print "not " unless eval 'star4 STDERR; 1'; +print "ok ", $i++, " star4 STDERR\n"; # test scalarref prototype sub sreftest (\$$) { - print "ok $_[1]\n" if ref $_[0]; + print "not " unless ref $_[0]; + print "ok $_[1] - sreftest\n"; } { no strict 'vars'; sreftest my $sref, $i++; sreftest($helem{$i}, $i++); sreftest $aelem[0], $i++; + sreftest sub { [0] }->()[0], $i++; + sreftest my $a = 'quidgley', $i++; + print "not " if eval 'return 1; sreftest(3+4)'; + print "ok ", $i++, ' - \$ with invalid argument', "\n"; +} + +# test single term +sub lazy (+$$) { + print "not " unless @_ == 3 && ref $_[0] eq $_[1]; + print "ok $_[2] - non container test\n"; +} +sub quietlazy (+) { return shift(@_) } +sub give_aref { [] } +sub list_or_scalar { wantarray ? (1..10) : [] } +{ + my @multiarray = ("a".."z"); + my %bighash = @multiarray; + lazy(\@multiarray, 'ARRAY', $i++); + lazy(\%bighash, 'HASH', $i++); + lazy({}, 'HASH', $i++); + lazy(give_aref, 'ARRAY', $i++); + lazy(3, '', $i++); # allowed by prototype, even if runtime error + lazy(list_or_scalar, 'ARRAY', $i++); # propagate scalar context } # test prototypes when they are evaled and there is a syntax error @@ -492,21 +599,23 @@ sub sreftest (\$$) { # string "parse error". # for my $p ( "", qw{ () ($) ($@) ($%) ($;$) (&) (&\@) (&@) (%) (\%) (\@) } ) { - no warnings 'prototype'; + my $warn = ""; + local $SIG{__WARN__} = sub { + my $thiswarn = join("",@_); + return if $thiswarn =~ /^Prototype mismatch: sub main::evaled_subroutine/; + $warn .= $thiswarn; + }; my $eval = "sub evaled_subroutine $p { &void *; }"; eval $eval; print "# eval[$eval]\nnot " unless $@ && $@ =~ /(parse|syntax) error/i; print "ok ", $i++, "\n"; + if ($warn eq '') { + print "ok ", $i++, "\n"; + } else { + print "not ok ", $i++, "# $warn \n"; + } } -# Not $$;$;$ -print "not " unless prototype "CORE::substr" eq '$$;$$'; -print "ok ", $i++, "\n"; - -# recv takes a scalar reference for its second argument -print "not " unless prototype "CORE::recv" eq '*\\$$$'; -print "ok ", $i++, "\n"; - { my $myvar; my @myarray; @@ -518,6 +627,8 @@ print "ok ", $i++, "\n"; print "not " unless myref($myvar) =~ /^SCALAR\(/; print "ok ", $i++, "\n"; + print "not " unless myref($myvar=7) =~ /^SCALAR\(/; + print "ok ", $i++, "\n"; print "not " unless myref(@myarray) =~ /^ARRAY\(/; print "ok ", $i++, "\n"; print "not " unless myref(%myhash) =~ /^HASH\(/; @@ -526,10 +637,33 @@ print "ok ", $i++, "\n"; print "ok ", $i++, "\n"; print "not " unless myref(*myglob) =~ /^GLOB\(/; print "ok ", $i++, "\n"; + + eval q/sub multi1 (\[%@]) { 1 } multi1 $myvar;/; + print "not " + unless $@ =~ /Type of arg 1 to main::multi1 must be one of \[%\@\] /; + print "ok ", $i++, "\n"; + eval q/sub multi2 (\[$*&]) { 1 } multi2 @myarray;/; + print "not " + unless $@ =~ /Type of arg 1 to main::multi2 must be one of \[\$\*&\] /; + print "ok ", $i++, "\n"; + eval q/sub multi3 (\[$@]) { 1 } multi3 %myhash;/; + print "not " + unless $@ =~ /Type of arg 1 to main::multi3 must be one of \[\$\@\] /; + print "ok ", $i++, "\n"; + eval q/sub multi4 ($\[%]) { 1 } multi4 1, &mysub;/; + print "not " + unless $@ =~ /Type of arg 2 to main::multi4 must be one of \[%\] /; + print "ok ", $i++, "\n"; + eval q/sub multi5 (\[$@]$) { 1 } multi5 *myglob;/; + print "not " + unless $@ =~ /Type of arg 1 to main::multi5 must be one of \[\$\@\] / + && $@ =~ /Not enough arguments/; + print "ok ", $i++, "\n"; } # check that obviously bad prototypes are getting warnings { + local $^W = 1; my $warn = ""; local $SIG{__WARN__} = sub { $warn .= join("",@_) }; @@ -554,3 +688,104 @@ print "ok ", $i++, "\n"; eval "sub good (\$\t\$\n\$) { 1; }"; print "not " if $@; print "ok ", $i++, "\n"; + +# Ought to fail, doesn't in 5.8.1. +eval 'sub bug (\[%@]) { } my $array = [0 .. 1]; bug %$array;'; +print "not " unless $@ =~ /Not a HASH reference/; +print "ok ", $i++, "\n"; + +# [perl #75904] +# Test that the following prototypes make subs parse as unary functions: +# * \sigil \[...] ;$ ;* ;\sigil ;\[...] +# [perl #118585] +# As a special case, make sure that ;;* is treated the same as ;* +print "not " + unless eval 'sub uniproto1 (*) {} uniproto1 $_, 1' or warn $@; +print "ok ", $i++, "\n"; +print "not " + unless eval 'sub uniproto2 (\$) {} uniproto2 $_, 1' or warn $@; +print "ok ", $i++, "\n"; +print "not " + unless eval 'sub uniproto3 (\[$%]) {} uniproto3 %_, 1' or warn $@; +print "ok ", $i++, "\n"; +print "not " + unless eval 'sub uniproto4 (;$) {} uniproto4 $_, 1' or warn $@; +print "ok ", $i++, "\n"; +print "not " + unless eval 'sub uniproto5 (;*) {} uniproto5 $_, 1' or warn $@; +print "ok ", $i++, "\n"; +print "not " + unless eval 'sub uniproto6 (;\@) {} uniproto6 @_, 1' or warn $@; +print "ok ", $i++, "\n"; +print "not " + unless eval 'sub uniproto7 (;\[$%@]) {} uniproto7 @_, 1' or warn $@; +print "ok ", $i++, "\n"; +print "not " + unless eval 'sub uniproto8 (+) {} uniproto8 $_, 1' or warn $@; +print "ok ", $i++, "\n"; +print "not " + unless eval 'sub uniproto9 (;+) {} uniproto9 $_, 1' or warn $@; +print "ok ", $i++, "\n"; +print "not " + unless eval 'sub uniproto10 (;;;*) {} uniproto10 $_, 1' or warn $@; +print "ok ", $i++, " - uniproto10 (;;;*)\n"; +print "not " + unless eval 'sub uniproto11 ( ; ; ; * ) {} uniproto10 $_, 1' or warn $@; +print "ok ", $i++, " - uniproto11 ( ; ; ; *)\n"; +print "not " + unless eval 'sub uniproto12 (;;;+) {} uniproto12 $_, 1' or warn $@; +print "ok ", $i++, " - uniproto12 (;;;*)\n"; +print "not " + unless eval 'sub uniproto12 ( ; ; ; + ) {} uniproto12 $_, 1' or warn $@; +print "ok ", $i++, " - uniproto12 ( ; ; ; * )\n"; + +# Test that a trailing semicolon makes a sub have listop precedence +sub unilist ($;) { $_[0]+1 } +sub unilist2(_;) { $_[0]+1 } +sub unilist3(;$;) { $_[0]+1 } +print "not " unless (unilist 0 || 5) == 6; +print "ok ", $i++, "\n"; +print "not " unless (unilist2 0 || 5) == 6; +print "ok ", $i++, "\n"; +print "not " unless (unilist3 0 || 5) == 6; +print "ok ", $i++, "\n"; + +{ + # Lack of prototype on a subroutine definition should override any prototype + # on the declaration. + sub z_zwap (&); + + local $SIG{__WARN__} = sub { + my $thiswarn = join "",@_; + if ($thiswarn =~ /^Prototype mismatch: sub main::z_zwap/) { + print 'ok ', $i++, "\n"; + } else { + print 'not ok ', $i++, "\n"; + print STDERR $thiswarn; + } + }; + + eval q{sub z_zwap {return @_}}; + + if ($@) { + print "not ok ", $i++, "# $@"; + } else { + print "ok ", $i++, "\n"; + } + + + my @a = (6,4,2); + my @got = eval q{z_zwap(@a)}; + + if ($@) { + print "not ok ", $i++, " # $@"; + } else { + print "ok ", $i++, "\n"; + } + + if ("@got" eq "@a") { + print "ok ", $i++, "\n"; + } else { + print "not ok ", $i++, " # >@got<\n"; + } +}