summaryrefslogtreecommitdiff
path: root/t
diff options
context:
space:
mode:
Diffstat (limited to 't')
-rw-r--r--t/op/aassign.t265
-rw-r--r--t/op/array.t8
-rw-r--r--t/op/hash.t7
-rw-r--r--t/op/sort.t18
-rw-r--r--t/perf/benchmarks370
-rw-r--r--t/perf/optree.t84
6 files changed, 731 insertions, 21 deletions
diff --git a/t/op/aassign.t b/t/op/aassign.t
new file mode 100644
index 0000000000..622053c004
--- /dev/null
+++ b/t/op/aassign.t
@@ -0,0 +1,265 @@
+#!./perl -w
+
+# Some miscellaneous checks for the list assignment operator, OP_AASSIGN.
+#
+# This file was only added in 2015; before then, such tests were
+# typically in various other random places like op/array.t. This test file
+# doesn't therefore attempt to be comprehensive; it merely provides a
+# central place to new put additional tests, especially those related to
+# the trickiness of commonality, e.g. ($a,$b) = ($b,$a).
+#
+# In particular, it's testing the flags
+# OPpASSIGN_COMMON_SCALAR
+# OPpASSIGN_COMMON_RC1
+# OPpASSIGN_COMMON_AGG
+
+BEGIN {
+ chdir 't' if -d 't';
+ @INC = '../lib';
+ require './test.pl';
+}
+
+use warnings;
+use strict;
+
+# general purpose package vars
+
+our $pkg_scalar;
+our @pkg_array;
+our %pkg_hash;
+
+sub f_ret_14 { return 1..4 }
+
+# stringify a hash ref
+
+sub sh {
+ my $rh = $_[0];
+ join ',', map "$_:$rh->{$_}", sort keys %$rh;
+}
+
+
+# where the RHS has surplus elements
+
+{
+ my ($a,$b);
+ ($a,$b) = f_ret_14();
+ is("$a:$b", "1:2", "surplus");
+}
+
+# common with slices
+
+{
+ my @a = (1,2);
+ @a[0,1] = @a[1,0];
+ is("$a[0]:$a[1]", "2:1", "lex array slice");
+}
+
+# package alias
+
+{
+ my ($a, $b) = 1..2;
+ for $pkg_scalar ($a) {
+ ($pkg_scalar, $b) = (3, $a);
+ is($pkg_scalar, 3, "package alias pkg");
+ is("$a:$b", "3:1", "package alias a:b");
+ }
+}
+
+# my array/hash populated via closure
+
+{
+ my $ra = f1();
+ my ($x, @a) = @$ra;
+ sub f1 { $x = 1; @a = 2..4; \@a }
+ is($x, 2, "my: array closure x");
+ is("@a", "3 4", "my: array closure a");
+
+ my $rh = f2();
+ my ($k, $v, %h) = (d => 4, %$rh, e => 6);
+ sub f2 { $k = 'a'; $v = 1; %h = qw(b 2 c 3); \%h }
+ is("$k:$v", "d:4", "my: hash closure k:v");
+ is(sh(\%h), "b:2,c:3,e:6", "my: hash closure h");
+}
+
+
+# various shared element scenarios within a my (...)
+
+{
+ my ($x,$y) = f3(); # $x and $y on both sides
+ sub f3 : lvalue { ($x,$y) = (1,2); $y, $x }
+ is ("$x:$y", "2:1", "my: scalar and lvalue sub");
+}
+
+{
+ my $ra = f4();
+ my @a = @$ra; # elements of @a on both sides
+ sub f4 { @a = 1..4; \@a }
+ is("@a", "1 2 3 4", "my: array and elements");
+}
+
+{
+ my $rh = f5();
+ my %h = %$rh; # elements of %h on both sides
+ sub f5 { %h = qw(a 1 b 2 c 3); \%h }
+ is(sh(\%h), "a:1,b:2,c:3", "my: hash and elements");
+}
+
+{
+ f6();
+ our $xalias6;
+ my ($x, $y) = (2, $xalias6);
+ sub f6 { $x = 1; *xalias6 = \$x; }
+ is ("$x:$y", "2:1", "my: pkg var aliased to lexical");
+}
+
+
+{
+ my @a;
+ f7();
+ my ($x,$y) = @a;
+ is ("$x:$y", "2:1", "my: lex array elements aliased");
+
+ sub f7 {
+ ($x, $y) = (1,2);
+ use feature 'refaliasing';
+ no warnings 'experimental';
+ \($a[0], $a[1]) = \($y,$x);
+ }
+}
+
+{
+ @pkg_array = ();
+ f8();
+ my ($x,$y) = @pkg_array;
+ is ("$x:$y", "2:1", "my: pkg array elements aliased");
+
+ sub f8 {
+ ($x, $y) = (1,2);
+ use feature 'refaliasing';
+ no warnings 'experimental';
+ \($pkg_array[0], $pkg_array[1]) = \($y,$x);
+ }
+}
+
+{
+ f9();
+ my ($x,$y) = f9();
+ is ("$x:$y", "2:1", "my: pkg scalar alias");
+
+ our $xalias9;
+ sub f9 : lvalue {
+ ($x, $y) = (1,2);
+ *xalias9 = \$x;
+ $y, $xalias9;
+ }
+}
+
+{
+ use feature 'refaliasing';
+ no warnings 'experimental';
+
+ f10();
+ our $pkg10;
+ \(my $lex) = \$pkg10;
+ my @a = ($lex,3); # equivalent to ($a[0],3)
+ is("@a", "1 3", "my: lex alias of array alement");
+
+ sub f10 {
+ @a = (1,2);
+ \$pkg10 = \$a[0];
+ }
+
+}
+
+{
+ use feature 'refaliasing';
+ no warnings 'experimental';
+
+ f11();
+ my @b;
+ my @a = (@b);
+ is("@a", "2 1", "my: lex alias of array alements");
+
+ sub f11 {
+ @a = (1,2);
+ \$b[0] = \$a[1];
+ \$b[1] = \$a[0];
+ }
+}
+
+# package aliasing
+
+{
+ my ($x, $y) = (1,2);
+
+ for $pkg_scalar ($x) {
+ ($pkg_scalar, $y) = (3, $x);
+ is("$pkg_scalar,$y", "3,1", "package scalar aliased");
+ }
+}
+
+# lvalue subs on LHS
+
+{
+ my @a;
+ sub f12 : lvalue { @a }
+ (f12()) = 1..3;
+ is("@a", "1 2 3", "lvalue sub on RHS returns array");
+}
+
+{
+ my ($x,$y);
+ sub f13 : lvalue { $x,$y }
+ (f13()) = 1..3;
+ is("$x:$y", "1:2", "lvalue sub on RHS returns scalars");
+}
+
+
+# package shared scalar vars
+
+{
+ our $pkg14a = 1;
+ our $pkg14b = 2;
+ ($pkg14a,$pkg14b) = ($pkg14b,$pkg14a);
+ is("$pkg14a:$pkg14b", "2:1", "shared package scalars");
+}
+
+# lexical shared scalar vars
+
+{
+ my $a = 1;
+ my $b = 2;
+ ($a,$b) = ($b,$a);
+ is("$a:$b", "2:1", "shared lexical scalars");
+}
+
+
+# lexical nested array elem swap
+
+{
+ my @a;
+ $a[0][0] = 1;
+ $a[0][1] = 2;
+ ($a[0][0],$a[0][1]) = ($a[0][1],$a[0][0]);
+ is("$a[0][0]:$a[0][1]", "2:1", "lexical nested array elem swap");
+}
+
+# package nested array elem swap
+
+{
+ our @a15;
+ $a15[0][0] = 1;
+ $a15[0][1] = 2;
+ ($a15[0][0],$a15[0][1]) = ($a15[0][1],$a15[0][0]);
+ is("$a15[0][0]:$a15[0][1]", "2:1", "package nested array elem swap");
+}
+
+# surplus RHS junk
+#
+{
+ our ($a16, $b16);
+ ($a16, undef, $b16) = 1..30;
+ is("$a16:$b16", "1:3", "surplus RHS junk");
+}
+
+done_testing();
diff --git a/t/op/array.t b/t/op/array.t
index 7239d482fc..4f0a772aba 100644
--- a/t/op/array.t
+++ b/t/op/array.t
@@ -6,7 +6,7 @@ BEGIN {
require './test.pl';
}
-plan (172);
+plan (173);
#
# @foo, @bar, and @ary are also used from tie-stdarray after tie-ing them
@@ -549,4 +549,10 @@ is "@ary", 'b a',
for(scalar $#foo) { $_ = 3 }
is $#foo, 3, 'assigning to arylen aliased in foreach(scalar $#arylen)';
+{
+ my @a = qw(a b c);
+ @a = @a;
+ is "@a", 'a b c', 'assigning to itself';
+}
+
"We're included by lib/Tie/Array/std.t so we need to return something true";
diff --git a/t/op/hash.t b/t/op/hash.t
index 429eb38ce2..b4d6c2585f 100644
--- a/t/op/hash.t
+++ b/t/op/hash.t
@@ -207,4 +207,11 @@ torture_hash('a .. zz', 'a' .. 'zz');
torture_hash('0 .. 9', 0 .. 9);
torture_hash("'Perl'", 'Rules');
+{
+ my %h = qw(a x b y c z);
+ no warnings qw(misc uninitialized);
+ %h = $h{a};
+ is(join(':', %h), 'x:', 'hash self-assign');
+}
+
done_testing();
diff --git a/t/op/sort.t b/t/op/sort.t
index 01227e3ff6..2e3ba68828 100644
--- a/t/op/sort.t
+++ b/t/op/sort.t
@@ -6,7 +6,7 @@ BEGIN {
set_up_inc('../lib');
}
use warnings;
-plan(tests => 190);
+plan(tests => 189);
# these shouldn't hang
{
@@ -778,12 +778,16 @@ cmp_ok($answer,'eq','good','sort subr called from other package');
is $@, "", 'abrupt scope exit turns off readonliness';
}
-{
- local $TODO = "sort should make sure elements are not freed in the sort block";
- eval { @nomodify_x=(1..8);
- our @copy = sort { undef @nomodify_x; 1 } (@nomodify_x, 3); };
- is($@, "");
-}
+# I commented out this TODO test because messing with FREEd scalars on the
+# stack can have all sorts of strange side-effects, not made safe by eval
+# - DAPM.
+#
+#{
+# local $TODO = "sort should make sure elements are not freed in the sort block";
+# eval { @nomodify_x=(1..8);
+# our @copy = sort { undef @nomodify_x; 1 } (@nomodify_x, 3); };
+# is($@, "");
+#}
# Sorting shouldn't increase the refcount of a sub
diff --git a/t/perf/benchmarks b/t/perf/benchmarks
index 144b58cb96..2e58849e38 100644
--- a/t/perf/benchmarks
+++ b/t/perf/benchmarks
@@ -242,4 +242,374 @@
code => 'index $x, "b"',
},
+
+ # list assign, OP_AASSIGN
+
+
+ # (....) = ()
+
+ 'expr::aassign::ma_empty' => {
+ desc => 'my array assigned empty',
+ setup => '',
+ code => 'my @a = ()',
+ },
+ 'expr::aassign::lax_empty' => {
+ desc => 'non-empty lexical array assigned empty',
+ setup => 'my @a = 1..3;',
+ code => '@a = ()',
+ },
+ 'expr::aassign::llax_empty' => {
+ desc => 'non-empty lexical var and array assigned empty',
+ setup => 'my ($x, @a) = 1..4;',
+ code => '($x, @a) = ()',
+ },
+ 'expr::aassign::3m_empty' => {
+ desc => 'three my vars assigned empty',
+ setup => '',
+ code => 'my ($x,$y,$z) = ()',
+ },
+ 'expr::aassign::3l_empty' => {
+ desc => 'three lexical vars assigned empty',
+ setup => 'my ($x,$y,$z)',
+ code => '($x,$y,$z) = ()',
+ },
+ 'expr::aassign::pa_empty' => {
+ desc => 'package array assigned empty',
+ setup => '',
+ code => '@a = ()',
+ },
+ 'expr::aassign::pax_empty' => {
+ desc => 'non-empty package array assigned empty',
+ setup => '@a = (1,2,3)',
+ code => '@a = ()',
+ },
+ 'expr::aassign::3p_empty' => {
+ desc => 'three package vars assigned empty',
+ setup => '($x,$y,$z) = 1..3;',
+ code => '($x,$y,$z) = ()',
+ },
+
+ # (....) = (1,2,3)
+
+ 'expr::aassign::ma_3c' => {
+ desc => 'my array assigned 3 consts',
+ setup => '',
+ code => 'my @a = (1,2,3)',
+ },
+ 'expr::aassign::lax_3c' => {
+ desc => 'non-empty lexical array assigned 3 consts',
+ setup => 'my @a = 1..3;',
+ code => '@a = (1,2,3)',
+ },
+ 'expr::aassign::llax_3c' => {
+ desc => 'non-empty lexical var and array assigned 3 consts',
+ setup => 'my ($x, @a) = 1..4;',
+ code => '($x, @a) = (1,2,3)',
+ },
+ 'expr::aassign::3m_3c' => {
+ desc => 'three my vars assigned 3 consts',
+ setup => '',
+ code => 'my ($x,$y,$z) = (1,2,3)',
+ },
+ 'expr::aassign::3l_3c' => {
+ desc => 'three lexical vars assigned 3 consts',
+ setup => 'my ($x,$y,$z)',
+ code => '($x,$y,$z) = (1,2,3)',
+ },
+ 'expr::aassign::pa_3c' => {
+ desc => 'package array assigned 3 consts',
+ setup => '',
+ code => '@a = (1,2,3)',
+ },
+ 'expr::aassign::pax_3c' => {
+ desc => 'non-empty package array assigned 3 consts',
+ setup => '@a = (1,2,3)',
+ code => '@a = (1,2,3)',
+ },
+ 'expr::aassign::3p_3c' => {
+ desc => 'three package vars assigned 3 consts',
+ setup => '($x,$y,$z) = 1..3;',
+ code => '($x,$y,$z) = (1,2,3)',
+ },
+
+ # (....) = @lexical
+
+ 'expr::aassign::ma_la' => {
+ desc => 'my array assigned lexical array',
+ setup => 'my @init = 1..3;',
+ code => 'my @a = @init',
+ },
+ 'expr::aassign::lax_la' => {
+ desc => 'non-empty lexical array assigned lexical array',
+ setup => 'my @init = 1..3; my @a = 1..3;',
+ code => '@a = @init',
+ },
+ 'expr::aassign::llax_la' => {
+ desc => 'non-empty lexical var and array assigned lexical array',
+ setup => 'my @init = 1..3; my ($x, @a) = 1..4;',
+ code => '($x, @a) = @init',
+ },
+ 'expr::aassign::3m_la' => {
+ desc => 'three my vars assigned lexical array',
+ setup => 'my @init = 1..3;',
+ code => 'my ($x,$y,$z) = @init',
+ },
+ 'expr::aassign::3l_la' => {
+ desc => 'three lexical vars assigned lexical array',
+ setup => 'my @init = 1..3; my ($x,$y,$z)',
+ code => '($x,$y,$z) = @init',
+ },
+ 'expr::aassign::pa_la' => {
+ desc => 'package array assigned lexical array',
+ setup => 'my @init = 1..3;',
+ code => '@a = @init',
+ },
+ 'expr::aassign::pax_la' => {
+ desc => 'non-empty package array assigned lexical array',
+ setup => 'my @init = 1..3; @a = @init',
+ code => '@a = @init',
+ },
+ 'expr::aassign::3p_la' => {
+ desc => 'three package vars assigned lexical array',
+ setup => 'my @init = 1..3; ($x,$y,$z) = 1..3;',
+ code => '($x,$y,$z) = @init',
+ },
+
+ # (....) = @package
+
+ 'expr::aassign::ma_pa' => {
+ desc => 'my array assigned package array',
+ setup => '@init = 1..3;',
+ code => 'my @a = @init',
+ },
+ 'expr::aassign::lax_pa' => {
+ desc => 'non-empty lexical array assigned package array',
+ setup => '@init = 1..3; my @a = 1..3;',
+ code => '@a = @init',
+ },
+ 'expr::aassign::llax_pa' => {
+ desc => 'non-empty lexical var and array assigned package array',
+ setup => '@init = 1..3; my ($x, @a) = 1..4;',
+ code => '($x, @a) = @init',
+ },
+ 'expr::aassign::3m_pa' => {
+ desc => 'three my vars assigned package array',
+ setup => '@init = 1..3;',
+ code => 'my ($x,$y,$z) = @init',
+ },
+ 'expr::aassign::3l_pa' => {
+ desc => 'three lexical vars assigned package array',
+ setup => '@init = 1..3; my ($x,$y,$z)',
+ code => '($x,$y,$z) = @init',
+ },
+ 'expr::aassign::pa_pa' => {
+ desc => 'package array assigned package array',
+ setup => '@init = 1..3;',
+ code => '@a = @init',
+ },
+ 'expr::aassign::pax_pa' => {
+ desc => 'non-empty package array assigned package array',
+ setup => '@init = 1..3; @a = @init',
+ code => '@a = @init',
+ },
+ 'expr::aassign::3p_pa' => {
+ desc => 'three package vars assigned package array',
+ setup => '@init = 1..3; ($x,$y,$z) = 1..3;',
+ code => '($x,$y,$z) = @init',
+ },
+
+ # (....) = @_;
+
+ 'expr::aassign::ma_defary' => {
+ desc => 'my array assigned @_',
+ setup => '@_ = 1..3;',
+ code => 'my @a = @_',
+ },
+ 'expr::aassign::lax_defary' => {
+ desc => 'non-empty lexical array assigned @_',
+ setup => '@_ = 1..3; my @a = 1..3;',
+ code => '@a = @_',
+ },
+ 'expr::aassign::llax_defary' => {
+ desc => 'non-empty lexical var and array assigned @_',
+ setup => '@_ = 1..3; my ($x, @a) = 1..4;',
+ code => '($x, @a) = @_',
+ },
+ 'expr::aassign::3m_defary' => {
+ desc => 'three my vars assigned @_',
+ setup => '@_ = 1..3;',
+ code => 'my ($x,$y,$z) = @_',
+ },
+ 'expr::aassign::3l_defary' => {
+ desc => 'three lexical vars assigned @_',
+ setup => '@_ = 1..3; my ($x,$y,$z)',
+ code => '($x,$y,$z) = @_',
+ },
+ 'expr::aassign::pa_defary' => {
+ desc => 'package array assigned @_',
+ setup => '@_ = 1..3;',
+ code => '@a = @_',
+ },
+ 'expr::aassign::pax_defary' => {
+ desc => 'non-empty package array assigned @_',
+ setup => '@_ = 1..3; @a = @_',
+ code => '@a = @_',
+ },
+ 'expr::aassign::3p_defary' => {
+ desc => 'three package vars assigned @_',
+ setup => '@_ = 1..3; ($x,$y,$z) = 1..3;',
+ code => '($x,$y,$z) = @_',
+ },
+
+
+ # (....) = ($lex1,$lex2,$lex3);
+
+ 'expr::aassign::ma_3l' => {
+ desc => 'my array assigned lexicals',
+ setup => 'my ($v1,$v2,$v3) = 1..3;',
+ code => 'my @a = ($v1,$v2,$v3)',
+ },
+ 'expr::aassign::lax_3l' => {
+ desc => 'non-empty lexical array assigned lexicals',
+ setup => 'my ($v1,$v2,$v3) = 1..3; my @a = 1..3;',
+ code => '@a = ($v1,$v2,$v3)',
+ },
+ 'expr::aassign::llax_3l' => {
+ desc => 'non-empty lexical var and array assigned lexicals',
+ setup => 'my ($v1,$v2,$v3) = 1..3; my ($x, @a) = 1..4;',
+ code => '($x, @a) = ($v1,$v2,$v3)',
+ },
+ 'expr::aassign::3m_3l' => {
+ desc => 'three my vars assigned lexicals',
+ setup => 'my ($v1,$v2,$v3) = 1..3;',
+ code => 'my ($x,$y,$z) = ($v1,$v2,$v3)',
+ },
+ 'expr::aassign::3l_3l' => {
+ desc => 'three lexical vars assigned lexicals',
+ setup => 'my ($v1,$v2,$v3) = 1..3; my ($x,$y,$z)',
+ code => '($x,$y,$z) = ($v1,$v2,$v3)',
+ },
+ 'expr::aassign::pa_3l' => {
+ desc => 'package array assigned lexicals',
+ setup => 'my ($v1,$v2,$v3) = 1..3;',
+ code => '@a = ($v1,$v2,$v3)',
+ },
+ 'expr::aassign::pax_3l' => {
+ desc => 'non-empty package array assigned lexicals',
+ setup => 'my ($v1,$v2,$v3) = 1..3; @a = @_',
+ code => '@a = ($v1,$v2,$v3)',
+ },
+ 'expr::aassign::3p_3l' => {
+ desc => 'three package vars assigned lexicals',
+ setup => 'my ($v1,$v2,$v3) = 1..3; ($x,$y,$z) = 1..3;',
+ code => '($x,$y,$z) = ($v1,$v2,$v3)',
+ },
+
+
+ # (....) = ($pkg1,$pkg2,$pkg3);
+
+ 'expr::aassign::ma_3p' => {
+ desc => 'my array assigned 3 package vars',
+ setup => '($v1,$v2,$v3) = 1..3;',
+ code => 'my @a = ($v1,$v2,$v3)',
+ },
+ 'expr::aassign::lax_3p' => {
+ desc => 'non-empty lexical array assigned 3 package vars',
+ setup => '($v1,$v2,$v3) = 1..3; my @a = 1..3;',
+ code => '@a = ($v1,$v2,$v3)',
+ },
+ 'expr::aassign::llax_3p' => {
+ desc => 'non-empty lexical var and array assigned 3 package vars',
+ setup => '($v1,$v2,$v3) = 1..3; my ($x, @a) = 1..4;',
+ code => '($x, @a) = ($v1,$v2,$v3)',
+ },
+ 'expr::aassign::3m_3p' => {
+ desc => 'three my vars assigned 3 package vars',
+ setup => '($v1,$v2,$v3) = 1..3;',
+ code => 'my ($x,$y,$z) = ($v1,$v2,$v3)',
+ },
+ 'expr::aassign::3l_3p' => {
+ desc => 'three lexical vars assigned 3 package vars',
+ setup => '($v1,$v2,$v3) = 1..3; my ($x,$y,$z)',
+ code => '($x,$y,$z) = ($v1,$v2,$v3)',
+ },
+ 'expr::aassign::pa_3p' => {
+ desc => 'package array assigned 3 package vars',
+ setup => '($v1,$v2,$v3) = 1..3;',
+ code => '@a = ($v1,$v2,$v3)',
+ },
+ 'expr::aassign::pax_3p' => {
+ desc => 'non-empty package array assigned 3 package vars',
+ setup => '($v1,$v2,$v3) = 1..3; @a = @_',
+ code => '@a = ($v1,$v2,$v3)',
+ },
+ 'expr::aassign::3p_3p' => {
+ desc => 'three package vars assigned 3 package vars',
+ setup => '($v1,$v2,$v3) = 1..3; ($x,$y,$z) = 1..3;',
+ code => '($x,$y,$z) = ($v1,$v2,$v3)',
+ },
+
+
+ # (....) = (1,2,$shared);
+
+ 'expr::aassign::llax_2c1s' => {
+ desc => 'non-empty lexical var and array assigned 2 consts and 1 shared var',
+ setup => 'my ($x, @a) = 1..4;',
+ code => '($x, @a) = (1,2,$x)',
+ },
+ 'expr::aassign::3l_2c1s' => {
+ desc => 'three lexical vars assigned 2 consts and 1 shared var',
+ setup => 'my ($x,$y,$z) = 1..3;',
+ code => '($x,$y,$z) = (1,2,$x)',
+ },
+ 'expr::aassign::3p_2c1s' => {
+ desc => 'three package vars assigned 2 consts and 1 shared var',
+ setup => '($x,$y,$z) = 1..3;',
+ code => '($x,$y,$z) = (1,2,$x)',
+ },
+
+
+ # ($a,$b) = ($b,$a);
+
+ 'expr::aassign::2l_swap' => {
+ desc => 'swap two lexical vars',
+ setup => 'my ($a,$b) = (1,2)',
+ code => '($a,$b) = ($b,$a)',
+ },
+ 'expr::aassign::2p_swap' => {
+ desc => 'swap two package vars',
+ setup => '($a,$b) = (1,2)',
+ code => '($a,$b) = ($b,$a)',
+ },
+ 'expr::aassign::2laelem_swap' => {
+ desc => 'swap two lexical vars',
+ setup => 'my @a = (1,2)',
+ code => '($a[0],$a[1]) = ($a[1],$a[0])',
+ },
+
+ # misc list assign
+
+ 'expr::aassign::5l_4l1s' => {
+ desc => 'long list of lexical vars, 1 shared',
+ setup => 'my ($a,$b,$c,$d,$e) = 1..5',
+ code => '($a,$b,$c,$d,$e) = ($a,$a,$c,$d,$e)',
+ },
+
+ 'expr::aassign::5p_4p1s' => {
+ desc => 'long list of package vars, 1 shared',
+ setup => '($a,$b,$c,$d,$e) = 1..5',
+ code => '($a,$b,$c,$d,$e) = ($a,$a,$c,$d,$e)',
+ },
+ 'expr::aassign::5l_defary' => {
+ desc => 'long list of lexical vars to assign @_ to',
+ setup => '@_ = 1..5',
+ code => 'my ($a,$b,$c,$d,$e) = @_',
+ },
+ 'expr::aassign::5l1la_defary' => {
+ desc => 'long list of lexical vars plus long slurp to assign @_ to',
+ setup => '@_ = 1..20',
+ code => 'my ($a,$b,$c,$d,$e,@rest) = @_',
+ },
+
+
];
diff --git a/t/perf/optree.t b/t/perf/optree.t
index 7e3a06e14a..40d2091ac7 100644
--- a/t/perf/optree.t
+++ b/t/perf/optree.t
@@ -10,26 +10,84 @@ BEGIN {
@INC = '../lib';
}
-plan 24;
+plan 51;
use v5.10; # state
-use B qw 'svref_2object OPpASSIGN_COMMON';
-
+use B qw(svref_2object
+ OPpASSIGN_COMMON_SCALAR
+ OPpASSIGN_COMMON_RC1
+ OPpASSIGN_COMMON_AGG
+ );
+
+
+# Test that OP_AASSIGN gets the appropriate
+# OPpASSIGN_COMMON* flags set.
+#
+# Too few flags set is likely to cause code to misbehave;
+# too many flags set unnecessarily slows things down.
+# See also the tests in t/op/aassign.t
+
+for my $test (
+ # Each anon array contains:
+ # [
+ # expected flags:
+ # a 3 char string, each char showing whether we expect a
+ # particular flag to be set:
+ # '-' indicates any char not set, while
+ # 'S': char 0: OPpASSIGN_COMMON_SCALAR,
+ # 'R': char 1: OPpASSIGN_COMMON_RC1,
+ # 'A' char 2: OPpASSIGN_COMMON_AGG,
+ # code to eval,
+ # description,
+ # ]
+
+ [ "---", '() = (1, $x, my $y, @z, f($p))', 'no LHS' ],
+ [ "---", '(undef, $x, my $y, @z, ($a ? $b : $c)) = ()', 'no RHS' ],
+ [ "---", '(undef, $x, my $y, @z, ($a ? $b : $c)) = (1,2)', 'safe RHS' ],
+ [ "---", 'my @a = (1,2)', 'safe RHS: my array' ],
+ [ "---", 'my %h = (1,2)', 'safe RHS: my hash' ],
+ [ "---", 'my ($a,$b,$c,$d) = 1..6; ($a,$b) = ($c,$d);', 'non-common lex' ],
+ [ "---", '($x,$y) = (1,2)', 'pkg var LHS only' ],
+ [ "---", 'my $p; my ($x,$y) = ($p, $p)', 'my; dup lex var on RHS' ],
+ [ "---", 'my $p; my ($x,$y); ($x,$y) = ($p, $p)', 'dup lex var on RHS' ],
+ [ "-R-", 'my ($self) = @_', 'LHS lex scalar only' ],
+ [ "-RA", 'my ($self, @rest) = @_', 'LHS lex mixed' ],
+ [ "-R-", 'my ($x,$y) = ($p, $q)', 'pkg var RHS only' ],
+ [ "S--", '($x,$y) = ($p, $q)', 'pkg scalar both sides' ],
+ [ "--A", 'my (@a, @b); @a = @b', 'lex ary both sides' ],
+ [ "-R-", 'my ($x,$y,$z,@a); ($x,$y,$z) = @a ', 'lex vars to lex ary' ],
+ [ "--A", '@a = @b', 'pkg ary both sides' ],
+ [ "--A", 'my (%a,%b); %a = %b', 'lex hash both sides' ],
+ [ "--A", '%a = %b', 'pkg hash both sides' ],
+ [ "--A", 'my $x; @a = ($a[0], $a[$x])', 'common ary' ],
+ [ "--A", 'my ($x,@a); @a = ($a[0], $a[$x])', 'common lex ary' ],
+ [ "S-A", 'my $x; ($a[$x], $a[0]) = ($a[0], $a[$x])', 'common ary elems' ],
+ [ "S-A", 'my ($x,@a); ($a[$x], $a[0]) = ($a[0], $a[$x])',
+ 'common lex ary elems' ],
+ [ "--A", 'my $x; my @a = @$x', 'lex ary may have stuff' ],
+ [ "-RA", 'my $x; my ($b, @a) = @$x', 'lex ary may have stuff' ],
+ [ "--A", 'my $x; my %a = @$x', 'lex hash may have stuff' ],
+ [ "-RA", 'my $x; my ($b, %a) = @$x', 'lex hash may have stuff' ],
+ [ "--A", 'my (@a,@b); @a = ($b[0])', 'lex ary and elem' ],
+ [ "S-A", 'my @a; ($a[1],$a[0]) = @a', 'lex ary and elem' ],
+ [ "--A", 'my @x; @y = $x[0]', 'pkg ary from lex elem' ],
+) {
+ my ($exp, $code, $desc) = @$test;
+ my $sub = eval "sub { $code }"
+ or die
+ "aassign eval('$code') failed: this test needs to be rewritten:\n"
+ . $@;
-# aassign with no common vars
-for ('my ($self) = @_',
- 'my @x; @y = $x[0]', # aelemfast_lex
- )
-{
- my $sub = eval "sub { $_ }";
- my $last_expr =
- svref_2object($sub)->ROOT->first->last;
+ my $last_expr = svref_2object($sub)->ROOT->first->last;
if ($last_expr->name ne 'aassign') {
die "Expected aassign but found ", $last_expr->name,
"; this test needs to be rewritten"
}
- is $last_expr->private & OPpASSIGN_COMMON, 0,
- "no ASSIGN_COMMON for $_";
+ my $got =
+ (($last_expr->private & OPpASSIGN_COMMON_SCALAR) ? 'S' : '-')
+ . (($last_expr->private & OPpASSIGN_COMMON_RC1) ? 'R' : '-')
+ . (($last_expr->private & OPpASSIGN_COMMON_AGG) ? 'A' : '-');
+ is $got, $exp, "OPpASSIGN_COMMON: $desc: '$code'";
}