keys(%h) was special in that it did not use the same code path as
other ops that distinguish between scalar and list lvalue context.
Consequently, some scalar lvalue contexts worked:
keys %h = 3;
${\scalar keys %h} = 3;
sub { $_[0] = 3 }->(scalar keys %h);
foreach(scalar keys %h) { $_ = 3 }
grep { $_ = 3 } scalar keys %h;
substr keys %h, 0, = 3;
while others did not:
keys %h .= 0;
read FH, keys %h, 0;
Fixing other bugs in the same code paths without breaking keys (or
adding *more* exceptions) is harder to do if keys is not consistent.
So this commit allows .= and read to assign to keys, by using the same
internal code (scalar_mod_type) that determines whether %h assignment
is allowed. The logic is reversed (since %h is list-only and keys %h
is scalar-only), so where %h is a valid lvalue keys %h is not, and
vice versa.
break;
case OP_KEYS:
- if (type != OP_SASSIGN && type != OP_LEAVESUBLV)
+ if (type != OP_LEAVESUBLV && !scalar_mod_type(NULL, type))
goto nomod;
goto lvalue_func;
case OP_SUBSTR:
chdir 't' if -d 't';
}
-print "1..182\n";
+print "1..185\n";
sub failed {
my ($got, $expected, $name) = @_;
like $@, qr/^Version control conflict marker at \(eval \d+\) line 3, near "$marker"/, "VCS marker '$marker' after operator";
}
+# keys assignments in weird contexts (mentioned in perl #128260)
+eval 'keys(%h) .= "00"';
+is $@, "", 'keys .=';
+eval 'sub { read $fh, keys %h, 0 }';
+is $@, "", 'read into keys';
+eval 'substr keys(%h),0,=3';
+is $@, "", 'substr keys assignment';
# Add new tests HERE (above this line)