Author: jonathan Date: Tue Jan 20 05:23:21 2009 New Revision: 35799 Modified: trunk/languages/perl6/src/classes/Role.pir
Log: [rakudo] Track what roles we have already created and re-use them appropriately. For example, every time you said does Foo[Int] before, it would have created a new Parrot role. Now it creates one and re-uses it. This means that .does(Foo[Int]) tests now work also. Modified: trunk/languages/perl6/src/classes/Role.pir ============================================================================== --- trunk/languages/perl6/src/classes/Role.pir (original) +++ trunk/languages/perl6/src/classes/Role.pir Tue Jan 20 05:23:21 2009 @@ -56,17 +56,60 @@ .param pmc pos_args :slurpy .param pmc name_args :slurpy :named - # XXX We need to look through the parameters we have and keep track - # of variants we did already initialize/parameterize with. - .local pmc selector, result, created_list - selector = getattribute self, '$!selector' - result = selector(pos_args :flat, name_args :flat :named) + # @!created is an array of hashes describing role instantiations that have + # already taken place. This means that we always hand back, for Foo[Int], + # the same Parrot-level role rather than creating one each time we ask for + # a Foo[Int]. The hash contains: + # * pos_args - array of the positional arguments for the instantiation + # * role - the Parrot role object + # Note that since named parameters don't participate in a multiple dispatch, + # they cannot form part of the long name for the role, so we don't need to + # check those. + .local pmc result, created_list, ins_hash, it, test_pos_args + .local int num_pos_args, num_name_args, i created_list = getattribute self, '@!created' unless null created_list goto got_created_list created_list = new 'ResizablePMCArray' setattribute self, '@!created', created_list + goto select_role got_created_list: - push created_list, result + num_pos_args = elements pos_args + it = iter created_list + it_loop: + unless it goto it_loop_end + ins_hash = shift it + + # Compare positional counts. + test_pos_args = ins_hash["pos_args"] + $I0 = elements test_pos_args + if $I0 != num_pos_args goto it_loop + + # Counts match, now look at positionals. + i = 0 + pos_loop: + if i >= num_pos_args goto pos_loop_end + $P0 = pos_args[i] + $P1 = test_pos_args[i] + $I0 = 'infix:==='($P0, $P1) + unless $I0 goto it_loop + inc i + goto pos_loop + pos_loop_end: + + # If we get here, we've found a match, so return it. + result = ins_hash["role"] + .return (result) + it_loop_end: + + # First time we've had these parameters, so need to instantiate them. + select_role: + .local pmc selector + selector = getattribute self, '$!selector' + result = selector(pos_args :flat, name_args :flat :named) + ins_hash = new 'Hash' + ins_hash["pos_args"] = pos_args + ins_hash["role"] = result + push created_list, ins_hash .return (result) .end @@ -96,6 +139,7 @@ it_loop: unless it goto it_loop_end $P0 = shift it + $P0 = $P0["role"] $I0 = does topic, $P0 if $I0 == 0 goto it_loop it_loop_end: @@ -135,6 +179,7 @@ .return ($I0) .end + =back =cut