mirror of
https://github.com/dlang/dmd.git
synced 2025-04-26 21:21:48 +03:00
Fix Issue 24135 - Eponymous template member overloads not shown as call candidates (#15572)
This commit is contained in:
parent
61b95f3584
commit
1b2b3dd763
5 changed files with 99 additions and 25 deletions
|
@ -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;
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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())
|
||||
{
|
||||
|
|
38
compiler/test/fail_compilation/onemember_overloads.d
Normal file
38
compiler/test/fail_compilation/onemember_overloads.d
Normal 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);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue