From 94eb61432e9f1ad40af4118e6b44af6cb59565db Mon Sep 17 00:00:00 2001 From: Andrej Mitrovic Date: Mon, 28 Apr 2014 11:55:17 +0200 Subject: [PATCH] Fix Issue 8101 - Display candidate function overloads when function call fails. --- src/func.c | 139 +++++++++++++++++++++++++----- test/fail_compilation/diag10415.d | 6 +- test/fail_compilation/diag11078.d | 4 +- test/fail_compilation/diag8101.d | 63 ++++++++++++++ 4 files changed, 187 insertions(+), 25 deletions(-) create mode 100644 test/fail_compilation/diag8101.d diff --git a/src/func.c b/src/func.c index 51ae9cb0fa36..1e83547c29aa 100644 --- a/src/func.c +++ b/src/func.c @@ -3044,6 +3044,100 @@ MATCH FuncDeclaration::leastAsSpecialized(FuncDeclaration *g) return MATCHnomatch; } +/// Walk through candidate template overloads and print them in the diagnostics. +struct TemplateCandidateWalker +{ + Loc loc; + int numToDisplay; // max num of overloads to print (-v overrides this). + + /// Count template overloads. + struct CountWalker + { + int numOverloads; + + static int fp(void *param, Dsymbol *s) + { + CountWalker *p = (CountWalker *)param; + ++(p->numOverloads); + return 0; + } + }; + + static int fp(void *param, Dsymbol *s) + { + TemplateDeclaration *t = s->isTemplateDeclaration(); + if (!t) return 0; + + TemplateCandidateWalker *p = (TemplateCandidateWalker *)param; + + ::errorSupplemental(t->loc, "%s", t->toPrettyChars()); + + if (!global.params.verbose && --(p->numToDisplay) == 0 && t->overnext) + { + // Too many overloads to sensibly display. + // Just show count of remaining overloads. + CountWalker cw; + cw.numOverloads = 0; + overloadApply(t->overnext, &cw, &CountWalker::fp); + + if (cw.numOverloads > 0) + ::errorSupplemental(p->loc, "... (%d more, -v to show) ...", cw.numOverloads); + + return 1; // stop iterating + } + + return 0; + } +}; + +/// Walk through candidate template overloads and print them in the diagnostics. +struct FuncCandidateWalker +{ + Loc loc; + int numToDisplay; // max num of overloads to print (-v overrides this). + + /// Count function overloads. + struct CountWalker + { + int numOverloads; + + static int fp(void *param, Dsymbol *s) + { + CountWalker *p = (CountWalker *)param; + + if (s->isFuncDeclaration()) + ++(p->numOverloads); + + return 0; + } + }; + + static int fp(void *param, Dsymbol *s) + { + FuncDeclaration *f = s->isFuncDeclaration(); + if (!f) return 0; + + FuncCandidateWalker *p = (FuncCandidateWalker *)param; + + ::errorSupplemental(f->loc, "%s%s", f->toPrettyChars(), + Parameter::argsTypesToChars(((TypeFunction *)f->type)->parameters, ((TypeFunction *)f->type)->varargs)); + + if (!global.params.verbose && --(p->numToDisplay) == 0 && f->overnext) + { + CountWalker cw; + cw.numOverloads = 0; + overloadApply(f->overnext, &cw, &CountWalker::fp); + + if (cw.numOverloads > 0) + ::errorSupplemental(p->loc, "... (%d more, -v to show) ...", cw.numOverloads); + + return 1; // stop iterating + } + + return 0; + } +}; + /******************************************* * Given a symbol that could be either a FuncDeclaration or * a function template, resolve it to a function symbol. @@ -3144,51 +3238,52 @@ FuncDeclaration *resolveFuncCall(Loc loc, Scope *sc, Dsymbol *s, if (tthis) tthis->modToBuffer(&fargsBuf); + const int numOverloadsDisplay = 5; // sensible number to display + if (!m.lastf && !(flags & 1)) // no match { - if (td && !fd) // all of overloads are template + if (td && !fd) // all of overloads are templates { ::error(loc, "%s %s.%s cannot deduce function from argument types !(%s)%s, candidates are:", td->kind(), td->parent->toPrettyChars(), td->ident->toChars(), tiargsBuf.peekString(), fargsBuf.peekString()); - // Display candidate template functions - int numToDisplay = 5; // sensible number to display - for (TemplateDeclaration *tdx = td; tdx; tdx = tdx->overnext) - { - ::errorSupplemental(tdx->loc, "%s", tdx->toPrettyChars()); - if (!global.params.verbose && --numToDisplay == 0 && tdx->overnext) - { - // Too many overloads to sensibly display. - // Just show count of remaining overloads. - int remaining = 0; - for (TemplateDeclaration *tdy = tdx->overnext; tdy; tdy = tdy->overnext) - ++remaining; - if (remaining > 0) - ::errorSupplemental(loc, "... (%d more, -v to show) ...", remaining); - break; - } - } + // Display candidate templates (even if there are no multiple overloads) + TemplateCandidateWalker tcw; + tcw.loc = loc; + tcw.numToDisplay = numOverloadsDisplay; + overloadApply(td, &tcw, &TemplateCandidateWalker::fp); } else { assert(fd); + + const char *trailMsg = (fd->overnext != NULL) ? ", candidates are:" : ""; TypeFunction *tf = (TypeFunction *)fd->type; if (tthis && !MODimplicitConv(tthis->mod, tf->mod)) // modifier mismatch { OutBuffer thisBuf, funcBuf; MODMatchToBuffer(&thisBuf, tthis->mod, tf->mod); MODMatchToBuffer(&funcBuf, tf->mod, tthis->mod); - ::error(loc, "%smethod %s is not callable using a %sobject", - funcBuf.peekString(), fd->toPrettyChars(), thisBuf.peekString()); + ::error(loc, "%smethod %s is not callable using a %sobject%s", + funcBuf.peekString(), fd->toPrettyChars(), thisBuf.peekString(), trailMsg); } else { //printf("tf = %s, args = %s\n", tf->deco, (*fargs)[0]->type->deco); - fd->error(loc, "%s%s is not callable using argument types %s", + fd->error(loc, "%s%s is not callable using argument types %s%s", Parameter::argsTypesToChars(tf->parameters, tf->varargs), tf->modToChars(), - fargsBuf.peekString()); + fargsBuf.peekString(), trailMsg); + } + + // Display candidate functions (only when there are multiple overloads) + if (fd->overnext) + { + FuncCandidateWalker fcw; + fcw.loc = loc; + fcw.numToDisplay = numOverloadsDisplay; + overloadApply(fd, &fcw, &FuncCandidateWalker::fp); } } } diff --git a/test/fail_compilation/diag10415.d b/test/fail_compilation/diag10415.d index 721770f97a27..e975eb439418 100644 --- a/test/fail_compilation/diag10415.d +++ b/test/fail_compilation/diag10415.d @@ -1,8 +1,10 @@ /* TEST_OUTPUT: --- -fail_compilation/diag10415.d(34): Error: function diag10415.C.x () const is not callable using argument types (int) const -fail_compilation/diag10415.d(37): Error: d.x is not an lvalue +fail_compilation/diag10415.d(36): Error: function diag10415.C.x () const is not callable using argument types (int) const, candidates are: +fail_compilation/diag10415.d(13): diag10415.C.x() +fail_compilation/diag10415.d(18): diag10415.C.x(int _param_0) +fail_compilation/diag10415.d(39): Error: d.x is not an lvalue --- */ diff --git a/test/fail_compilation/diag11078.d b/test/fail_compilation/diag11078.d index 8d5499d44ce4..64c89b05905b 100644 --- a/test/fail_compilation/diag11078.d +++ b/test/fail_compilation/diag11078.d @@ -1,7 +1,9 @@ /* TEST_OUTPUT: --- -fail_compilation/diag11078.d(17): Error: function diag11078.S1.value () is not callable using argument types (double) +fail_compilation/diag11078.d(19): Error: function diag11078.S1.value () is not callable using argument types (double), candidates are: +fail_compilation/diag11078.d(12): diag11078.S1.value() +fail_compilation/diag11078.d(13): diag11078.S1.value(int n) --- */ diff --git a/test/fail_compilation/diag8101.d b/test/fail_compilation/diag8101.d new file mode 100644 index 000000000000..2ebc568211fa --- /dev/null +++ b/test/fail_compilation/diag8101.d @@ -0,0 +1,63 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag8101.d(56): Error: function diag8101.f_0 (int) is not callable using argument types () +fail_compilation/diag8101.d(57): Error: function diag8101.f_1 (int) is not callable using argument types (), candidates are: +fail_compilation/diag8101.d(32): diag8101.f_1(int) +fail_compilation/diag8101.d(33): diag8101.f_1(int, int) +fail_compilation/diag8101.d(58): Error: function diag8101.f_2 (int) is not callable using argument types (), candidates are: +fail_compilation/diag8101.d(35): diag8101.f_2(int) +fail_compilation/diag8101.d(36): diag8101.f_2(int, int) +fail_compilation/diag8101.d(37): diag8101.f_2(int, int, int) +fail_compilation/diag8101.d(38): diag8101.f_2(int, int, int, int) +fail_compilation/diag8101.d(39): diag8101.f_2(int, int, int, int, int) +fail_compilation/diag8101.d(58): ... (1 more, -v to show) ... +fail_compilation/diag8101.d(60): Error: template diag8101.t_0 cannot deduce function from argument types !()(), candidates are: +fail_compilation/diag8101.d(42): diag8101.t_0(T1)() +fail_compilation/diag8101.d(61): Error: template diag8101.t_1 cannot deduce function from argument types !()(), candidates are: +fail_compilation/diag8101.d(44): diag8101.t_1(T1)() +fail_compilation/diag8101.d(45): diag8101.t_1(T1, T2)() +fail_compilation/diag8101.d(62): Error: template diag8101.t_2 cannot deduce function from argument types !()(), candidates are: +fail_compilation/diag8101.d(47): diag8101.t_2(T1)() +fail_compilation/diag8101.d(48): diag8101.t_2(T1, T2)() +fail_compilation/diag8101.d(49): diag8101.t_2(T1, T2, T3)() +fail_compilation/diag8101.d(50): diag8101.t_2(T1, T2, T3, T4)() +fail_compilation/diag8101.d(51): diag8101.t_2(T1, T2, T3, T4, T5)() +fail_compilation/diag8101.d(62): ... (1 more, -v to show) ... +--- +*/ + +void f_0(int); + +void f_1(int); +void f_1(int, int); + +void f_2(int); +void f_2(int, int); +void f_2(int, int, int); +void f_2(int, int, int, int); +void f_2(int, int, int, int, int); +void f_2(int, int, int, int, int, int); + +void t_0(T1)(); + +void t_1(T1)(); +void t_1(T1, T2)(); + +void t_2(T1)(); +void t_2(T1, T2)(); +void t_2(T1, T2, T3)(); +void t_2(T1, T2, T3, T4)(); +void t_2(T1, T2, T3, T4, T5)(); +void t_2(T1, T2, T3, T4, T5, T6)(); + +void main() +{ + f_0(); + f_1(); + f_2(); + + t_0(); + t_1(); + t_2(); +}