Skip to content

Commit e861a6e

Browse files
committed
Collect names of multiple erroring parameters
Rather than stop immediately at the first failure, we can be a bit more helpful by collecting up potentially multiple names at once. We limit the list to 5 elements, just to limit the potential output in the case of accidentally passing a list of hundreds or thousands of elements into such a function.
1 parent a189ac0 commit e861a6e

File tree

3 files changed

+75
-15
lines changed

3 files changed

+75
-15
lines changed

pod/perldiag.pod

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4163,9 +4163,12 @@ which is forbidden. See L<perlvar/%{^HOOK}> and L<perlfunc/require EXPR>.
41634163

41644164
=item Missing required named parameter '%s' to subroutine '%s'
41654165

4166-
(F) A subroutine was invoked that uses a signature that declares a
4167-
non-optional named parameter, but the caller did not provide a value associated
4168-
with that name. The caller of the subroutine is presumably at fault.
4166+
=item Missing required named parameters '%s' to subroutine '%s'
4167+
4168+
(F) A subroutine was invoked that uses a signature that declares at least
4169+
one non-optional named parameter, but the caller did not provide a value
4170+
associated with that name. The caller of the subroutine is presumably at
4171+
fault.
41694172

41704173
The message attempts to include the name of the called subroutine. If
41714174
the subroutine has been aliased, the subroutine's original name will be
@@ -7530,10 +7533,12 @@ perl does not recognise the name of the requested attribute.
75307533

75317534
=item Unrecognized named parameter '%s' to subroutine '%s'
75327535

7533-
(F) A subroutine was invoked that uses a signature that declares named parameters but has no
7534-
slurpy parameter, and the caller provided a name that did not
7535-
match any declared named parameter. The caller of the subroutine is
7536-
presumably at fault.
7536+
=item Unrecognized named parameters '%s' to subroutine '%s'
7537+
7538+
(F) A subroutine was invoked that uses a signature that declares named
7539+
parameters but has no slurpy parameter, and the caller provided at least one
7540+
name that did not match any declared named parameter. The caller of the
7541+
subroutine is presumably at fault.
75377542

75387543
The message attempts to include the name of the called subroutine. If
75397544
the subroutine has been aliased, the subroutine's original name will be

pp.c

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7890,6 +7890,27 @@ PP(pp_argcheck)
78907890
return NORMAL;
78917891
}
78927892

7893+
/* Helper function for collecting up hash key names for a human-readable
7894+
* error message string
7895+
*/
7896+
#define accumulate_error_names(n_errorsp, error_namesp, namepv, namelen) S_accumulate_error_names(aTHX_ n_errorsp, error_namesp, namepv, namelen)
7897+
STATIC void
7898+
S_accumulate_error_names(pTHX_ size_t *n_errorsp, SV **error_namesp, const char *namepv, STRLEN namelen)
7899+
{
7900+
size_t n_errors = ++(*n_errorsp);
7901+
7902+
SV *error_names = (*error_namesp);
7903+
if(!error_names)
7904+
error_names = (*error_namesp) = newSVpvs_flags("", SVs_TEMP);
7905+
7906+
if(n_errors <= 5) {
7907+
/* Only bother collecting up the first 5 */
7908+
if(n_errors > 1)
7909+
sv_catpvs(error_names, ", ");
7910+
sv_catpvf(error_names, "'%" UTF8f "'", UTF8fARG(true, namelen, namepv));
7911+
}
7912+
}
7913+
78937914
PP(pp_multiparam)
78947915
{
78957916
struct op_multiparam_aux *aux = (struct op_multiparam_aux *)cUNOP_AUX->op_aux;
@@ -7983,6 +8004,9 @@ PP(pp_multiparam)
79838004
SvPADSTALE_on(PAD_SVl(named->padix));
79848005
}
79858006

