Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
If a multi-method dispatch fails, also dump the list of candidates, s…
…orted as the dispatcher would sort them, like we do for failed multi-sub dispatches.
  • Loading branch information
jnthn committed Jul 16, 2010
1 parent 7b26327 commit b19a44e
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 14 deletions.
54 changes: 40 additions & 14 deletions src/pmc/p6invocation.pmc
Expand Up @@ -46,7 +46,8 @@ static STRING *CANDIDATE_LIST_str;

/* This does the grunt work of working out what the next candidate is. Takes
* account of us maybe needing to look into multi variants and all that lot. */
static PMC *get_next_candidate(PARROT_INTERP, PMC *SELF, int check_only, INTVAL *is_multi_dispatch) {
static PMC *get_next_candidate(PARROT_INTERP, PMC *SELF, int check_only,
INTVAL *is_multi_dispatch, PMC **guilty_multi) {
PMC *candidates, *current, *search_list;
STRING *name;
INTVAL position, resume_point;
Expand Down Expand Up @@ -88,7 +89,11 @@ static PMC *get_next_candidate(PARROT_INTERP, PMC *SELF, int check_only, INTVAL
if (VTABLE_isa(interp, current, CONST_STRING(interp, "Perl6MultiSub"))) {
/* Multi. Ask the multi-dispatcher for all possible variants that we
* could call with the current argument, unless we have none in
* which we're just gonna have to leave the multi here in the list. */
* which we're just gonna have to leave the multi here in the list.
* We may also mark the first multi we run into as being "guilty"
* for the dispatch failure so we can give a better error. */
if (guilty_multi && PMC_IS_NULL(*guilty_multi))
*guilty_multi = current;
if (!PMC_IS_NULL(Parrot_pcc_get_signature(interp, CURRENT_CONTEXT(interp)))) {
PMC *possibles = get_all_candidates_with_cur_args(interp, current);
if (VTABLE_elements(interp, possibles) == 0) {
Expand Down Expand Up @@ -212,7 +217,7 @@ pmclass P6Invocation dynpmc group perl6_group auto_attrs {

/* If not, then we see if the dispatcher can potentially find more. */
Parrot_pcc_set_signature(interp, CURRENT_CONTEXT(interp), NULL);
return !PMC_IS_NULL(get_next_candidate(interp, SELF, P6I_MODE_CHECK, NULL));
return !PMC_IS_NULL(get_next_candidate(interp, SELF, P6I_MODE_CHECK, NULL, NULL));
}

VTABLE INTVAL get_integer() {
Expand All @@ -225,7 +230,7 @@ pmclass P6Invocation dynpmc group perl6_group auto_attrs {
GETATTR_P6Invocation_first_candidate(interp, clone, first_candidate);
if (PMC_IS_NULL(first_candidate)) {
Parrot_pcc_set_signature(interp, CURRENT_CONTEXT(interp), NULL);
first_candidate = get_next_candidate(interp, clone, P6I_MODE_CHECK, NULL);
first_candidate = get_next_candidate(interp, clone, P6I_MODE_CHECK, NULL, NULL);
}
return first_candidate;
}
Expand All @@ -239,13 +244,15 @@ pmclass P6Invocation dynpmc group perl6_group auto_attrs {
PMC *lexpad, *first_candidate;
opcode_t *addr;
INTVAL is_multi_dispatch = 0;
PMC *guilty_multi = PMCNULL;

/* In the straightforward case, we know our first candidate right off the
* bat; if not, use list. We also nullify first candidate so we hit the
* candidate list next time we're used. */
GETATTR_P6Invocation_first_candidate(interp, SELF, first_candidate);
if (PMC_IS_NULL(first_candidate))
first_candidate = get_next_candidate(interp, SELF, P6I_MODE_DISPATCH, &is_multi_dispatch);
first_candidate = get_next_candidate(interp, SELF, P6I_MODE_DISPATCH,
&is_multi_dispatch, &guilty_multi);
else
SETATTR_P6Invocation_first_candidate(interp, SELF, PMCNULL);

Expand All @@ -256,18 +263,37 @@ pmclass P6Invocation dynpmc group perl6_group auto_attrs {
/* Oh noes, no candidate. If we aren't in soft-fail mode, then
* throw an exception with an informative error message. */
if (!PObj_flag_TEST(P6I_FAILURE_MODE, SELF)) {
STRING *method_name, *type_name;
STRING *method_name, *type_name, *signatures;

/* Get object type name. */
PMC *WHAT, *perl_meth;
PMC *call_sig = Parrot_pcc_get_signature(interp, CURRENT_CONTEXT(interp));
PMC *obj = VTABLE_get_pmc_keyed_int(interp, call_sig, 0);
PMC *WHAT_meth = VTABLE_find_method(interp, obj, CONST_STRING(interp, "WHAT"));
PMC *first_cand = PMCNULL;
PMC *call_sig = Parrot_pcc_get_signature(interp, CURRENT_CONTEXT(interp));
PMC *obj = VTABLE_get_pmc_keyed_int(interp, call_sig, 0);
PMC *WHAT_meth = VTABLE_find_method(interp, obj, CONST_STRING(interp, "WHAT"));
Parrot_ext_call(interp, WHAT_meth, "Pi->P", obj, &WHAT);
perl_meth = VTABLE_find_method(interp, WHAT, CONST_STRING(interp, "perl"));
perl_meth = VTABLE_find_method(interp, WHAT, CONST_STRING(interp, "perl"));
Parrot_ext_call(interp, perl_meth, "Pi->S", WHAT, &type_name);

/* Get method name. */
GETATTR_P6Invocation_name(interp, SELF, method_name);
Parrot_ex_throw_from_c_args(interp, next, 1,
"No candidates found to invoke for method '%Ss' on object of type '%Ss'",
method_name, type_name);

/* If we know the multi most immediately blameable for not having any
* candidates, get a dump of it's signatures too. */
if (!PMC_IS_NULL(guilty_multi)) {
STRING *siggies;
PMC *dump_meth = VTABLE_find_method(interp, guilty_multi,
CONST_STRING(interp, "dump_sorted_candidate_signatures"));
Parrot_ext_call(interp, dump_meth, "Pi->S", guilty_multi, &siggies);
Parrot_ex_throw_from_c_args(interp, next, 1,
"No candidates found to invoke for method '%Ss' on object of type '%Ss'; available candidates has signatures:\n%Ss",
method_name, type_name, siggies);
}
else {
Parrot_ex_throw_from_c_args(interp, next, 1,
"No candidates found to invoke for method '%Ss' on object of type '%Ss'",
method_name, type_name);
}
}

/* Otherwise, we look up something that when invoked will just give a
Expand All @@ -294,7 +320,7 @@ pmclass P6Invocation dynpmc group perl6_group auto_attrs {
GETATTR_P6Invocation_first_candidate(interp, SELF, first_candidate);
if (PMC_IS_NULL(first_candidate)) {
Parrot_pcc_set_signature(interp, CURRENT_CONTEXT(interp), NULL);
get_next_candidate(interp, SELF, P6I_MODE_DISPATCH, NULL);
get_next_candidate(interp, SELF, P6I_MODE_DISPATCH, NULL, NULL);
}
else {
SETATTR_P6Invocation_first_candidate(interp, SELF, PMCNULL);
Expand Down
42 changes: 42 additions & 0 deletions src/pmc/perl6multisub.pmc
Expand Up @@ -1362,6 +1362,48 @@ skipping any candidates with subids already present in the invocant.
}
RETURN (PMC *SELF);
}

/*

=item METHOD STRING *dump_sorted_candidate_signatures()

Dumps a list of candidate signautres, sorted in dispatch order.

=cut

*/

METHOD STRING *dump_sorted_candidate_signatures() {
candidate_info **candidates = NULL;
candidate_info **cur_candidate = NULL;
STRING *signatures = Parrot_str_new(interp, "", 0);
PMC *unsorted;

/* Make sure that we have a candidate list built. */
GETATTR_Perl6MultiSub_candidates_sorted(interp, SELF, candidates);
GETATTR_Perl6MultiSub_candidates(interp, SELF, unsorted);
if (!candidates) {
PMC *proto;
candidates = sort_candidates(interp, unsorted, &proto);
SETATTR_Perl6MultiSub_candidates_sorted(interp, SELF, candidates);
SETATTR_Perl6MultiSub_proto(interp, SELF, proto);
}
if (!candidates)
Parrot_ex_throw_from_c_args(interp, NULL, 1,
"Failed to build candidate list");

/* Now go over the candidates and build a result string. */
cur_candidate = candidates;
while (1) {
if (!cur_candidate[0] && !cur_candidate[1])
break;
if (cur_candidate[0])
signatures = dump_signature(interp, signatures, (*cur_candidate)->sub);
cur_candidate++;
}

RETURN (STRING *signatures);
}
}

/*
Expand Down

0 comments on commit b19a44e

Please sign in to comment.