<commit_before># Sometimes, we see references to roles that provide parameters but
# do not fully resolve them. For example, in:
#
#   class C does R[T] { }
#
# We need to represent R[T], but we cannot yet fully specialize the
# role because we don't have the first parameter to hand. We may also
# run into the issue where we have things like:
#
#   sub foo(R[T] $x) { ... }
#   if $x ~~ R[T] { ... }
#
# Where we clearly want to talk about a partial parameterization of a
# role and actually want to do so in a way distinct from a particular
# instantiation of it. This meta-object represents those "partial types"
# as both a way to curry on your way to a full specialization, but also
# as a way to do type-checking or punning.
class Perl6::Metamodel::CurriedRoleHOW
    does Perl6::Metamodel::RolePunning
    does Perl6::Metamodel::TypePretense
    does Perl6::Metamodel::Naming
    does Perl6::Metamodel::RoleContainer
{
    has $!curried_role;
    has @!pos_args;
    has %!named_args;
    has @!role_typecheck_list;
    has $!is_complete;

    my $archetypes_g := Perl6::Metamodel::Archetypes.new( :composable(1), :inheritalizable(1), :parametric(1), :generic(1) );
    my $archetypes_ng := Perl6::Metamodel::Archetypes.new( :nominal(1), :composable(1), :inheritalizable(1), :parametric(1) );
    method archetypes() {
        if nqp::isconcrete(self) {
            for @!pos_args {
                if $_.HOW.archetypes.generic {
                    return $archetypes_g;
                }
            }
            for %!named_args {
                if $_.value.HOW.archetypes.generic {
                    return $archetypes_g;
                }
            }
        }
        $archetypes_ng
    }

    method new(*%named) {
        nqp::findmethod(NQPMu, 'BUILDALL')(nqp::create(self), |%named)
    }

    method new_type($curried_role, *@pos_args, *%named_args) {
        # construct a name
        my $name := $curried_role.HOW.name($curried_role);
        if @pos_args {
            my @pieces := nqp::list_s();
            for @pos_args {
                nqp::push_s(@pieces, $_.HOW.name($_));
            }
            $name := $name ~ "[" ~ nqp::join(",", @pieces) ~ "]";
        }

        my $meta := self.new(:curried_role($curried_role), :pos_args(@pos_args),
            :named_args(%named_args), :name($name));
        my $type := nqp::settypehll(nqp::newtype($meta, 'Uninstantiable'), 'perl6');
        nqp::settypecheckmode($type, 2);
    }

    method complete_parameterization($obj) {
        unless $!is_complete {
            self.parameterize_roles($obj);
            self.update_role_typecheck_list($obj);
            $!is_complete := 1;
        }
    }

    method parameterize_roles($obj) {
        my @pos_args;
        nqp::push(@pos_args, $obj);
        for @!pos_args {
            nqp::push(@pos_args, $_);
        }
        my $candidate := $!curried_role.HOW.select_candidate($!curried_role, @pos_args, %!named_args);
        my $type_env;
        my $error;
        try {
            my $body_block := nqp::decont($candidate.HOW.body_block($candidate));
            my @result := $candidate.HOW.body_block($candidate)(|@pos_args, |%!named_args);
            $type_env := @result[1];
        }
        my @r := $candidate.HOW.roles($candidate, :!transitive);
        for @r {
            my $role := $_;
            if nqp::can($_.HOW, 'curried_role') && $_.HOW.archetypes.generic && $type_env {
                $role := $_.HOW.instantiate_generic($_, $type_env);
            }
            self.add_role($obj, $role);
        }
        self.update_role_typecheck_list($obj);
    }

    method update_role_typecheck_list($obj) {
        my @rtl;
        nqp::push(@rtl, $!curried_role);
        # for $!curried_role.HOW.role_typecheck_list($obj) {
        #     nqp::push(@rtl, $_);
        # }
        for self.roles_to_compose($obj) {
            nqp::push(@rtl, $_);
            for $_.HOW.role_typecheck_list($_) {
                nqp::push(@rtl, $_);
            }
        }
        @!role_typecheck_list := @rtl;
    }

    method instantiate_generic($obj, $type_env) {
        my @new_pos;
        my %new_named;
        for @!pos_args {
            @new_pos.push($_.HOW.archetypes.generic ??
                $_.HOW.instantiate_generic($_, $type_env) !!
                $_);
        }
        for %!named_args {
            %new_named{$_.key} := $_.value.HOW.archetypes.generic ??
                $_.value.HOW.instantiate_generic($_.value, $type_env) !!
                $_.value;
        }
        self.new_type($!curried_role, |@new_pos, |%new_named)
    }

    method specialize($obj, $first_arg) {
        $!curried_role.HOW.specialize($!curried_role, $first_arg,
            |@!pos_args, |%!named_args);
    }

    method curried_role($obj) {
        $!curried_role
    }
<commit_msg>Update type check cache for non-generic currings.<commit_after># Sometimes, we see references to roles that provide parameters but
# do not fully resolve them. For example, in:
#
#   class C does R[T] { }
#
# We need to represent R[T], but we cannot yet fully specialize the
# role because we don't have the first parameter to hand. We may also
# run into the issue where we have things like:
#
#   sub foo(R[T] $x) { ... }
#   if $x ~~ R[T] { ... }
#
# Where we clearly want to talk about a partial parameterization of a
# role and actually want to do so in a way distinct from a particular
# instantiation of it. This meta-object represents those "partial types"
# as both a way to curry on your way to a full specialization, but also
# as a way to do type-checking or punning.
class Perl6::Metamodel::CurriedRoleHOW
    does Perl6::Metamodel::RolePunning
    does Perl6::Metamodel::TypePretense
    does Perl6::Metamodel::Naming
    does Perl6::Metamodel::RoleContainer
{
    has $!curried_role;
    has @!pos_args;
    has %!named_args;
    has @!role_typecheck_list;
    has $!is_complete;
    has $!archetypes;

    my $archetypes_g := Perl6::Metamodel::Archetypes.new( :composable(1), :inheritalizable(1), :parametric(1), :generic(1) );
    my $archetypes_ng := Perl6::Metamodel::Archetypes.new( :nominal(1), :composable(1), :inheritalizable(1), :parametric(1) );
    method !choose_archetype() {
        for @!pos_args {
            if $_.HOW.archetypes.generic {
                return $archetypes_g;
            }
        }
        for %!named_args {
            if $_.value.HOW.archetypes.generic {
                return $archetypes_g;
            }
        }
        $archetypes_ng
    }
    method archetypes() {
        if nqp::isconcrete(self) {
            $!archetypes := self.'!choose_archetype'() unless $!archetypes;
            return $!archetypes;
        }
        $archetypes_ng
    }

    method new(*%named) {
        nqp::findmethod(NQPMu, 'BUILDALL')(nqp::create(self), |%named)
    }

    method new_type($curried_role, *@pos_args, *%named_args) {
        # construct a name
        my $name := $curried_role.HOW.name($curried_role);
        if @pos_args {
            my @pieces := nqp::list_s();
            for @pos_args {
                nqp::push_s(@pieces, $_.HOW.name($_));
            }
            $name := $name ~ "[" ~ nqp::join(",", @pieces) ~ "]";
        }

        my $meta := self.new(:curried_role($curried_role), :pos_args(@pos_args),
            :named_args(%named_args), :name($name));
        my $type := nqp::settypehll(nqp::newtype($meta, 'Uninstantiable'), 'perl6');
        nqp::settypecheckmode($type, 2);
    }

    method parameterize_roles($obj) {
        my @pos_args;
        nqp::push(@pos_args, $obj);
        for @!pos_args {
            nqp::push(@pos_args, $_);
        }
        my $candidate := $!curried_role.HOW.select_candidate($!curried_role, @pos_args, %!named_args);
        my $type_env;
        my $error;
        try {
            my $body_block := nqp::decont($candidate.HOW.body_block($candidate));
            my @result := $candidate.HOW.body_block($candidate)(|@pos_args, |%!named_args);
            $type_env := @result[1];
        }
        my @r := $candidate.HOW.roles($candidate, :!transitive);
        for @r {
            my $role := $_;
            if nqp::can($_.HOW, 'curried_role') && $_.HOW.archetypes.generic && $type_env {
                $role := $_.HOW.instantiate_generic($_, $type_env);
            }
            self.add_role($obj, $role);
        }
        self.update_role_typecheck_list($obj);
    }

    method update_role_typecheck_list($obj) {
        my @rtl;
        nqp::push(@rtl, $!curried_role);
        # for $!curried_role.HOW.role_typecheck_list($obj) {
        #     nqp::push(@rtl, $_);
        # }
        for self.roles_to_compose($obj) {
            nqp::push(@rtl, $_);
            for $_.HOW.role_typecheck_list($_) {
                nqp::push(@rtl, $_);
            }
        }
        @!role_typecheck_list := @rtl;
        unless self.archetypes.generic {
            nqp::settypecache($obj, @rtl);
        }
    }

    method complete_parameterization($obj) {
        unless $!is_complete {
            self.parameterize_roles($obj);
            self.update_role_typecheck_list($obj);
            $!is_complete := 1;
        }
    }

    method instantiate_generic($obj, $type_env) {
        my @new_pos;
        my %new_named;
        for @!pos_args {
            @new_pos.push($_.HOW.archetypes.generic ??
                $_.HOW.instantiate_generic($_, $type_env) !!
                $_);
        }
        for %!named_args {
            %new_named{$_.key} := $_.value.HOW.archetypes.generic ??
                $_.value.HOW.instantiate_generic($_.value, $type_env) !!
                $_.value;
        }
        self.new_type($!curried_role, |@new_pos, |%new_named)
    }

    method specialize($obj, $first_arg) {
        $!curried_role.HOW.specialize($!curried_role, $first_arg,
            |@!pos_args, |%!named_args);
    }

    method curried_role($obj) {
        $!curried_role
    }

{'fraction_non_alphanumeric': 0.14357480156736663, 'fraction_numerical': 0.0038179443383904352, 'mean_word_length': 2.225534672715489, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7644899', 'n_tokens_mistral': 3396, 'n_tokens_neox': 3272, 'n_words': 657}