8007+
size_t n_errors = 0;
8008+
SV *error_names = NULL;
8009+
79868010
while(argc) {
79878011
SV **svp;
79888012

@@ -8060,22 +8084,32 @@ PP(pp_multiparam)
80608084
hv_store_ent(hv, name, newSVsv(val), 0);
80618085
}
80628086
else {
8063-
// TODO: Consider collecting up all the names of unrecognised
8064-
// in one string
8065-
croak_caller("Unrecognized named parameter '%" UTF8f "' to subroutine '%" SVf "'",
8066-
UTF8fARG(true, namelen, namepv), S_find_runcv_name());
8087+
accumulate_error_names(&n_errors, &error_names, namepv, namelen);
80678088
}
80688089
}
80698090

8091+
if(n_errors) {
8092+
if(n_errors > 5)
8093+
sv_catpvs(error_names, ", ...");
8094+
/* diag_listed_as: Unrecognized named parameter '%s' to subroutine '%s' */
8095+
croak_caller("Unrecognized named parameter%s %" SVf " to subroutine '%" SVf "'",
8096+
n_errors > 1 ? "s" : "", SVfARG(error_names), SVfARG(S_find_runcv_name()));
8097+
}
8098+
80708099
for(size_t namedix = 0; namedix < n_named; namedix++) {
80718100
struct op_multiparam_named_aux *named = aux->named + namedix;
80728101
if(!named->is_required || !SvPADSTALE(PAD_SVl(named->padix)))
80738102
continue;
80748103

8075-
// TODO: Consider collecting up all the names of missing
8076-
// parameters in one string
8077-
croak_caller("Missing required named parameter '%" UTF8f "' to subroutine '%" SVf "'",
8078-
UTF8fARG(true, named->namelen, named->namepv), S_find_runcv_name());
8104+
accumulate_error_names(&n_errors, &error_names, named->namepv, named->namelen);
8105+
}
8106+
8107+
if(n_errors) {
8108+
if(n_errors > 5)
8109+
sv_catpvs(error_names, ", ...");
8110+
/* diag_listed_as: Missing required named parameter '%s' to subroutine '%s' */
8111+
croak_caller("Missing required named parameter%s %" SVf " to subroutine '%" SVf "'",
8112+
n_errors > 1 ? "s" : "", SVfARG(error_names), SVfARG(S_find_runcv_name()));
80798113
}
80808114
}
80818115

t/lib/croak/signatures

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,9 +285,30 @@ f(alpha => 123); ## line 4
285285
EXPECT
286286
Missing required named parameter 'beta' to subroutine 'main::f' at - line 4.
287287
########
288+
# NAME multiple missing required named
289+
no warnings 'experimental::signature_named_parameters';
290+
sub f (:$alpha, :$beta) { } ## line 3
291+
f(); ## line 4
292+
EXPECT
293+
Missing required named parameters 'alpha', 'beta' to subroutine 'main::f' at - line 4.
294+
########
288295
# NAME unrecognised named
289296
no warnings 'experimental::signature_named_parameters';
290297
sub f (:$alpha) { } ## line 3
291298
f(alpha => 123, gamma => 456); ## line 4
292299
EXPECT
293300
Unrecognized named parameter 'gamma' to subroutine 'main::f' at - line 4.
301+
########
302+
# NAME multiple unrecognised named
303+
no warnings 'experimental::signature_named_parameters';
304+
sub f (:$alpha) { } ## line 3
305+
f(alpha => 123, gamma => 456, delta => 789); ## line 4
306+
EXPECT
307+
Unrecognized named parameters 'gamma', 'delta' to subroutine 'main::f' at - line 4.
308+
########
309+
# NAME multiple unrecognised named limiting
310+
no warnings 'experimental::signature_named_parameters';
311+
sub f (:$alpha) { } ## line 3
312+
f(alpha => 123, 'a' .. 'z'); ## line 4
313+
EXPECT
314+
Unrecognized named parameters 'a', 'c', 'e', 'g', 'i', ... to subroutine 'main::f' at - line 4.

0 commit comments

Comments
 (0)