xref: /openbsd-src/gnu/usr.bin/perl/t/op/lexsub.t (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1#!perl
2
3BEGIN {
4    chdir 't';
5    @INC = '../lib';
6    require './test.pl';
7    *bar::is = *is;
8    *bar::like = *like;
9}
10plan 126;
11
12# -------------------- Errors with feature disabled -------------------- #
13
14eval "#line 8 foo\nmy sub foo";
15is $@, qq 'Experimental "my" subs not enabled at foo line 8.\n',
16  'my sub unexperimental error';
17eval "#line 8 foo\nCORE::state sub foo";
18is $@, qq 'Experimental "state" subs not enabled at foo line 8.\n',
19  'state sub unexperimental error';
20eval "#line 8 foo\nour sub foo";
21is $@, qq 'Experimental "our" subs not enabled at foo line 8.\n',
22  'our sub unexperimental error';
23
24# -------------------- our -------------------- #
25
26no warnings "experimental::lexical_subs";
27use feature 'lexical_subs';
28{
29  our sub foo { 42 }
30  is foo, 42, 'calling our sub from same package';
31  is &foo, 42, 'calling our sub from same package (amper)';
32  package bar;
33  sub bar::foo { 43 }
34  is foo, 42, 'calling our sub from another package';
35  is &foo, 42, 'calling our sub from another package (amper)';
36}
37package bar;
38is foo, 43, 'our sub falling out of scope';
39is &foo, 43, 'our sub falling out of scope (called via amper)';
40package main;
41{
42  sub bar::a { 43 }
43  our sub a {
44    if (shift) {
45      package bar;
46      is a, 43, 'our sub invisible inside itself';
47      is &a, 43, 'our sub invisible inside itself (called via amper)';
48    }
49    42
50  }
51  a(1);
52  sub bar::b { 43 }
53  our sub b;
54  our sub b {
55    if (shift) {
56      package bar;
57      is b, 42, 'our sub visible inside itself after decl';
58      is &b, 42, 'our sub visible inside itself after decl (amper)';
59    }
60    42
61  }
62  b(1)
63}
64sub c { 42 }
65sub bar::c { 43 }
66{
67  our sub c;
68  package bar;
69  is c, 42, 'our sub foo; makes lex alias for existing sub';
70  is &c, 42, 'our sub foo; makes lex alias for existing sub (amper)';
71}
72{
73  our sub d;
74  sub bar::d { 'd43' }
75  package bar;
76  sub d { 'd42' }
77  is eval ::d, 'd42', 'our sub foo; applies to subsequent sub foo {}';
78}
79{
80  our sub e ($);
81  is prototype "::e", '$', 'our sub with proto';
82}
83{
84  our sub if() { 42 }
85  my $x = if if if;
86  is $x, 42, 'lexical subs (even our) override all keywords';
87  package bar;
88  my $y = if if if;
89  is $y, 42, 'our subs from other packages override all keywords';
90}
91
92# -------------------- state -------------------- #
93
94use feature 'state'; # state
95{
96  state sub foo { 44 }
97  isnt \&::foo, \&foo, 'state sub is not stored in the package';
98  is eval foo, 44, 'calling state sub from same package';
99  is eval &foo, 44, 'calling state sub from same package (amper)';
100  package bar;
101  is eval foo, 44, 'calling state sub from another package';
102  is eval &foo, 44, 'calling state sub from another package (amper)';
103}
104package bar;
105is foo, 43, 'state sub falling out of scope';
106is &foo, 43, 'state sub falling out of scope (called via amper)';
107{
108  sub sa { 43 }
109  state sub sa {
110    if (shift) {
111      is sa, 43, 'state sub invisible inside itself';
112      is &sa, 43, 'state sub invisible inside itself (called via amper)';
113    }
114    44
115  }
116  sa(1);
117  sub sb { 43 }
118  state sub sb;
119  state sub sb {
120    if (shift) {
121      # ‘state sub foo{}’ creates a new pad entry, not reusing the forward
122      #  declaration.  Being invisible inside itself, it sees the stub.
123      eval{sb};
124      like $@, qr/^Undefined subroutine &sb called at /,
125        'state sub foo {} after forward declaration';
126      eval{&sb};
127      like $@, qr/^Undefined subroutine &sb called at /,
128        'state sub foo {} after forward declaration (amper)';
129    }
130    44
131  }
132  sb(1);
133  sub sb2 { 43 }
134  state sub sb2;
135  sub sb2 {
136    if (shift) {
137      package bar;
138      is sb2, 44, 'state sub visible inside itself after decl';
139      is &sb2, 44, 'state sub visible inside itself after decl (amper)';
140    }
141    44
142  }
143  sb2(1);
144  state sub sb3;
145  {
146    state sub sb3 { # new pad entry
147      # The sub containing this comment is invisible inside itself.
148      # So this one here will assign to the outer pad entry:
149      sub sb3 { 47 }
150    }
151  }
152  is eval{sb3}, 47,
153    'sub foo{} applying to "state sub foo;" even inside state sub foo{}';
154  # Same test again, but inside an anonymous sub
155  sub {
156    state sub sb4;
157    {
158      state sub sb4 {
159        sub sb4 { 47 }
160      }
161    }
162    is sb4, 47,
163      'sub foo{} applying to "state sub foo;" even inside state sub foo{}';
164  }->();
165}
166sub sc { 43 }
167{
168  state sub sc;
169  eval{sc};
170  like $@, qr/^Undefined subroutine &sc called at /,
171     'state sub foo; makes no lex alias for existing sub';
172  eval{&sc};
173  like $@, qr/^Undefined subroutine &sc called at /,
174     'state sub foo; makes no lex alias for existing sub (amper)';
175}
176package main;
177{
178  state sub se ($);
179  is prototype eval{\&se}, '$', 'state sub with proto';
180  is prototype "se", undef, 'prototype "..." ignores state subs';
181}
182{
183  state sub if() { 44 }
184  my $x = if if if;
185  is $x, 44, 'state subs override all keywords';
186  package bar;
187  my $y = if if if;
188  is $y, 44, 'state subs from other packages override all keywords';
189}
190{
191  use warnings; no warnings "experimental::lexical_subs";
192  state $w ;
193  local $SIG{__WARN__} = sub { $w .= shift };
194  eval '#line 87 squidges
195    state sub foo;
196    state sub foo {};
197  ';
198  is $w,
199     '"state" subroutine &foo masks earlier declaration in same scope at '
200   . "squidges line 88.\n",
201     'warning for state sub masking earlier declaration';
202}
203# Since state vars inside anonymous subs are cloned at the same time as the
204# anonymous subs containing them, the same should happen for state subs.
205sub make_closure {
206  my $x = shift;
207  sub {
208    state sub foo { $x }
209    foo
210  }
211}
212$sub1 = make_closure 48;
213$sub2 = make_closure 49;
214is &$sub1, 48, 'state sub in closure (1)';
215is &$sub2, 49, 'state sub in closure (2)';
216# But we need to test that state subs actually do persist from one invoca-
217# tion of a named sub to another (i.e., that they are not my subs).
218{
219  use warnings; no warnings "experimental::lexical_subs";
220  state $w;
221  local $SIG{__WARN__} = sub { $w .= shift };
222  eval '#line 65 teetet
223    sub foom {
224      my $x = shift;
225      state sub poom { $x }
226      eval{\&poom}
227    }
228  ';
229  is $w, "Variable \"\$x\" will not stay shared at teetet line 67.\n",
230         'state subs get "Variable will not stay shared" messages';
231  my $poom = foom(27);
232  my $poom2 = foom(678);
233  is eval{$poom->()}, eval {$poom2->()},
234    'state subs close over the first outer my var, like pkg subs';
235  my $x = 43;
236  for $x (765) {
237    state sub etetetet { $x }
238    is eval{etetetet}, 43, 'state sub ignores for() localisation';
239  }
240}
241# And we also need to test that multiple state subs can close over each
242# other’s entries in the parent subs pad, and that cv_clone is not con-
243# fused by that.
244sub make_anon_with_state_sub{
245  sub {
246    state sub s1;
247    state sub s2 { \&s1 }
248    sub s1 { \&s2 }
249    if (@_) { return \&s1 }
250    is s1,\&s2, 'state sub in anon closure closing over sibling state sub';
251    is s2,\&s1, 'state sub in anon closure closing over sibling state sub';
252  }
253}
254{
255  my $s = make_anon_with_state_sub;
256  &$s;
257
258  # And make sure the state subs were actually cloned.
259  isnt make_anon_with_state_sub->(0), &$s(0),
260    'state subs in anon subs are cloned';
261  is &$s(0), &$s(0), 'but only when the anon sub is cloned';
262}
263{
264  state sub BEGIN { exit };
265  pass 'state subs are never special blocks';
266  state sub END { shift }
267  is eval{END('jkqeudth')}, jkqeudth,
268    'state sub END {shift} implies @_, not @ARGV';
269  state sub CORE { scalar reverse shift }
270  is CORE::uc("hello"), "HELLO",
271    'lexical CORE does not interfere with CORE::...';
272}
273{
274  state sub redef {}
275  use warnings; no warnings "experimental::lexical_subs";
276  state $w;
277  local $SIG{__WARN__} = sub { $w .= shift };
278  eval "#line 56 pygpyf\nsub redef {}";
279  is $w, "Subroutine redef redefined at pygpyf line 56.\n",
280         "sub redefinition warnings from state subs";
281}
282{
283  state sub p (\@) {
284    is ref $_[0], 'ARRAY', 'state sub with proto';
285  }
286  p(my @a);
287  p my @b;
288  state sub q () { 45 }
289  is q(), 45, 'state constant called with parens';
290}
291{
292  state sub x;
293  eval 'sub x {3}';
294  is x, 3, 'state sub defined inside eval';
295
296  sub r {
297    state sub foo { 3 };
298    if (@_) { # outer call
299      r();
300      is foo(), 42,
301         'state sub run-time redefinition applies to all recursion levels';
302    }
303    else { # inner call
304      eval 'sub foo { 42 }';
305    }
306  }
307  r(1);
308}
309like runperl(
310      switches => [ '-Mfeature=lexical_subs,state' ],
311      prog     => 'state sub a { foo ref } a()',
312      stderr   => 1
313     ),
314     qr/syntax error/,
315    'referencing a state sub after a syntax error does not crash';
316{
317  state $stuff;
318  package A {
319    state sub foo{ $stuff .= our $AUTOLOAD }
320    *A::AUTOLOAD = \&foo;
321  }
322  A::bar();
323  is $stuff, 'A::bar', 'state sub assigned to *AUTOLOAD can autoload';
324}
325{
326  state sub quire{qr "quires"}
327  package o { use overload qr => \&quire }
328  ok "quires" =~ bless([], o::), 'state sub used as overload method';
329}
330{
331  local $ENV{PERL5DB} = 'sub DB::DB{}';
332  is(
333    runperl(
334     switches => [ '-d' ],
335     progs => [ split "\n",
336      'use feature qw - lexical_subs state -;
337       no warnings q-experimental::lexical_subs-;
338       sub DB::sub{ print qq|4\n|; goto $DB::sub }
339       state sub foo {print qq|2\n|}
340       foo();
341      '
342     ],
343     stderr => 1
344    ),
345    "4\n2\n",
346    'state subs and DB::sub under -d'
347  );
348}
349
350# -------------------- my -------------------- #
351
352{
353  my sub foo { 44 }
354  isnt \&::foo, \&foo, 'my sub is not stored in the package';
355  is foo, 44, 'calling my sub from same package';
356  is &foo, 44, 'calling my sub from same package (amper)';
357  package bar;
358  is foo, 44, 'calling my sub from another package';
359  is &foo, 44, 'calling my sub from another package (amper)';
360}
361package bar;
362is foo, 43, 'my sub falling out of scope';
363is &foo, 43, 'my sub falling out of scope (called via amper)';
364{
365  sub ma { 43 }
366  my sub ma {
367    if (shift) {
368      is ma, 43, 'my sub invisible inside itself';
369      is &ma, 43, 'my sub invisible inside itself (called via amper)';
370    }
371    44
372  }
373  ma(1);
374  sub mb { 43 }
375  my sub mb;
376  my sub mb {
377    if (shift) {
378      # ‘my sub foo{}’ creates a new pad entry, not reusing the forward
379      #  declaration.  Being invisible inside itself, it sees the stub.
380      eval{mb};
381      like $@, qr/^Undefined subroutine &mb called at /,
382        'my sub foo {} after forward declaration';
383      eval{&mb};
384      like $@, qr/^Undefined subroutine &mb called at /,
385        'my sub foo {} after forward declaration (amper)';
386    }
387    44
388  }
389  mb(1);
390  sub mb2 { 43 }
391  my sub sb2;
392  sub mb2 {
393    if (shift) {
394      package bar;
395      is mb2, 44, 'my sub visible inside itself after decl';
396      is &mb2, 44, 'my sub visible inside itself after decl (amper)';
397    }
398    44
399  }
400  mb2(1);
401  my sub mb3;
402  {
403    my sub mb3 { # new pad entry
404      # The sub containing this comment is invisible inside itself.
405      # So this one here will assign to the outer pad entry:
406      sub mb3 { 47 }
407    }
408  }
409  is eval{mb3}, 47,
410    'sub foo{} applying to "my sub foo;" even inside my sub foo{}';
411  # Same test again, but inside an anonymous sub
412  sub {
413    my sub mb4;
414    {
415      my sub mb4 {
416        sub mb4 { 47 }
417      }
418    }
419    is mb4, 47,
420      'sub foo{} applying to "my sub foo;" even inside my sub foo{}';
421  }->();
422}
423sub mc { 43 }
424{
425  my sub mc;
426  eval{mc};
427  like $@, qr/^Undefined subroutine &mc called at /,
428     'my sub foo; makes no lex alias for existing sub';
429  eval{&mc};
430  like $@, qr/^Undefined subroutine &mc called at /,
431     'my sub foo; makes no lex alias for existing sub (amper)';
432}
433package main;
434{
435  my sub me ($);
436  is prototype eval{\&me}, '$', 'my sub with proto';
437  is prototype "me", undef, 'prototype "..." ignores my subs';
438
439  my $coderef = eval "my sub foo (\$\x{30cd}) {1}; \\&foo";
440  my $proto = prototype $coderef;
441  ok(utf8::is_utf8($proto), "my sub with UTF8 proto maintains the UTF8ness");
442  is($proto, "\$\x{30cd}", "check the prototypes actually match");
443}
444{
445  my sub if() { 44 }
446  my $x = if if if;
447  is $x, 44, 'my subs override all keywords';
448  package bar;
449  my $y = if if if;
450  is $y, 44, 'my subs from other packages override all keywords';
451}
452{
453  use warnings; no warnings "experimental::lexical_subs";
454  my $w ;
455  local $SIG{__WARN__} = sub { $w .= shift };
456  eval '#line 87 squidges
457    my sub foo;
458    my sub foo {};
459  ';
460  is $w,
461     '"my" subroutine &foo masks earlier declaration in same scope at '
462   . "squidges line 88.\n",
463     'warning for my sub masking earlier declaration';
464}
465# Test that my subs are cloned inside anonymous subs.
466sub mmake_closure {
467  my $x = shift;
468  sub {
469    my sub foo { $x }
470    foo
471  }
472}
473$sub1 = mmake_closure 48;
474$sub2 = mmake_closure 49;
475is &$sub1, 48, 'my sub in closure (1)';
476is &$sub2, 49, 'my sub in closure (2)';
477# Test that they are cloned in named subs.
478{
479  use warnings; no warnings "experimental::lexical_subs";
480  my $w;
481  local $SIG{__WARN__} = sub { $w .= shift };
482  eval '#line 65 teetet
483    sub mfoom {
484      my $x = shift;
485      my sub poom { $x }
486      \&poom
487    }
488  ';
489  is $w, undef, 'my subs get no "Variable will not stay shared" messages';
490  my $poom = mfoom(27);
491  my $poom2 = mfoom(678);
492  is $poom->(), 27, 'my subs closing over outer my var (1)';
493  is $poom2->(), 678, 'my subs closing over outer my var (2)';
494  my $x = 43;
495  my sub aoeu;
496  for $x (765) {
497    my sub etetetet { $x }
498    sub aoeu { $x }
499    is etetetet, 765, 'my sub respects for() localisation';
500    is aoeu, 43, 'unless it is declared outside the for loop';
501  }
502}
503# And we also need to test that multiple my subs can close over each
504# other’s entries in the parent subs pad, and that cv_clone is not con-
505# fused by that.
506sub make_anon_with_my_sub{
507  sub {
508    my sub s1;
509    my sub s2 { \&s1 }
510    sub s1 { \&s2 }
511    if (@_) { return eval { \&s1 } }
512    is eval{s1},eval{\&s2}, 'my sub in anon closure closing over sibling my sub';
513    is eval{s2},eval{\&s1}, 'my sub in anon closure closing over sibling my sub';
514  }
515}
516
517# Test my subs inside predeclared my subs
518{
519  my sub s2;
520  sub s2 {
521    my $x = 3;
522    my sub s3 { eval '$x' }
523    s3;
524  }
525  is s2, 3, 'my sub inside predeclared my sub';
526}
527
528{
529  my $s = make_anon_with_my_sub;
530  &$s;
531
532  # And make sure the my subs were actually cloned.
533  isnt make_anon_with_my_sub->(0), &$s(0),
534    'my subs in anon subs are cloned';
535  isnt &$s(0), &$s(0), 'at each invocation of the enclosing sub';
536}
537{
538  my sub BEGIN { exit };
539  pass 'my subs are never special blocks';
540  my sub END { shift }
541  is END('jkqeudth'), jkqeudth,
542    'my sub END {shift} implies @_, not @ARGV';
543}
544{
545  my sub redef {}
546  use warnings; no warnings "experimental::lexical_subs";
547  my $w;
548  local $SIG{__WARN__} = sub { $w .= shift };
549  eval "#line 56 pygpyf\nsub redef {}";
550  is $w, "Subroutine redef redefined at pygpyf line 56.\n",
551         "sub redefinition warnings from my subs";
552
553  undef $w;
554  sub {
555    my sub x {};
556    sub { eval "#line 87 khaki\n\\&x" }
557  }->()();
558  is $w, "Subroutine \"&x\" is not available at khaki line 87.\n",
559         "unavailability warning during compilation of eval in closure";
560
561  undef $w;
562  no warnings 'void';
563  eval <<'->()();';
564#line 87 khaki
565    sub {
566      my sub x{}
567      sub not_lexical8 {
568        \&x
569      }
570    }
571->()();
572  is $w, "Subroutine \"&x\" is not available at khaki line 90.\n",
573         "unavailability warning during compilation of named sub in anon";
574
575  undef $w;
576  sub not_lexical9 {
577    my sub x {};
578    format =
579@
580&x
581.
582  }
583  eval { write };
584  my($f,$l) = (__FILE__,__LINE__ - 1);
585  is $w, "Subroutine \"&x\" is not available at $f line $l.\n",
586         'unavailability warning during cloning';
587  $l -= 3;
588  is $@, "Undefined subroutine &x called at $f line $l.\n",
589         'Vivified sub is correctly named';
590}
591sub not_lexical10 {
592  my sub foo;
593  foo();
594  sub not_lexical11 {
595    my sub bar {
596      my $x = 'khaki car keys for the khaki car';
597      not_lexical10();
598      sub foo {
599       is $x, 'khaki car keys for the khaki car',
600       'mysubs in inner clonables use the running clone of their CvOUTSIDE'
601      }
602    }
603    bar()
604  }
605}
606not_lexical11();
607{
608  my sub p (\@) {
609    is ref $_[0], 'ARRAY', 'my sub with proto';
610  }
611  p(my @a);
612  p @a;
613  my sub q () { 46 }
614  is q(), 46, 'my constant called with parens';
615}
616{
617  my sub x;
618  my $count;
619  sub x { x() if $count++ < 10 }
620  x();
621  is $count, 11, 'my recursive subs';
622}
623{
624  my sub x;
625  eval 'sub x {3}';
626  is x, 3, 'my sub defined inside eval';
627}
628
629{
630  state $w;
631  local $SIG{__WARN__} = sub { $w .= shift };
632  eval q{ my sub george () { 2 } };
633  is $w, undef, 'no double free from constant my subs';
634}
635like runperl(
636      switches => [ '-Mfeature=lexical_subs,state' ],
637      prog     => 'my sub a { foo ref } a()',
638      stderr   => 1
639     ),
640     qr/syntax error/,
641    'referencing a my sub after a syntax error does not crash';
642{
643  state $stuff;
644  package A {
645    my sub foo{ $stuff .= our $AUTOLOAD }
646    *A::AUTOLOAD = \&foo;
647  }
648  A::bar();
649  is $stuff, 'A::bar', 'my sub assigned to *AUTOLOAD can autoload';
650}
651{
652  my sub quire{qr "quires"}
653  package mo { use overload qr => \&quire }
654  ok "quires" =~ bless([], mo::), 'my sub used as overload method';
655}
656
657{
658  local $ENV{PERL5DB} = 'sub DB::DB{}';
659  is(
660    runperl(
661     switches => [ '-d' ],
662     progs => [ split "\n",
663      'use feature qw - lexical_subs state -;
664       no warnings q-experimental::lexical_subs-;
665       sub DB::sub{ print qq|4\n|; goto $DB::sub }
666       my sub foo {print qq|2\n|}
667       foo();
668      '
669     ],
670     stderr => 1
671    ),
672    "4\n2\n",
673    'my subs and DB::sub under -d'
674  );
675}
676
677# -------------------- Interactions (and misc tests) -------------------- #
678
679is sub {
680    my sub s1;
681    my sub s2 { 3 };
682    sub s1 { state sub foo { \&s2 } foo }
683    s1
684  }->()(), 3, 'state sub inside my sub closing over my sub uncle';
685
686{
687  my sub s2 { 3 };
688  sub not_lexical { state sub foo { \&s2 } foo }
689  is not_lexical->(), 3, 'state subs that reference my sub from outside';
690}
691
692# Test my subs inside predeclared package subs
693# This test also checks that CvOUTSIDE pointers are not mangled when the
694# inner sub’s CvOUTSIDE points to another sub.
695sub not_lexical2;
696sub not_lexical2 {
697  my $x = 23;
698  my sub bar;
699  sub not_lexical3 {
700    not_lexical2();
701    sub bar { $x }
702  };
703  bar
704}
705is not_lexical3, 23, 'my subs inside predeclared package subs';
706
707# Test my subs inside predeclared package sub, where the lexical sub is
708# declared outside the package sub.
709# This checks that CvOUTSIDE pointers are fixed up even when the sub is
710# not declared inside the sub that its CvOUTSIDE points to.
711sub not_lexical5 {
712  my sub foo;
713  sub not_lexical4;
714  sub not_lexical4 {
715    my $x = 234;
716    not_lexical5();
717    sub foo { $x }
718  }
719  foo
720}
721is not_lexical4, 234,
722    'my sub defined in predeclared pkg sub but declared outside';
723
724undef *not_lexical6;
725{
726  my sub foo;
727  sub not_lexical6 { sub foo { } }
728  pass 'no crash when cloning a mysub declared inside an undef pack sub';
729}
730
731undef &not_lexical7;
732eval 'sub not_lexical7 { my @x }';
733{
734  my sub foo;
735  foo();
736  sub not_lexical7 {
737    state $x;
738    sub foo {
739      is ref \$x, 'SCALAR',
740        "redeffing a mysub's outside does not make it use the wrong pad"
741    }
742  }
743}
744
745like runperl(
746      switches => [ '-Mfeature=lexical_subs,state', '-Mwarnings=FATAL,all', '-M-warnings=experimental::lexical_subs' ],
747      prog     => 'my sub foo; sub foo { foo } foo',
748      stderr   => 1
749     ),
750     qr/Deep recursion on subroutine "foo"/,
751    'deep recursion warnings for lexical subs do not crash';
752
753like runperl(
754      switches => [ '-Mfeature=lexical_subs,state', '-Mwarnings=FATAL,all', '-M-warnings=experimental::lexical_subs' ],
755      prog     => 'my sub foo() { 42 } undef &foo',
756      stderr   => 1
757     ),
758     qr/Constant subroutine foo undefined at /,
759    'constant undefinition warnings for lexical subs do not crash';
760
761{
762  my sub foo;
763  *AutoloadTestSuper::blah = \&foo;
764  sub AutoloadTestSuper::AUTOLOAD {
765    is $AutoloadTestSuper::AUTOLOAD, "AutoloadTestSuper::blah",
766      "Autoloading via inherited lex stub";
767  }
768  @AutoloadTest::ISA = AutoloadTestSuper::;
769  AutoloadTest->blah;
770}
771