mirror of
https://github.com/dlang/dmd.git
synced 2025-04-27 05:30:13 +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();
|
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
|
override Visibility visible() pure nothrow @nogc @safe
|
||||||
{
|
{
|
||||||
return visibility;
|
return visibility;
|
||||||
|
|
|
@ -1487,6 +1487,7 @@ public:
|
||||||
bool hasStaticCtorOrDtor() override;
|
bool hasStaticCtorOrDtor() override;
|
||||||
const char* kind() const override;
|
const char* kind() const override;
|
||||||
const char* toChars() const override;
|
const char* toChars() const override;
|
||||||
|
const char* toCharsNoConstraints() const;
|
||||||
Visibility visible() override;
|
Visibility visible() override;
|
||||||
const char* getConstraintEvalError(const char*& tip);
|
const char* getConstraintEvalError(const char*& tip);
|
||||||
TemplateDeclaration* isTemplateDeclaration() override;
|
TemplateDeclaration* isTemplateDeclaration() override;
|
||||||
|
@ -3981,6 +3982,7 @@ struct HdrGenState final
|
||||||
bool doFuncBodies;
|
bool doFuncBodies;
|
||||||
bool vcg_ast;
|
bool vcg_ast;
|
||||||
bool skipConstraints;
|
bool skipConstraints;
|
||||||
|
bool showOneMember;
|
||||||
bool fullQual;
|
bool fullQual;
|
||||||
int32_t tpltMember;
|
int32_t tpltMember;
|
||||||
int32_t autoMember;
|
int32_t autoMember;
|
||||||
|
@ -3997,6 +3999,7 @@ struct HdrGenState final
|
||||||
doFuncBodies(),
|
doFuncBodies(),
|
||||||
vcg_ast(),
|
vcg_ast(),
|
||||||
skipConstraints(),
|
skipConstraints(),
|
||||||
|
showOneMember(true),
|
||||||
fullQual(),
|
fullQual(),
|
||||||
tpltMember(),
|
tpltMember(),
|
||||||
autoMember(),
|
autoMember(),
|
||||||
|
@ -4007,7 +4010,7 @@ struct HdrGenState final
|
||||||
inEnumDecl()
|
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),
|
hdrgen(hdrgen),
|
||||||
ddoc(ddoc),
|
ddoc(ddoc),
|
||||||
fullDump(fullDump),
|
fullDump(fullDump),
|
||||||
|
@ -4015,6 +4018,7 @@ struct HdrGenState final
|
||||||
doFuncBodies(doFuncBodies),
|
doFuncBodies(doFuncBodies),
|
||||||
vcg_ast(vcg_ast),
|
vcg_ast(vcg_ast),
|
||||||
skipConstraints(skipConstraints),
|
skipConstraints(skipConstraints),
|
||||||
|
showOneMember(showOneMember),
|
||||||
fullQual(fullQual),
|
fullQual(fullQual),
|
||||||
tpltMember(tpltMember),
|
tpltMember(tpltMember),
|
||||||
autoMember(autoMember),
|
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).
|
// max num of overloads to print (-v or -verror-supplements overrides this).
|
||||||
const uint DisplayLimit = global.params.v.errorSupplementCount();
|
const uint DisplayLimit = global.params.v.errorSupplementCount();
|
||||||
const(char)* constraintsTip;
|
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())
|
if (auto fd = s.isFuncDeclaration())
|
||||||
{
|
{
|
||||||
|
@ -1765,16 +1779,14 @@ if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration))
|
||||||
return true;
|
return true;
|
||||||
auto tf = cast(TypeFunction) fd.type;
|
auto tf = cast(TypeFunction) fd.type;
|
||||||
OutBuffer buf;
|
OutBuffer buf;
|
||||||
buf.writestring(fd.toPrettyChars());
|
buf.writestring(child ? fd.toChars() : fd.toPrettyChars());
|
||||||
buf.writestring(parametersTypeToChars(tf.parameterList));
|
buf.writestring(parametersTypeToChars(tf.parameterList));
|
||||||
if (tf.mod)
|
if (tf.mod)
|
||||||
{
|
{
|
||||||
buf.writeByte(' ');
|
buf.writeByte(' ');
|
||||||
buf.MODtoBuffer(tf.mod);
|
buf.MODtoBuffer(tf.mod);
|
||||||
}
|
}
|
||||||
.errorSupplemental(fd.loc,
|
.errorSupplemental(fd.loc, "%s`%s`", errorPrefix(), buf.peekChars());
|
||||||
printed ? " `%s`" :
|
|
||||||
single_candidate ? "Candidate is: `%s`" : "Candidates are: `%s`", buf.peekChars());
|
|
||||||
}
|
}
|
||||||
else if (auto td = s.isTemplateDeclaration())
|
else if (auto td = s.isTemplateDeclaration())
|
||||||
{
|
{
|
||||||
|
@ -1782,35 +1794,43 @@ if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration))
|
||||||
|
|
||||||
if (!print)
|
if (!print)
|
||||||
return true;
|
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;
|
OutBuffer buf;
|
||||||
HdrGenState hgs;
|
HdrGenState hgs;
|
||||||
hgs.skipConstraints = true;
|
hgs.skipConstraints = true;
|
||||||
|
hgs.showOneMember = !recurse;
|
||||||
toCharsMaybeConstraints(td, buf, hgs);
|
toCharsMaybeConstraints(td, buf, hgs);
|
||||||
const tmsg = buf.peekChars();
|
const tmsg = buf.peekChars();
|
||||||
const cmsg = td.getConstraintEvalError(constraintsTip);
|
const cmsg = child ? null : td.getConstraintEvalError(constraintsTip);
|
||||||
|
|
||||||
// add blank space if there are multiple candidates
|
|
||||||
// the length of the blank space is `strlen("Candidates are: ")`
|
|
||||||
|
|
||||||
if (cmsg)
|
if (cmsg)
|
||||||
{
|
.errorSupplemental(td.loc, "%s`%s`\n%s", errorPrefix(), tmsg, cmsg);
|
||||||
.errorSupplemental(td.loc,
|
|
||||||
printed ? " `%s`\n%s" :
|
|
||||||
single_candidate ? "Candidate is: `%s`\n%s" : "Candidates are: `%s`\n%s",
|
|
||||||
tmsg, cmsg);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
|
.errorSupplemental(td.loc, "%s`%s`", errorPrefix(), tmsg);
|
||||||
|
|
||||||
|
if (recurse)
|
||||||
{
|
{
|
||||||
.errorSupplemental(td.loc,
|
child = true;
|
||||||
printed ? " `%s`" :
|
foreach (d; *td.members)
|
||||||
single_candidate ? "Candidate is: `%s`" : "Candidates are: `%s`",
|
{
|
||||||
tmsg);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
// determine if there's > 1 candidate
|
// determine if there's > 1 candidate
|
||||||
int count = 0;
|
|
||||||
overloadApply(declaration, (s) {
|
overloadApply(declaration, (s) {
|
||||||
if (matchSymbol(s, false))
|
if (matchSymbol(s, false))
|
||||||
count++;
|
count++;
|
||||||
|
@ -1820,7 +1840,7 @@ if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration))
|
||||||
overloadApply(declaration, (s) {
|
overloadApply(declaration, (s) {
|
||||||
if (global.params.v.verbose || printed < DisplayLimit)
|
if (global.params.v.verbose || printed < DisplayLimit)
|
||||||
{
|
{
|
||||||
if (matchSymbol(s, true, count == 1))
|
if (matchSymbol(s, true))
|
||||||
printed++;
|
printed++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -62,6 +62,7 @@ struct HdrGenState
|
||||||
bool doFuncBodies; /// include function bodies in output
|
bool doFuncBodies; /// include function bodies in output
|
||||||
bool vcg_ast; /// write out codegen-ast
|
bool vcg_ast; /// write out codegen-ast
|
||||||
bool skipConstraints; // skip constraints when doing templates
|
bool skipConstraints; // skip constraints when doing templates
|
||||||
|
bool showOneMember = true;
|
||||||
|
|
||||||
bool fullQual; /// fully qualify types when printing
|
bool fullQual; /// fully qualify types when printing
|
||||||
int tpltMember;
|
int tpltMember;
|
||||||
|
@ -1974,7 +1975,7 @@ void toCharsMaybeConstraints(const TemplateDeclaration td, ref OutBuffer buf, re
|
||||||
}
|
}
|
||||||
buf.writeByte(')');
|
buf.writeByte(')');
|
||||||
|
|
||||||
if (td.onemember)
|
if (hgs.showOneMember && td.onemember)
|
||||||
{
|
{
|
||||||
if (const fd = td.onemember.isFuncDeclaration())
|
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