Fix Issue 24135 - Eponymous template member overloads not shown as call candidates (#15572)

This commit is contained in:
Nick Treleaven 2024-06-01 00:47:19 +01:00 committed by GitHub
parent 61b95f3584
commit 1b2b3dd763
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 99 additions and 25 deletions

View file

@ -751,6 +751,17 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
return buf.extractChars();
}
/****************************
* Similar to `toChars`, but does not print the template constraints
*/
const(char)* toCharsNoConstraints() const
{
HdrGenState hgs = { skipConstraints: true };
OutBuffer buf;
toCharsMaybeConstraints(this, buf, hgs);
return buf.extractChars();
}
override Visibility visible() pure nothrow @nogc @safe
{
return visibility;

View file

@ -1487,6 +1487,7 @@ public:
bool hasStaticCtorOrDtor() override;
const char* kind() const override;
const char* toChars() const override;
const char* toCharsNoConstraints() const;
Visibility visible() override;
const char* getConstraintEvalError(const char*& tip);
TemplateDeclaration* isTemplateDeclaration() override;
@ -3981,6 +3982,7 @@ struct HdrGenState final
bool doFuncBodies;
bool vcg_ast;
bool skipConstraints;
bool showOneMember;
bool fullQual;
int32_t tpltMember;
int32_t autoMember;
@ -3997,6 +3999,7 @@ struct HdrGenState final
doFuncBodies(),
vcg_ast(),
skipConstraints(),
showOneMember(true),
fullQual(),
tpltMember(),
autoMember(),
@ -4007,7 +4010,7 @@ struct HdrGenState final
inEnumDecl()
{
}
HdrGenState(bool hdrgen, bool ddoc = false, bool fullDump = false, bool importcHdr = false, bool doFuncBodies = false, bool vcg_ast = false, bool skipConstraints = false, bool fullQual = false, int32_t tpltMember = 0, int32_t autoMember = 0, int32_t forStmtInit = 0, int32_t insideFuncBody = 0, int32_t insideAggregate = 0, bool declstring = false, EnumDeclaration* inEnumDecl = nullptr) :
HdrGenState(bool hdrgen, bool ddoc = false, bool fullDump = false, bool importcHdr = false, bool doFuncBodies = false, bool vcg_ast = false, bool skipConstraints = false, bool showOneMember = true, bool fullQual = false, int32_t tpltMember = 0, int32_t autoMember = 0, int32_t forStmtInit = 0, int32_t insideFuncBody = 0, int32_t insideAggregate = 0, bool declstring = false, EnumDeclaration* inEnumDecl = nullptr) :
hdrgen(hdrgen),
ddoc(ddoc),
fullDump(fullDump),
@ -4015,6 +4018,7 @@ struct HdrGenState final
doFuncBodies(doFuncBodies),
vcg_ast(vcg_ast),
skipConstraints(skipConstraints),
showOneMember(showOneMember),
fullQual(fullQual),
tpltMember(tpltMember),
autoMember(autoMember),

View file

@ -1746,10 +1746,24 @@ if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration))
// max num of overloads to print (-v or -verror-supplements overrides this).
const uint DisplayLimit = global.params.v.errorSupplementCount();
const(char)* constraintsTip;
// determine if the first candidate was printed
int printed;
bool matchSymbol(Dsymbol s, bool print, bool single_candidate = false)
int printed = 0; // number of candidates printed
int count = 0; // total candidates
bool child; // true if inside an eponymous template
const(char)* errorPrefix() @safe
{
if (child)
return " - Containing: ";
// align with blank spaces after first message
enum plural = "Candidates are: ";
enum spaces = " ";
if (printed)
return spaces;
return (count == 1) ? "Candidate is: " : plural;
}
bool matchSymbol(Dsymbol s, bool print)
{
if (auto fd = s.isFuncDeclaration())
{
@ -1765,16 +1779,14 @@ if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration))
return true;
auto tf = cast(TypeFunction) fd.type;
OutBuffer buf;
buf.writestring(fd.toPrettyChars());
buf.writestring(child ? fd.toChars() : fd.toPrettyChars());
buf.writestring(parametersTypeToChars(tf.parameterList));
if (tf.mod)
{
buf.writeByte(' ');
buf.MODtoBuffer(tf.mod);
}
.errorSupplemental(fd.loc,
printed ? " `%s`" :
single_candidate ? "Candidate is: `%s`" : "Candidates are: `%s`", buf.peekChars());
.errorSupplemental(fd.loc, "%s`%s`", errorPrefix(), buf.peekChars());
}
else if (auto td = s.isTemplateDeclaration())
{
@ -1782,35 +1794,43 @@ if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration))
if (!print)
return true;
// td.onemember may not have overloads set
// (see fail_compilation/onemember_overloads.d)
// assume if more than one member it is overloaded internally
bool recurse = td.onemember && td.members.length > 1;
OutBuffer buf;
HdrGenState hgs;
hgs.skipConstraints = true;
hgs.showOneMember = !recurse;
toCharsMaybeConstraints(td, buf, hgs);
const tmsg = buf.peekChars();
const cmsg = td.getConstraintEvalError(constraintsTip);
// add blank space if there are multiple candidates
// the length of the blank space is `strlen("Candidates are: ")`
const cmsg = child ? null : td.getConstraintEvalError(constraintsTip);
if (cmsg)
{
.errorSupplemental(td.loc,
printed ? " `%s`\n%s" :
single_candidate ? "Candidate is: `%s`\n%s" : "Candidates are: `%s`\n%s",
tmsg, cmsg);
}
.errorSupplemental(td.loc, "%s`%s`\n%s", errorPrefix(), tmsg, cmsg);
else
.errorSupplemental(td.loc, "%s`%s`", errorPrefix(), tmsg);
if (recurse)
{
.errorSupplemental(td.loc,
printed ? " `%s`" :
single_candidate ? "Candidate is: `%s`" : "Candidates are: `%s`",
tmsg);
child = true;
foreach (d; *td.members)
{
if (d.ident != td.ident)
continue;
if (auto fd2 = d.isFuncDeclaration())
matchSymbol(fd2, print);
else if (auto td2 = d.isTemplateDeclaration())
matchSymbol(td2, print);
}
child = false;
}
}
return true;
}
// determine if there's > 1 candidate
int count = 0;
overloadApply(declaration, (s) {
if (matchSymbol(s, false))
count++;
@ -1820,7 +1840,7 @@ if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration))
overloadApply(declaration, (s) {
if (global.params.v.verbose || printed < DisplayLimit)
{
if (matchSymbol(s, true, count == 1))
if (matchSymbol(s, true))
printed++;
}
else

View file

@ -62,6 +62,7 @@ struct HdrGenState
bool doFuncBodies; /// include function bodies in output
bool vcg_ast; /// write out codegen-ast
bool skipConstraints; // skip constraints when doing templates
bool showOneMember = true;
bool fullQual; /// fully qualify types when printing
int tpltMember;
@ -1974,7 +1975,7 @@ void toCharsMaybeConstraints(const TemplateDeclaration td, ref OutBuffer buf, re
}
buf.writeByte(')');
if (td.onemember)
if (hgs.showOneMember && td.onemember)
{
if (const fd = td.onemember.isFuncDeclaration())
{

View file

@ -0,0 +1,38 @@
/*
TEST_OUTPUT:
---
fail_compilation/onemember_overloads.d(29): Error: none of the overloads of `skipOver` are callable using argument types `()`
fail_compilation/onemember_overloads.d(25): Candidates are: `onemember_overloads.skipOver(string)`
fail_compilation/onemember_overloads.d(18): `skipOver(alias pred = (a, b) => a == b)`
fail_compilation/onemember_overloads.d(20): - Containing: `skipOver(Haystack, Needles...)(ref Haystack haystack, Needles needles)`
fail_compilation/onemember_overloads.d(21): - Containing: `skipOver(R)(ref R r1)`
fail_compilation/onemember_overloads.d(22): - Containing: `skipOver(R, Es...)(ref R r, Es es)`
fail_compilation/onemember_overloads.d(30): Error: template `t2` is not callable using argument types `!()()`
fail_compilation/onemember_overloads.d(33): Candidate is: `t2(T)`
fail_compilation/onemember_overloads.d(35): - Containing: `t2(string)`
fail_compilation/onemember_overloads.d(36): - Containing: `t2(int[])`
fail_compilation/onemember_overloads.d(37): - Containing: `t2(R)(R)`
---
*/
template skipOver(alias pred = (a, b) => a == b)
{
bool skipOver(Haystack, Needles...)(ref Haystack haystack, Needles needles) => true;
bool skipOver(R)(ref R r1) => true;
bool skipOver(R, Es...)(ref R r, Es es) => true;
}
void skipOver(string);
void main()
{
skipOver();
t2();
}
template t2(T)
{
bool t2(string);
bool t2(int[]);
bool t2(R)(R);
}