# New Ticket Created by Ron Schmidt # Please include the string: [perl #62948] # in the subject line of all future correspondence about this issue. # <URL: http://rt.perl.org/rt3/Ticket/Display.html?id=62948 >
This is a follow up to rt #61324 that observed, among other things, that 'my @a; @a[2] = "b"; say @a' crashed with a null PMC error. rt #61324 was closed and that problem was fixed but a closer look revealed a number of seemingly related problems that were not. If the program started with 'my @a; @a[1] = "b"' several other cases like 'my @b = @a;', 'my @b = ("c", @a);', 'my $x = + @a.grep({ $_ eq "b"})', and 'my $x = @a.min()' all crashed with null PMC errors even after #61324 patches. It seems that when you take some slurpy params like say/print and grep, min, join etc. with a declaration like that below .param pmc args :slurpy your args are allocated as a ResizablePMCArray. List.pir registers itself as a parent class of ResizablePMCArray and effectively provides the '!flatten' method for the args in such a case. When the List.pir '!flatten' method sees a perl array (Perl6Array) it calls splice to flatten and append it to the result set. The ResizablePMCArray get_pmc_keyed_int vtable function, called by splice, was appending PMCNULL values to the results and causing the crashes. ResizablePMCArray is an ancestor of Perl6Array. The array assignments like 'my @a; @a[1] = "b"; my @b = @a' where also calling the same '!flatten’ method. The patch I include here provides a reasonably simple, pir based, get_pmc_keyed_int vtable function in Array.pir that seems to fix all of the above problems without breaking anything. There are other possible approaches to the problem. Since it also fixes the problem with print/say I also include a patch to remove the changes to print that are no longer needed. Tests for related conditions were already in array_extending.t so I include a patch that puts more tests there including the problem cases noted above. It seems to me that the tests in array_extending.t are really autovivification tests that might belong in the S09-autovivification directory. I also include a patch that tentatively removes some autovivification code from Positional.pir since my patch to Array.pir covers all test cases, the autovivification of rvalue Positional references was a problem in the existing code and it is not clear to me whether the Positional role is intended to do autovivification going forward. The patch to Array.pir includes a comment noting the problems with rvalue autovivification similar to those described for hashes in rt #61882. I expect to be boarding a flight to Mexico tomorrow but expect to be able to get some access to email by WIFI next week. Hope some of this helps, Ron
Index: t/spec/S02-builtin_data_types/array_extending.t =================================================================== --- t/spec/S02-builtin_data_types/array_extending.t (revision 25127) +++ t/spec/S02-builtin_data_types/array_extending.t (working copy) @@ -2,7 +2,7 @@ use Test; -plan 16; +plan 21; { # Compare with Perl 5: @@ -86,3 +86,19 @@ ok @a[1] ~~ undef, '... and the second is undef'; is @a[2], 6, '... and the third is 6'; } + +{ + my @a; + @a[2] = 'b'; + my @b = @a; + is +...@b, 3, 'really a degenerative case of assigning list to array'; + @b = (6, @a); + is +...@b, 4, 'assigning list with extended array to an array'; + my $s = @a.join(':'); + is $s, '::b', 'join on extended array'; + my $n = + @a.grep({ $_ eq 'b'}); + is $n, 1, 'grep on extended array'; + @a[1] = 'c'; # cmp doesn't handle undef cmp undef yet + my $m = @a.min(); + ok not defined $m, 'min on list with undefined el returns undef'; +} Index: src/classes/Array.pir =================================================================== --- src/classes/Array.pir (revision 36120) +++ src/classes/Array.pir (working copy) @@ -30,7 +30,9 @@ .namespace ['Perl6Array'] .sub 'delete' :method :multi(Perl6Array) .param pmc indices :slurpy - .local pmc result + .local pmc super_class_accessor, result + + super_class_accessor = getattribute self, ['ResizablePMCArray'], 'proxy' result = new 'List' null $P99 @@ -47,7 +49,7 @@ dec $I0 shorten_loop: if $I0 < 0 goto shorten_end - $P0 = self[$I0] + $P0 = super_class_accessor[$I0] unless null $P0 goto shorten_end delete self[$I0] dec $I0 @@ -267,6 +269,29 @@ =cut +=item get_pmc_keyed_int() (vtable method) + +Try to return undef/Failure rather than null for null index. Also +autovivifies for now. + +=cut + +# autovivification will happen here for rvalues which will need fixing later ... + +.sub get_pmc_keyed_int :vtable :method + .param int key + .local pmc super_class_accessor, retval + + super_class_accessor = getattribute self, ['ResizablePMCArray'], 'proxy' + retval = super_class_accessor[ key ] + unless null retval goto done + retval = 'undef'() + super_class_accessor[ key ] = retval +done: + .return (retval) +.end + + # Local Variables: # mode: pir # fill-column: 100 Index: src/classes/Positional.pir =================================================================== --- src/classes/Positional.pir (revision 36120) +++ src/classes/Positional.pir (working copy) @@ -46,9 +46,10 @@ goto end result_fetch: result = self[$I0] - unless null result goto end - result = 'undef'() - self[$I0] = result +# -- not clear on whether autovivication is part of positional role (maybe?) -- +# unless null result goto end +# result = 'undef'() +# self[$I0] = result goto end result_whatever: result = 'list'(self) Index: src/builtins/io.pir =================================================================== --- src/builtins/io.pir (revision 36120) +++ src/builtins/io.pir (working copy) @@ -20,9 +20,6 @@ iter_loop: unless it goto iter_end $P0 = shift it - unless null $P0 goto iter_nonull - $P0 = new 'Failure' - iter_nonull: print $P0 goto iter_loop iter_end: