1850e2753Smillert#!./perl 2850e2753Smillert 36fb12b70Safresh1BEGIN { 4b8851fccSafresh1 chdir 't' if -d 't'; 56fb12b70Safresh1 require q(./test.pl); 6*9f11ffb7Safresh1 set_up_inc('../lib'); 76fb12b70Safresh1} 8b8851fccSafresh1 9b8851fccSafresh1use strict; 10b8851fccSafresh1use warnings; 11b8851fccSafresh1 12b8851fccSafresh1plan(tests => 66); 1343003dfeSmillert 1443003dfeSmillertrequire mro; 15850e2753Smillert 16850e2753Smillert{ 17850e2753Smillert package MRO_A; 18850e2753Smillert our @ISA = qw//; 19850e2753Smillert package MRO_B; 20850e2753Smillert our @ISA = qw//; 21850e2753Smillert package MRO_C; 22850e2753Smillert our @ISA = qw//; 23850e2753Smillert package MRO_D; 24850e2753Smillert our @ISA = qw/MRO_A MRO_B MRO_C/; 25850e2753Smillert package MRO_E; 26850e2753Smillert our @ISA = qw/MRO_A MRO_B MRO_C/; 27850e2753Smillert package MRO_F; 28850e2753Smillert our @ISA = qw/MRO_D MRO_E/; 29850e2753Smillert} 30850e2753Smillert 31850e2753Smillertmy @MFO_F_DFS = qw/MRO_F MRO_D MRO_A MRO_B MRO_C MRO_E/; 32850e2753Smillertmy @MFO_F_C3 = qw/MRO_F MRO_D MRO_E MRO_A MRO_B MRO_C/; 33850e2753Smillertis(mro::get_mro('MRO_F'), 'dfs'); 34850e2753Smillertok(eq_array( 35850e2753Smillert mro::get_linear_isa('MRO_F'), \@MFO_F_DFS 36850e2753Smillert)); 37850e2753Smillert 38850e2753Smillertok(eq_array(mro::get_linear_isa('MRO_F', 'dfs'), \@MFO_F_DFS)); 39850e2753Smillertok(eq_array(mro::get_linear_isa('MRO_F', 'c3'), \@MFO_F_C3)); 40850e2753Smillerteval{mro::get_linear_isa('MRO_F', 'C3')}; 41850e2753Smillertlike($@, qr/^Invalid mro name: 'C3'/); 42850e2753Smillert 43850e2753Smillertmro::set_mro('MRO_F', 'c3'); 44850e2753Smillertis(mro::get_mro('MRO_F'), 'c3'); 45850e2753Smillertok(eq_array( 46850e2753Smillert mro::get_linear_isa('MRO_F'), \@MFO_F_C3 47850e2753Smillert)); 48850e2753Smillert 49850e2753Smillertok(eq_array(mro::get_linear_isa('MRO_F', 'dfs'), \@MFO_F_DFS)); 50850e2753Smillertok(eq_array(mro::get_linear_isa('MRO_F', 'c3'), \@MFO_F_C3)); 51850e2753Smillerteval{mro::get_linear_isa('MRO_F', 'C3')}; 52850e2753Smillertlike($@, qr/^Invalid mro name: 'C3'/); 53850e2753Smillert 54850e2753Smillertmy @isarev = sort { $a cmp $b } @{mro::get_isarev('MRO_B')}; 55850e2753Smillertok(eq_array( 56850e2753Smillert \@isarev, 57850e2753Smillert [qw/MRO_D MRO_E MRO_F/] 58850e2753Smillert)); 59850e2753Smillert 60850e2753Smillertok(!mro::is_universal('MRO_B')); 61850e2753Smillert 62850e2753Smillert@UNIVERSAL::ISA = qw/MRO_F/; 63850e2753Smillertok(mro::is_universal('MRO_B')); 64850e2753Smillert 65850e2753Smillert@UNIVERSAL::ISA = (); 66898184e3Ssthenok(!mro::is_universal('MRO_B')); 67850e2753Smillert 68850e2753Smillert# is_universal, get_mro, and get_linear_isa should 69898184e3Ssthen# handle non-existent packages sanely 70850e2753Smillertok(!mro::is_universal('Does_Not_Exist')); 71850e2753Smillertis(mro::get_mro('Also_Does_Not_Exist'), 'dfs'); 72850e2753Smillertok(eq_array( 73850e2753Smillert mro::get_linear_isa('Does_Not_Exist_Three'), 74850e2753Smillert [qw/Does_Not_Exist_Three/] 75850e2753Smillert)); 76850e2753Smillert 77850e2753Smillert# Assigning @ISA via globref 78850e2753Smillert{ 79850e2753Smillert package MRO_TestBase; 80850e2753Smillert sub testfunc { return 123 } 81850e2753Smillert package MRO_TestOtherBase; 82850e2753Smillert sub testfunctwo { return 321 } 83850e2753Smillert package MRO_M; our @ISA = qw/MRO_TestBase/; 84850e2753Smillert} 85850e2753Smillert*MRO_N::ISA = *MRO_M::ISA; 86850e2753Smillertis(eval { MRO_N->testfunc() }, 123); 87850e2753Smillert 88850e2753Smillert# XXX TODO (when there's a way to backtrack through a glob's aliases) 89850e2753Smillert# push(@MRO_M::ISA, 'MRO_TestOtherBase'); 90850e2753Smillert# is(eval { MRO_N->testfunctwo() }, 321); 91850e2753Smillert 92850e2753Smillert# Simple DESTROY Baseline 93850e2753Smillert{ 94850e2753Smillert my $x = 0; 95850e2753Smillert my $obj; 96850e2753Smillert 97850e2753Smillert { 98850e2753Smillert package DESTROY_MRO_Baseline; 99850e2753Smillert sub new { bless {} => shift } 100850e2753Smillert sub DESTROY { $x++ } 101850e2753Smillert 102850e2753Smillert package DESTROY_MRO_Baseline_Child; 103850e2753Smillert our @ISA = qw/DESTROY_MRO_Baseline/; 104850e2753Smillert } 105850e2753Smillert 106850e2753Smillert $obj = DESTROY_MRO_Baseline->new(); 107850e2753Smillert undef $obj; 108850e2753Smillert is($x, 1); 109850e2753Smillert 110850e2753Smillert $obj = DESTROY_MRO_Baseline_Child->new(); 111850e2753Smillert undef $obj; 112850e2753Smillert is($x, 2); 113850e2753Smillert} 114850e2753Smillert 115850e2753Smillert# Dynamic DESTROY 116850e2753Smillert{ 117850e2753Smillert my $x = 0; 118850e2753Smillert my $obj; 119850e2753Smillert 120850e2753Smillert { 121850e2753Smillert package DESTROY_MRO_Dynamic; 122850e2753Smillert sub new { bless {} => shift } 123850e2753Smillert 124850e2753Smillert package DESTROY_MRO_Dynamic_Child; 125850e2753Smillert our @ISA = qw/DESTROY_MRO_Dynamic/; 126850e2753Smillert } 127850e2753Smillert 128850e2753Smillert $obj = DESTROY_MRO_Dynamic->new(); 129850e2753Smillert undef $obj; 130850e2753Smillert is($x, 0); 131850e2753Smillert 132850e2753Smillert $obj = DESTROY_MRO_Dynamic_Child->new(); 133850e2753Smillert undef $obj; 134850e2753Smillert is($x, 0); 135850e2753Smillert 136850e2753Smillert no warnings 'once'; 137850e2753Smillert *DESTROY_MRO_Dynamic::DESTROY = sub { $x++ }; 138850e2753Smillert 139850e2753Smillert $obj = DESTROY_MRO_Dynamic->new(); 140850e2753Smillert undef $obj; 141850e2753Smillert is($x, 1); 142850e2753Smillert 143850e2753Smillert $obj = DESTROY_MRO_Dynamic_Child->new(); 144850e2753Smillert undef $obj; 145850e2753Smillert is($x, 2); 146850e2753Smillert} 147850e2753Smillert 148850e2753Smillert# clearing @ISA in different ways 149850e2753Smillert# some are destructive to the package, hence the new 150850e2753Smillert# package name each time 151850e2753Smillert{ 152850e2753Smillert no warnings 'uninitialized'; 153850e2753Smillert { 154850e2753Smillert package ISACLEAR; 155850e2753Smillert our @ISA = qw/XX YY ZZ/; 156850e2753Smillert } 157850e2753Smillert # baseline 158850e2753Smillert ok(eq_array(mro::get_linear_isa('ISACLEAR'),[qw/ISACLEAR XX YY ZZ/])); 159850e2753Smillert 160850e2753Smillert # this looks dumb, but it preserves existing behavior for compatibility 161850e2753Smillert # (undefined @ISA elements treated as "main") 162850e2753Smillert $ISACLEAR::ISA[1] = undef; 163850e2753Smillert ok(eq_array(mro::get_linear_isa('ISACLEAR'),[qw/ISACLEAR XX main ZZ/])); 164850e2753Smillert 165850e2753Smillert # undef the array itself 166850e2753Smillert undef @ISACLEAR::ISA; 167850e2753Smillert ok(eq_array(mro::get_linear_isa('ISACLEAR'),[qw/ISACLEAR/])); 168850e2753Smillert 169850e2753Smillert # Now, clear more than one package's @ISA at once 170850e2753Smillert { 171850e2753Smillert package ISACLEAR1; 172850e2753Smillert our @ISA = qw/WW XX/; 173850e2753Smillert 174850e2753Smillert package ISACLEAR2; 175850e2753Smillert our @ISA = qw/YY ZZ/; 176850e2753Smillert } 177850e2753Smillert # baseline 178850e2753Smillert ok(eq_array(mro::get_linear_isa('ISACLEAR1'),[qw/ISACLEAR1 WW XX/])); 179850e2753Smillert ok(eq_array(mro::get_linear_isa('ISACLEAR2'),[qw/ISACLEAR2 YY ZZ/])); 180850e2753Smillert (@ISACLEAR1::ISA, @ISACLEAR2::ISA) = (); 181850e2753Smillert 182850e2753Smillert ok(eq_array(mro::get_linear_isa('ISACLEAR1'),[qw/ISACLEAR1/])); 183850e2753Smillert ok(eq_array(mro::get_linear_isa('ISACLEAR2'),[qw/ISACLEAR2/])); 18443003dfeSmillert 18543003dfeSmillert # [perl #49564] This is a pretty obscure way of clearing @ISA but 18643003dfeSmillert # it tests a regression that affects XS code calling av_clear too. 18743003dfeSmillert { 18843003dfeSmillert package ISACLEAR3; 18943003dfeSmillert our @ISA = qw/WW XX/; 19043003dfeSmillert } 19143003dfeSmillert ok(eq_array(mro::get_linear_isa('ISACLEAR3'),[qw/ISACLEAR3 WW XX/])); 19243003dfeSmillert { 19343003dfeSmillert package ISACLEAR3; 19443003dfeSmillert reset 'I'; 19543003dfeSmillert } 19643003dfeSmillert ok(eq_array(mro::get_linear_isa('ISACLEAR3'),[qw/ISACLEAR3/])); 197850e2753Smillert} 198850e2753Smillert 199850e2753Smillert# Check that recursion bails out "cleanly" in a variety of cases 200850e2753Smillert# (as opposed to say, bombing the interpreter or something) 201850e2753Smillert{ 202850e2753Smillert my @recurse_codes = ( 203850e2753Smillert '@MRO_R1::ISA = "MRO_R2"; @MRO_R2::ISA = "MRO_R1";', 204850e2753Smillert '@MRO_R3::ISA = "MRO_R4"; push(@MRO_R4::ISA, "MRO_R3");', 205850e2753Smillert '@MRO_R5::ISA = "MRO_R6"; @MRO_R6::ISA = qw/XX MRO_R5 YY/;', 206850e2753Smillert '@MRO_R7::ISA = "MRO_R8"; push(@MRO_R8::ISA, qw/XX MRO_R7 YY/)', 207850e2753Smillert ); 208850e2753Smillert foreach my $code (@recurse_codes) { 209850e2753Smillert eval $code; 210850e2753Smillert ok($@ =~ /Recursive inheritance detected/); 211850e2753Smillert } 212850e2753Smillert} 213850e2753Smillert 214850e2753Smillert# Check that SUPER caches get invalidated correctly 215850e2753Smillert{ 216850e2753Smillert { 217850e2753Smillert package SUPERTEST; 218850e2753Smillert sub new { bless {} => shift } 219850e2753Smillert sub foo { $_[1]+1 } 220850e2753Smillert 221850e2753Smillert package SUPERTEST::MID; 222850e2753Smillert our @ISA = 'SUPERTEST'; 223850e2753Smillert 224850e2753Smillert package SUPERTEST::KID; 225850e2753Smillert our @ISA = 'SUPERTEST::MID'; 226850e2753Smillert sub foo { my $s = shift; $s->SUPER::foo(@_) } 227850e2753Smillert 228850e2753Smillert package SUPERTEST::REBASE; 229850e2753Smillert sub foo { $_[1]+3 } 230850e2753Smillert } 231850e2753Smillert 232850e2753Smillert my $stk_obj = SUPERTEST::KID->new(); 233850e2753Smillert is($stk_obj->foo(1), 2); 234850e2753Smillert { no warnings 'redefine'; 235850e2753Smillert *SUPERTEST::foo = sub { $_[1]+2 }; 236850e2753Smillert } 237850e2753Smillert is($stk_obj->foo(2), 4); 238850e2753Smillert @SUPERTEST::MID::ISA = 'SUPERTEST::REBASE'; 239850e2753Smillert is($stk_obj->foo(3), 6); 240850e2753Smillert} 241850e2753Smillert 24243003dfeSmillert{ 24343003dfeSmillert { 24443003dfeSmillert # assigning @ISA via arrayref to globref RT 60220 24543003dfeSmillert package P1; 24643003dfeSmillert sub new { bless {}, shift } 24743003dfeSmillert 24843003dfeSmillert package P2; 24943003dfeSmillert } 25043003dfeSmillert *{P2::ISA} = [ 'P1' ]; 25143003dfeSmillert my $foo = P2->new; 25243003dfeSmillert ok(!eval { $foo->bark }, "no bark method"); 25343003dfeSmillert no warnings 'once'; # otherwise it'll bark about P1::bark used only once 25443003dfeSmillert *{P1::bark} = sub { "[bark]" }; 25543003dfeSmillert is(scalar eval { $foo->bark }, "[bark]", "can bark now"); 25643003dfeSmillert} 257b39c5158Smillert 258b39c5158Smillert{ 259b39c5158Smillert # assigning @ISA via arrayref then modifying it RT 72866 260b39c5158Smillert { 261b39c5158Smillert package Q1; 262b39c5158Smillert sub foo { } 263b39c5158Smillert 264b39c5158Smillert package Q2; 265b39c5158Smillert sub bar { } 266b39c5158Smillert 267b39c5158Smillert package Q3; 268b39c5158Smillert } 269b39c5158Smillert push @Q3::ISA, "Q1"; 270b39c5158Smillert can_ok("Q3", "foo"); 271b39c5158Smillert *Q3::ISA = []; 272b39c5158Smillert push @Q3::ISA, "Q1"; 273b39c5158Smillert can_ok("Q3", "foo"); 274b39c5158Smillert *Q3::ISA = []; 275b39c5158Smillert push @Q3::ISA, "Q2"; 276b39c5158Smillert can_ok("Q3", "bar"); 277b39c5158Smillert ok(!Q3->can("foo"), "can't call foo method any longer"); 278b39c5158Smillert} 279b39c5158Smillert 280b39c5158Smillert{ 281b39c5158Smillert # test mro::method_changed_in 282b39c5158Smillert my $count = mro::get_pkg_gen("MRO_A"); 283b39c5158Smillert mro::method_changed_in("MRO_A"); 284b39c5158Smillert my $count_new = mro::get_pkg_gen("MRO_A"); 285b39c5158Smillert 286b39c5158Smillert is($count_new, $count + 1); 287b39c5158Smillert} 288b39c5158Smillert 289b39c5158Smillert{ 290b39c5158Smillert # test if we can call mro::invalidate_all_method_caches; 291b39c5158Smillert eval { 292b39c5158Smillert mro::invalidate_all_method_caches(); 293b39c5158Smillert }; 294b39c5158Smillert is($@, ""); 295b39c5158Smillert} 296898184e3Ssthen 297898184e3Ssthen{ 298898184e3Ssthen # @main::ISA 299898184e3Ssthen no warnings 'once'; 300898184e3Ssthen @main::ISA = 'parent'; 301898184e3Ssthen my $output = ''; 302898184e3Ssthen *parent::do = sub { $output .= 'parent' }; 303898184e3Ssthen *parent2::do = sub { $output .= 'parent2' }; 304898184e3Ssthen main->do; 305898184e3Ssthen @main::ISA = 'parent2'; 306898184e3Ssthen main->do; 307898184e3Ssthen is $output, 'parentparent2', '@main::ISA is magical'; 308898184e3Ssthen} 309898184e3Ssthen 310898184e3Ssthen{ 311898184e3Ssthen # Undefining *ISA, then modifying @ISA 312898184e3Ssthen # This broke Class::Trait. See [perl #79024]. 313898184e3Ssthen {package Class::Trait::Base} 314898184e3Ssthen no strict 'refs'; 315898184e3Ssthen undef *{"Extra::TSpouse::ISA"}; 316898184e3Ssthen 'Extra::TSpouse'->isa('Class::Trait::Base'); # cache the mro 317898184e3Ssthen unshift @{"Extra::TSpouse::ISA"}, 'Class::Trait::Base'; 318898184e3Ssthen ok 'Extra::TSpouse'->isa('Class::Trait::Base'), 319898184e3Ssthen 'a isa b after undef *a::ISA and @a::ISA modification'; 320898184e3Ssthen} 321898184e3Ssthen 322898184e3Ssthen{ 323898184e3Ssthen # Deleting $package::{ISA} 324898184e3Ssthen # Broken in 5.10.0; fixed in 5.13.7 325898184e3Ssthen @Blength::ISA = 'Bladd'; 326898184e3Ssthen delete $Blength::{ISA}; 327898184e3Ssthen ok !Blength->isa("Bladd"), 'delete $package::{ISA}'; 328898184e3Ssthen} 329898184e3Ssthen 330898184e3Ssthen{ 331898184e3Ssthen # Undefining stashes 332898184e3Ssthen @Thrext::ISA = "Thwit"; 333898184e3Ssthen @Thwit::ISA = "Sile"; 334898184e3Ssthen undef %Thwit::; 335898184e3Ssthen ok !Thrext->isa('Sile'), 'undef %package:: updates subclasses'; 336898184e3Ssthen} 33791f110e0Safresh1 33891f110e0Safresh1{ 33991f110e0Safresh1 # Obliterating @ISA via glob assignment 34091f110e0Safresh1 # Broken in 5.14.0; fixed in 5.17.2 34191f110e0Safresh1 @Gwythaint::ISA = "Fantastic::Creature"; 34291f110e0Safresh1 undef *This_glob_haD_better_not_exist; # paranoia; must have no array 34391f110e0Safresh1 *Gwythaint::ISA = *This_glob_haD_better_not_exist; 34491f110e0Safresh1 ok !Gwythaint->isa("Fantastic::Creature"), 34591f110e0Safresh1 'obliterating @ISA via glob assignment'; 34691f110e0Safresh1} 34791f110e0Safresh1 34891f110e0Safresh1{ 34991f110e0Safresh1 # Autovivifying @ISA via @{*ISA} 35091f110e0Safresh1 no warnings; 35191f110e0Safresh1 undef *fednu::ISA; 35291f110e0Safresh1 @{*fednu::ISA} = "pyfg"; 35391f110e0Safresh1 ok +fednu->isa("pyfg"), 'autovivifying @ISA via *{@ISA}'; 35491f110e0Safresh1} 35591f110e0Safresh1 35691f110e0Safresh1{ 35791f110e0Safresh1 sub Detached::method; 35891f110e0Safresh1 my $h = delete $::{"Detached::"}; 35991f110e0Safresh1 eval { local *Detached::method }; 36091f110e0Safresh1 is $@, "", 'localising gv-with-cv belonging to detached package'; 36191f110e0Safresh1} 36291f110e0Safresh1 36391f110e0Safresh1{ 36491f110e0Safresh1 # *ISA localisation 36591f110e0Safresh1 @il::ISA = "ilsuper"; 36691f110e0Safresh1 sub ilsuper::can { "puree" } 36791f110e0Safresh1 sub il::tomatoes; 36891f110e0Safresh1 { 36991f110e0Safresh1 local *il::ISA; 37091f110e0Safresh1 is +il->can("tomatoes"), \&il::tomatoes, 'local *ISA'; 37191f110e0Safresh1 } 37291f110e0Safresh1 is "il"->can("tomatoes"), "puree", 'local *ISA unwinding'; 37391f110e0Safresh1 { 37491f110e0Safresh1 local *il::ISA = []; 37591f110e0Safresh1 is +il->can("tomatoes"), \&il::tomatoes, 'local *ISA = []'; 37691f110e0Safresh1 } 37791f110e0Safresh1 is "il"->can("tomatoes"), "puree", 'local *ISA=[] unwinding'; 37891f110e0Safresh1} 37991f110e0Safresh1 38091f110e0Safresh1# Changes to UNIVERSAL::DESTROY should not leave stale DESTROY caches 38191f110e0Safresh1# (part of #114864) 38291f110e0Safresh1our $destroy_output; 38391f110e0Safresh1sub UNIVERSAL::DESTROY { $destroy_output = "old" } 38491f110e0Safresh1my $x = bless[]; 38591f110e0Safresh1undef $x; # cache the DESTROY method 38691f110e0Safresh1undef *UNIVERSAL::DESTROY; 38791f110e0Safresh1*UNIVERSAL::DESTROY = sub { $destroy_output = "new" }; 38891f110e0Safresh1$x = bless[]; 38991f110e0Safresh1undef $x; # should use the new DESTROY 39091f110e0Safresh1is $destroy_output, "new", 39191f110e0Safresh1 'Changes to UNIVERSAL::DESTROY invalidate DESTROY caches'; 39291f110e0Safresh1undef *UNIVERSAL::DESTROY; 3936fb12b70Safresh1 3946fb12b70Safresh1{ 3956fb12b70Safresh1 no warnings 'uninitialized'; 3966fb12b70Safresh1 $#_119433::ISA++; 3976fb12b70Safresh1 pass "no crash when ISA contains nonexistent elements"; 3986fb12b70Safresh1} 399b8851fccSafresh1 400b8851fccSafresh1{ # 123788 401b8851fccSafresh1 fresh_perl_is(<<'PROG', "ok", {}, "don't crash when deleting ISA"); 402b8851fccSafresh1$x = \@{q(Foo::ISA)}; 403b8851fccSafresh1delete $Foo::{ISA}; 404b8851fccSafresh1@$x = "Bar"; 405b8851fccSafresh1print "ok\n"; 406b8851fccSafresh1PROG 407b8851fccSafresh1 408b8851fccSafresh1 # when there are multiple references to an ISA array, the mg_obj 409b8851fccSafresh1 # turns into an AV of globs, which is a different code path 410b8851fccSafresh1 # this test only crashes on -DDEBUGGING builds 411b8851fccSafresh1 fresh_perl_is(<<'PROG', "ok", {}, "a case with multiple refs to ISA"); 412b8851fccSafresh1@Foo::ISA = qw(Abc Def); 413b8851fccSafresh1$x = \@{q(Foo::ISA)}; 414b8851fccSafresh1*Bar::ISA = $x; 415b8851fccSafresh1delete $Bar::{ISA}; 416b8851fccSafresh1delete $Foo::{ISA}; 417b8851fccSafresh1++$y; 418b8851fccSafresh1$x->[1] = "Ghi"; 419b8851fccSafresh1@$x = "Bar"; 420b8851fccSafresh1print "ok\n"; 421b8851fccSafresh1PROG 422b8851fccSafresh1 423b8851fccSafresh1 # reverse order of delete to exercise removing from the other end 424b8851fccSafresh1 # of the array 425b8851fccSafresh1 # again, may only crash on -DDEBUGGING builds 426b8851fccSafresh1 fresh_perl_is(<<'PROG', "ok", {}, "a case with multiple refs to ISA"); 427b8851fccSafresh1$x = \@{q(Foo::ISA)}; 428b8851fccSafresh1*Bar::ISA = $x; 429b8851fccSafresh1delete $Foo::{ISA}; 430b8851fccSafresh1delete $Bar::{ISA}; 431b8851fccSafresh1++$y; 432b8851fccSafresh1@$x = "Bar"; 433b8851fccSafresh1print "ok\n"; 434b8851fccSafresh1PROG 435b8851fccSafresh1} 436b8851fccSafresh1 437b8851fccSafresh1{ 438b8851fccSafresh1 # [perl #127351] 439b8851fccSafresh1 # *Foo::ISA = \@some_array 440b8851fccSafresh1 # didn't magicalize the elements of @some_array, causing two 441b8851fccSafresh1 # problems: 442b8851fccSafresh1 443b8851fccSafresh1 # a) assignment to those elements didn't update the cache 444b8851fccSafresh1 445b8851fccSafresh1 fresh_perl_is(<<'PROG', "foo\nother", {}, "magical *ISA = arrayref elements"); 446b8851fccSafresh1*My::Parent::foo = sub { "foo" }; 447b8851fccSafresh1*My::OtherParent::foo = sub { "other" }; 448b8851fccSafresh1my $x = [ "My::Parent" ]; 449b8851fccSafresh1*Fake::ISA = $x; 450b8851fccSafresh1print Fake->foo, "\n"; 451b8851fccSafresh1$x->[0] = "My::OtherParent"; 452b8851fccSafresh1print Fake->foo, "\n"; 453b8851fccSafresh1PROG 454b8851fccSafresh1 455b8851fccSafresh1 # b) code that attempted to remove the magic when @some_array 456b8851fccSafresh1 # was no longer an @ISA asserted/crashed 457b8851fccSafresh1 458b8851fccSafresh1 fresh_perl_is(<<'PROG', "foo", {}, "unmagicalize *ISA elements"); 459b8851fccSafresh1{ 460b8851fccSafresh1 local *My::Parent::foo = sub { "foo" }; 461b8851fccSafresh1 my $x = [ "My::Parent" ]; 462b8851fccSafresh1 *Fake::ISA = $x; 463b8851fccSafresh1 print Fake->foo, "\n"; 464b8851fccSafresh1 my $s = \%Fake::; 465b8851fccSafresh1 delete $s->{ISA}; 466b8851fccSafresh1} 467b8851fccSafresh1PROG 468b8851fccSafresh1} 469