/* =item C<static void add_to_cache(PARROT_INTERP, NQP_md_cache *cache, PMC *capture, INTVAL num_args)> Adds an entry to the multi-dispatch cache. =cut */ void add_to_cache(PARROT_INTERP, NQP_md_cache *cache, PMC *capture, INTVAL num_args, PMC *result) { INTVAL arg_tup[MD_CACHE_MAX_ARITY]; INTVAL i, entries, ins_type; struct Pcc_cell * pc_positionals; /* Make sure 6model type ID is set. */ if (!smo_id) smo_id = Parrot_pmc_get_type_str(interp, Parrot_str_new(interp, "SixModelObject", 0)); /* If it's zero arity, just stick it in that slot. */ if (num_args == 0) { cache->zero_arity = result; return; } /* If the cache is saturated, don't do anything (we could instead do a random * replacement). */ entries = cache->arity_caches[num_args - 1].num_entries; if (entries == MD_CACHE_MAX_ENTRIES) return; /* Create arg tuple. */ if (capture->vtable->base_type == enum_class_CallContext) GETATTR_CallContext_positionals(interp, capture, pc_positionals); else return; for (i = 0; i < num_args; i++) { if (pc_positionals[i].type == BIND_VAL_OBJ) { PMC *arg = pc_positionals[i].u.p; if (arg->vtable->base_type != smo_id) return; arg_tup[i] = STABLE(arg)->type_cache_id | (IS_CONCRETE(arg) ? 1 : 0); } else { arg_tup[i] = (pc_positionals[i].type << 1) | 1; } } /* If there's no entries yet, need to do some allocation. */ if (entries == 0) { cache->arity_caches[num_args - 1].type_ids = mem_sys_allocate(num_args * sizeof(INTVAL) * MD_CACHE_MAX_ENTRIES); cache->arity_caches[num_args - 1].results = mem_sys_allocate(sizeof(PMC *) * MD_CACHE_MAX_ENTRIES); } /* Add entry. */ ins_type = entries * num_args; for (i = 0; i < num_args; i++) cache->arity_caches[num_args - 1].type_ids[ins_type + i] = arg_tup[i]; cache->arity_caches[num_args - 1].results[entries] = result; cache->arity_caches[num_args - 1].num_entries = entries + 1; }
/* =item C<static PMC * find_in_cache(PARROT_INTERP, NQP_md_cache *cache, PMC *capture, INTVAL num_args)> Looks for an entry in the multi-dispatch cache. =cut */ static PMC * find_in_cache(PARROT_INTERP, NQP_md_cache *cache, PMC *capture, INTVAL num_args) { INTVAL arg_tup[MD_CACHE_MAX_ARITY]; INTVAL i, j, entries, t_pos; struct Pcc_cell * pc_positionals; /* If it's zero-arity, return result right off. */ if (num_args == 0) return cache->zero_arity; /* Create arg tuple. */ if (capture->vtable->base_type == enum_class_CallContext) GETATTR_CallContext_positionals(interp, capture, pc_positionals); else return NULL; for (i = 0; i < num_args; i++) { if (pc_positionals[i].type == BIND_VAL_OBJ) { PMC *arg = pc_positionals[i].u.p; if (arg->vtable->base_type != smo_id) return NULL; arg_tup[i] = STABLE(arg)->type_cache_id | (IS_CONCRETE(arg) ? 1 : 0); } else { arg_tup[i] = (pc_positionals[i].type << 1) | 1; } } /* Look through entries. */ entries = cache->arity_caches[num_args - 1].num_entries; t_pos = 0; for (i = 0; i < entries; i++) { INTVAL match = 1; for (j = 0; j < num_args; j++) { if (cache->arity_caches[num_args - 1].type_ids[t_pos + j] != arg_tup[j]) { match = 0; break; } } if (match) return cache->arity_caches[num_args - 1].results[i]; t_pos += num_args; } return NULL; }
/* Takes a signature along with positional and named arguments and binds them * into the provided lexpad (actually, anything that has a Hash interface will * do). Returns BIND_RESULT_OK if binding works out, BIND_RESULT_FAIL if there * is a failure and BIND_RESULT_JUNCTION if the failure was because of a * Junction being passed (meaning we need to auto-thread). */ INTVAL Rakudo_binding_bind(PARROT_INTERP, PMC *lexpad, PMC *sig_pmc, PMC *capture, INTVAL no_nom_type_check, STRING **error) { INTVAL i, num_pos_args; INTVAL bind_fail = 0; INTVAL cur_pos_arg = 0; Rakudo_Signature *sig = (Rakudo_Signature *)PMC_data(sig_pmc); PMC *params = sig->params; INTVAL num_params = VTABLE_elements(interp, params); Rakudo_BindVal cur_bv; /* If we do have some named args, we want to make a clone of the hash * to work on. We'll delete stuff from it as we bind, and what we have * left over can become the slurpy hash or - if we aren't meant to be * taking one - tell us we have a problem. */ PMC *named_args_copy = PMCNULL; /* If we have a |$foo that's followed by slurpies, then we can suppress * any future arity checks. */ INTVAL suppress_arity_fail = 0; /* If it's a Parrot capture, it may contain natively typed arguments. * NOTE: This is a really an encapsulation breakage; if Parrot folks * change stuff and this breaks, it's not Parrot's fault. */ struct Pcc_cell * pc_positionals = NULL; /* Set up statics. */ if (!smo_id) setup_binder_statics(interp); /* If we've got a CallContext, just has an attribute with list of named * parameter names. Otherwise, it's probably a Perl 6 Capture and we need * to extract its parts. */ if (capture->vtable->base_type == enum_class_CallContext) { PMC *named_names = VTABLE_get_attr_str(interp, capture, NAMED_str); if (!PMC_IS_NULL(named_names)) { PMC *iter = VTABLE_get_iter(interp, named_names); named_args_copy = Parrot_pmc_new(interp, enum_class_Hash); while (VTABLE_get_bool(interp, iter)) { STRING *name = VTABLE_shift_string(interp, iter); VTABLE_set_pmc_keyed_str(interp, named_args_copy, name, VTABLE_get_pmc_keyed_str(interp, capture, name)); } } GETATTR_CallContext_positionals(interp, capture, pc_positionals); } else if (capture->vtable->base_type == smo_id && STABLE(capture)->type_check(interp, capture, Rakudo_types_capture_get())) { PMC *captype = Rakudo_types_capture_get(); PMC *list_part = VTABLE_get_attr_keyed(interp, capture, captype, LIST_str); PMC *hash_part = VTABLE_get_attr_keyed(interp, capture, captype, HASH_str); capture = Rakudo_isnqplist(list_part) ? list_part : Parrot_pmc_new(interp, enum_class_ResizablePMCArray); if (hash_part->vtable->base_type == enum_class_Hash) { PMC *iter = VTABLE_get_iter(interp, hash_part); named_args_copy = Parrot_pmc_new(interp, enum_class_Hash); while (VTABLE_get_bool(interp, iter)) { STRING *arg_copy_name = VTABLE_shift_string(interp, iter); VTABLE_set_pmc_keyed_str(interp, named_args_copy, arg_copy_name, VTABLE_get_pmc_keyed_str(interp, hash_part, arg_copy_name)); } } } else { Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION, "Internal Error: Rakudo_binding_bind passed invalid Capture"); } /* Now we'll walk through the signature and go about binding things. */ num_pos_args = VTABLE_elements(interp, capture); for (i = 0; i < num_params; i++) { Rakudo_Parameter *param = (Rakudo_Parameter *)PMC_data( VTABLE_get_pmc_keyed_int(interp, params, i)); /* Is it looking for us to bind a capture here? */ if (param->flags & SIG_ELEM_IS_CAPTURE) { /* Capture the arguments from this point forwards into a Capture. * Of course, if there's no variable name we can (cheaply) do pretty * much nothing. */ if (STRING_IS_NULL(param->variable_name)) { bind_fail = BIND_RESULT_OK; } else { PMC *captype = Rakudo_types_capture_get(); PMC *capsnap = REPR(captype)->allocate(interp, STABLE(captype)); PMC *pos_args = Parrot_pmc_new(interp, enum_class_ResizablePMCArray); PMC *named_args = Parrot_pmc_new(interp, enum_class_Hash); INTVAL k; VTABLE_set_attr_keyed(interp, capsnap, captype, LIST_str, pos_args); VTABLE_set_attr_keyed(interp, capsnap, captype, HASH_str, named_args); for (k = cur_pos_arg; k < num_pos_args; k++) { cur_bv = get_positional_bind_val(interp, pc_positionals, capture, k); VTABLE_push_pmc(interp, pos_args, cur_bv.type == BIND_VAL_OBJ ? cur_bv.val.o : create_box(interp, cur_bv)); } if (!PMC_IS_NULL(named_args_copy)) { PMC *iter = VTABLE_get_iter(interp, named_args_copy); while (VTABLE_get_bool(interp, iter)) { STRING *name = VTABLE_shift_string(interp, iter); VTABLE_set_pmc_keyed_str(interp, named_args, name, VTABLE_get_pmc_keyed_str(interp, named_args_copy, name)); } } cur_bv.type = BIND_VAL_OBJ; cur_bv.val.o = capsnap; bind_fail = Rakudo_binding_bind_one_param(interp, lexpad, sig, param, cur_bv, no_nom_type_check, error); } if (bind_fail) { return bind_fail; } else if (i + 1 == num_params) { /* Since a capture acts as "the ultimate slurpy" in a sense, if * this is the last parameter in the signature we can return * success right off the bat. */ return BIND_RESULT_OK; } else { Rakudo_Parameter *next_param = (Rakudo_Parameter *)PMC_data( VTABLE_get_pmc_keyed_int(interp, params, i + 1)); if (next_param->flags & (SIG_ELEM_SLURPY_POS | SIG_ELEM_SLURPY_NAMED)) suppress_arity_fail = 1; } } /* Could it be a named slurpy? */ else if (param->flags & SIG_ELEM_SLURPY_NAMED) { /* Can cheat a bit if it's the default method %_. * We give the hash to the lexpad. */ if (param->flags & SIG_ELEM_METHOD_SLURPY_NAMED && lexpad->vtable->base_type == p6l_id) { SETATTR_Perl6LexPad_default_named_slurpy(interp, lexpad, named_args_copy); PARROT_GC_WRITE_BARRIER(interp, lexpad); } else { /* We'll either take the current named arguments copy hash which * will by definition contain all unbound named parameters and use * that, or just create an empty one. */ PMC *slurpy = PMC_IS_NULL(named_args_copy) ? Parrot_pmc_new(interp, enum_class_Hash) : named_args_copy; cur_bv.type = BIND_VAL_OBJ; cur_bv.val.o = Rakudo_binding_create_hash(interp, slurpy); bind_fail = Rakudo_binding_bind_one_param(interp, lexpad, sig, param, cur_bv, no_nom_type_check, error); if (bind_fail) return bind_fail; } /* Nullify named arguments hash now we've consumed it, to mark all * is well. */ named_args_copy = PMCNULL; } /* Otherwise, maybe it's a positional. */ else if (PMC_IS_NULL(param->named_names)) { /* Slurpy or LoL-slurpy? */ if (param->flags & (SIG_ELEM_SLURPY_POS | SIG_ELEM_SLURPY_LOL)) { /* Create Perl 6 array, create RPA of all remaining things, then * store it. */ PMC *temp = Parrot_pmc_new(interp, enum_class_ResizablePMCArray); while (cur_pos_arg < num_pos_args) { cur_bv = get_positional_bind_val(interp, pc_positionals, capture, cur_pos_arg); VTABLE_push_pmc(interp, temp, cur_bv.type == BIND_VAL_OBJ ? cur_bv.val.o : create_box(interp, cur_bv)); cur_pos_arg++; } cur_bv.type = BIND_VAL_OBJ; cur_bv.val.o = param->flags & SIG_ELEM_SLURPY_POS ? Rakudo_binding_create_positional(interp, temp) : Rakudo_binding_create_lol(interp, temp); bind_fail = Rakudo_binding_bind_one_param(interp, lexpad, sig, param, cur_bv, no_nom_type_check, error); if (bind_fail) return bind_fail; } /* Otherwise, a positional. */ else { /* Do we have a value?. */ if (cur_pos_arg < num_pos_args) { /* Easy - just bind that. */ cur_bv = get_positional_bind_val(interp, pc_positionals, capture, cur_pos_arg); bind_fail = Rakudo_binding_bind_one_param(interp, lexpad, sig, param, cur_bv, no_nom_type_check, error); if (bind_fail) return bind_fail; cur_pos_arg++; } else { /* No value. If it's optional, fetch a default and bind that; * if not, we're screwed. Note that we never nominal type check * an optional with no value passed. */ if (param->flags & SIG_ELEM_IS_OPTIONAL) { cur_bv.type = BIND_VAL_OBJ; cur_bv.val.o = Rakudo_binding_handle_optional(interp, param, lexpad); bind_fail = Rakudo_binding_bind_one_param(interp, lexpad, sig, param, cur_bv, 0, error); if (bind_fail) return bind_fail; } else { if (error) *error = Rakudo_binding_arity_fail(interp, params, num_params, num_pos_args, 0); return BIND_RESULT_FAIL; } } } } /* Else, it's a non-slurpy named. */ else { /* Try and get hold of value. */ PMC *value = PMCNULL; INTVAL num_names = VTABLE_elements(interp, param->named_names); INTVAL j; if (!PMC_IS_NULL(named_args_copy)) { for (j = 0; j < num_names; j++) { STRING *name = VTABLE_get_string_keyed_int(interp, param->named_names, j); value = VTABLE_get_pmc_keyed_str(interp, named_args_copy, name); if (!PMC_IS_NULL(value)) { /* Found a value. Delete entry from to-bind args and stop looking. */ VTABLE_delete_keyed_str(interp, named_args_copy, name); break; } } } /* Did we get one? */ if (PMC_IS_NULL(value)) { /* Nope. We'd better hope this param was optional... */ if (param->flags & SIG_ELEM_IS_OPTIONAL) { cur_bv.type = BIND_VAL_OBJ; cur_bv.val.o = Rakudo_binding_handle_optional(interp, param, lexpad); bind_fail = Rakudo_binding_bind_one_param(interp, lexpad, sig, param, cur_bv, 0, error); } else if (!suppress_arity_fail) { if (error) *error = Parrot_sprintf_c(interp, "Required named parameter '%S' not passed", VTABLE_get_string_keyed_int(interp, param->named_names, 0)); return BIND_RESULT_FAIL; } } else { cur_bv.type = BIND_VAL_OBJ; cur_bv.val.o = value; bind_fail = Rakudo_binding_bind_one_param(interp, lexpad, sig, param, cur_bv, 0, error); } /* If we got a binding failure, return it. */ if (bind_fail) return bind_fail; } } /* Do we have any left-over args? */ if (cur_pos_arg < num_pos_args && !suppress_arity_fail) { /* Oh noes, too many positionals passed. */ if (error) *error = Rakudo_binding_arity_fail(interp, params, num_params, num_pos_args, 1); return BIND_RESULT_FAIL; } if (!PMC_IS_NULL(named_args_copy) && VTABLE_elements(interp, named_args_copy)) { /* Oh noes, unexpected named args. */ if (error) { INTVAL num_extra = VTABLE_elements(interp, named_args_copy); PMC *iter = VTABLE_get_iter(interp, named_args_copy); if (num_extra == 1) { *error = Parrot_sprintf_c(interp, "Unexpected named parameter '%S' passed", VTABLE_shift_string(interp, iter)); } else { INTVAL first = 1; STRING *comma = Parrot_str_new(interp, ", ", 0); *error = Parrot_sprintf_c(interp, "%d unexpected named parameters passed (", num_extra); while (VTABLE_get_bool(interp, iter)) { STRING *name = VTABLE_shift_string(interp, iter); if (!first) *error = Parrot_str_concat(interp, *error, comma); else first = 0; *error = Parrot_str_concat(interp, *error, name); } *error = Parrot_str_concat(interp, *error, Parrot_str_new(interp, ")", 0)); } } return BIND_RESULT_FAIL; } /* If we get here, we're done. */ return BIND_RESULT_OK; }
/* Compile time trial binding; tries to determine at compile time whether * certain binds will/won't work. */ INTVAL Rakudo_binding_trial_bind(PARROT_INTERP, PMC *sig_pmc, PMC *capture) { INTVAL i, num_pos_args, got_prim; INTVAL cur_pos_arg = 0; Rakudo_Signature *sig = (Rakudo_Signature *)PMC_data(sig_pmc); PMC *params = sig->params; INTVAL num_params = VTABLE_elements(interp, params); /* Grab arguments. */ struct Pcc_cell * pc_positionals = NULL; if (capture->vtable->base_type == enum_class_CallContext) GETATTR_CallContext_positionals(interp, capture, pc_positionals); else return TRIAL_BIND_NOT_SURE; /* Set up statics. */ if (!smo_id) setup_binder_statics(interp); /* Walk through the signature and consider the parameters. */ num_pos_args = VTABLE_elements(interp, capture); for (i = 0; i < num_params; i++) { Rakudo_Parameter *param = (Rakudo_Parameter *)PMC_data( VTABLE_get_pmc_keyed_int(interp, params, i)); /* If the parameter is anything other than a boring old * required positional parameter, we won't analyze it. */ if (param->flags & ~( SIG_ELEM_MULTI_INVOCANT | SIG_ELEM_IS_PARCEL | SIG_ELEM_IS_COPY | SIG_ELEM_ARRAY_SIGIL | SIG_ELEM_HASH_SIGIL | SIG_ELEM_NATIVE_VALUE)) return TRIAL_BIND_NOT_SURE; if (!PMC_IS_NULL(param->named_names)) return TRIAL_BIND_NOT_SURE; if (!PMC_IS_NULL(param->post_constraints)) return TRIAL_BIND_NOT_SURE; if (!PMC_IS_NULL(param->type_captures)) return TRIAL_BIND_NOT_SURE; /* Did we pass too few required arguments? If so, fail. */ if (cur_pos_arg >= num_pos_args) return TRIAL_BIND_NO_WAY; /* Otherwise, need to consider type. */ got_prim = pc_positionals[cur_pos_arg].type; if (param->flags & SIG_ELEM_NATIVE_VALUE) { if (got_prim == BIND_VAL_OBJ) { /* We got an object; if we aren't sure we can unbox, we can't * be sure about the dispatch. */ PMC *arg = pc_positionals[cur_pos_arg].u.p; storage_spec spec = REPR(arg)->get_storage_spec(interp, STABLE(arg)); switch (param->flags & SIG_ELEM_NATIVE_VALUE) { case SIG_ELEM_NATIVE_INT_VALUE: if (!(spec.can_box & STORAGE_SPEC_CAN_BOX_INT)) return TRIAL_BIND_NOT_SURE; break; case SIG_ELEM_NATIVE_NUM_VALUE: if (!(spec.can_box & STORAGE_SPEC_CAN_BOX_NUM)) return TRIAL_BIND_NOT_SURE; break; case SIG_ELEM_NATIVE_STR_VALUE: if (!(spec.can_box & STORAGE_SPEC_CAN_BOX_STR)) return TRIAL_BIND_NOT_SURE; break; default: /* WTF... */ return TRIAL_BIND_NOT_SURE; } } else { /* If it's the wrong type of native, there's no way it * can ever bind. */ if ((param->flags & SIG_ELEM_NATIVE_INT_VALUE) && got_prim != BIND_VAL_INT || (param->flags & SIG_ELEM_NATIVE_NUM_VALUE) && got_prim != BIND_VAL_NUM || (param->flags & SIG_ELEM_NATIVE_STR_VALUE) && got_prim != BIND_VAL_STR) return TRIAL_BIND_NO_WAY; } } else { /* Work out a parameter type to consider, and see if it matches. */ PMC * const arg = got_prim == BIND_VAL_OBJ ? pc_positionals[cur_pos_arg].u.p : got_prim == BIND_VAL_INT ? Rakudo_types_int_get() : got_prim == BIND_VAL_NUM ? Rakudo_types_num_get() : Rakudo_types_str_get(); if (param->nominal_type != Rakudo_types_mu_get() && !STABLE(arg)->type_check(interp, arg, param->nominal_type)) { /* If it failed because we got a junction, may auto-thread; * hand back "not sure" for now. */ if (STABLE(arg)->WHAT == Rakudo_types_junction_get()) return TRIAL_BIND_NOT_SURE; /* It failed to, but that doesn't mean it can't work at runtime; * we perhaps want an Int, and the most we know is we have an Any, * which would include Int. However, the Int ~~ Str case can be * rejected now, as there's no way it'd ever match. Basically, we * just flip the type check around. */ return STABLE(param->nominal_type)->type_check(interp, param->nominal_type, arg) ? TRIAL_BIND_NOT_SURE : TRIAL_BIND_NO_WAY; } } /* Continue to next argument. */ cur_pos_arg++; } /* If we have any left over arguments, it's a binding fail. */ if (cur_pos_arg < num_pos_args) return TRIAL_BIND_NO_WAY; /* Otherwise, if we get there, all is well. */ return TRIAL_BIND_OK; }
static PMC* find_best_candidate(PARROT_INTERP, Rakudo_md_candidate_info **candidates, INTVAL num_candidates, PMC *capture, opcode_t *next, PMC *dispatcher, INTVAL many) { Rakudo_md_candidate_info **cur_candidate = candidates; Rakudo_md_candidate_info **possibles = mem_allocate_n_typed(num_candidates + 1, Rakudo_md_candidate_info *); PMC *junctional_res = PMCNULL; PMC *many_res = many ? Parrot_pmc_new(interp, enum_class_ResizablePMCArray) : PMCNULL; const INTVAL num_args = VTABLE_elements(interp, capture); INTVAL possibles_count = 0; INTVAL pure_type_result = 1; INTVAL type_check_count; INTVAL type_mismatch; /* We expect a Parrot capture in the multi-dispatcher, always. */ struct Pcc_cell * pc_positionals = NULL; if (capture->vtable->base_type == enum_class_CallContext) { GETATTR_CallContext_positionals(interp, capture, pc_positionals); } else { mem_sys_free(possibles); Parrot_ex_throw_from_c_args(interp, next, 1, "INTERNAL ERROR: multi-dispatcher must be given a low level capture"); } /* Iterate over the candidates and collect best ones; terminate * when we see two nulls (may break out earlier). */ while (1) { INTVAL i; if (*cur_candidate == NULL) { /* We've hit the end of a tied group now. If any of them have a * bindability check requirement, we'll do any of those now. */ if (possibles_count) { Rakudo_md_candidate_info **new_possibles = NULL; INTVAL new_possibles_count = 0; INTVAL i; for (i = 0; i < possibles_count; i++) { Parrot_pcc_set_signature(interp, CURRENT_CONTEXT(interp), NULL); /* First, if there's a required named parameter and it was * not passed, we can very quickly eliminate this candidate * without doing a full bindability check. */ if (possibles[i]->req_named) { if (!VTABLE_exists_keyed_str(interp, capture, possibles[i]->req_named)) { /* Required named arg not passed, so we eliminate * it right here. Flag that we've built a list of * new possibles, and that this was not a pure * type-based result that we can cache. */ if (!new_possibles) new_possibles = mem_allocate_n_typed(num_candidates, Rakudo_md_candidate_info *); pure_type_result = 0; continue; } } /* Otherwise, may need full bind check. */ if (possibles[i]->bind_check) { /* We'll invoke the sub (but not re-enter the runloop) * and then attempt to bind the signature. */ PMC *cthunk, *lexpad, *sig; opcode_t *where; INTVAL bind_check_result; Rakudo_Code *code_obj = (Rakudo_Code *)PMC_data(possibles[i]->sub); cthunk = Parrot_pmc_getprop(interp, code_obj->_do, Parrot_str_new(interp, "COMPILER_THUNK", 0)); if (!PMC_IS_NULL(cthunk)) { /* We need to do the tie-break on something not yet compiled. * Get it compiled. */ Parrot_ext_call(interp, cthunk, "->"); } Parrot_pcc_reuse_continuation(interp, CURRENT_CONTEXT(interp), next); where = VTABLE_invoke(interp, possibles[i]->sub, next); lexpad = Parrot_pcc_get_lex_pad(interp, CURRENT_CONTEXT(interp)); sig = possibles[i]->signature; bind_check_result = Rakudo_binding_bind(interp, lexpad, sig, capture, 0, NULL); where = VTABLE_invoke(interp, Parrot_pcc_get_continuation(interp, CURRENT_CONTEXT(interp)), where); /* If we haven't got a possibles storage space, allocate it now. */ if (!new_possibles) new_possibles = mem_allocate_n_typed(num_candidates, Rakudo_md_candidate_info *); /* If we don't fail, need to put this one onto the list * (note that needing a junction dispatch is OK). */ if (bind_check_result != BIND_RESULT_FAIL) { new_possibles[new_possibles_count] = possibles[i]; new_possibles_count++; } /* Since we had to do a bindability check, this is not * a result we can cache on nominal type. */ pure_type_result = 0; } /* Otherwise, it's just nominal; accept it. */ else { if (!new_possibles) new_possibles = mem_allocate_n_typed(num_candidates, Rakudo_md_candidate_info *); new_possibles[new_possibles_count] = possibles[i]; new_possibles_count++; } } /* If we have an updated list of possibles, free old one and use this * new one from here on in. */ if (new_possibles) { mem_sys_free(possibles); possibles = new_possibles; possibles_count = new_possibles_count; } } /* Now we have eliminated any that fail the bindability check. * See if we need to push it onto the many list and continue. * Otherwise, we have the result we were looking for. */ if (many) { for (i = 0; i < possibles_count; i++) VTABLE_push_pmc(interp, many_res, possibles[i]->sub); possibles_count = 0; } else if (possibles_count) { break; } /* Keep looping and looking, unless we really hit the end. */ if (cur_candidate[1]) { cur_candidate++; continue; } else { break; } }