New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix Issue 15613, 11529: Show parameter mismatch and rvalue/lvalue ref message #7554
Conversation
Thanks for your pull request, @ntrel! We are looking forward to reviewing it, and you should be hearing from a maintainer soon. Some tips to help speed things up:
Bear in mind that large or tricky changes may require multiple rounds of review and revision. Please see CONTRIBUTING.md for more information. Bugzilla references
|
5ecde07
to
244000b
Compare
Better diagnostics is exactly what D needs right now! Great work! |
src/dmd/func.d
Outdated
@@ -3618,3 +3620,21 @@ extern (C++) final class DeleteDeclaration : FuncDeclaration | |||
v.visit(this); | |||
} | |||
} | |||
|
|||
void showArgMismatch(Loc loc, Expressions* fargs, TypeFunction tf, size_t failIndex) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add Ddoc style function comment.
src/dmd/func.d
Outdated
auto msg = "cannot pass %sargument `%s` of type `%s` to parameter `%s`"; | ||
// don't print parameter type if it's already in the parameter string | ||
if (strcmp(par.type.toChars(), ts[1]) != 0) | ||
msg ~= " of type `%s`"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't guaranteed to produce a 0 terminated array.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just use two different msg
strings.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i.e.:
msg = strcmp() ? "cannot pass ..." : "cannot pass ... of type ...";
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed by adding \0
to 2nd string, hope that's OK?
src/dmd/hdrgen.d
Outdated
@@ -3433,3 +3433,17 @@ extern (C++) const(char)* parametersTypeToChars(Parameters* parameters, int vara | |||
v.parametersToBuffer(parameters, varargs); | |||
return buf.extractString(); | |||
} | |||
|
|||
extern (C++) const(char)* parameterToChars(Parameter parameter, int varargs) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add Ddoc function comment.
src/dmd/mtype.d
Outdated
@@ -5935,6 +5936,7 @@ extern (C++) final class TypeFunction : TypeNext | |||
} | |||
} | |||
|
|||
auto u = size_t.max; // used for failedIndex if no match |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer having a bool failed
and a size_t failedIndex
and use failed
to determine whether or not failedIndex
holds a valid value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can just check the return value against MATCH.nomatch
to determine if failedIndex
is valid.
src/dmd/hdrgen.d
Outdated
* parameter = parameter to print. | ||
* varargs = Kind of varargs, see TypeFunction.varargs. | ||
* Returns: NT string representing parameter. */ | ||
extern (C++) const(char)* parameterToChars(Parameter parameter, int varargs) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DDoc also needs a summary, and what does "NT" mean? If "null-terminated", spell it out please.
src/dmd/hdrgen.d
Outdated
/** Params: | ||
* parameters = parameters to print, such as TypeFunction.parameters. | ||
* varargs = Kind of varargs, see TypeFunction.varargs. | ||
* Returns: NT string representing parameters. */ | ||
extern (C++) const(char)* parametersTypeToChars(Parameters* parameters, int varargs) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DDoc also needs a summary, and what does "NT" mean? If "null-terminated", spell it out please.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please don't abbreviate null-terminated.
test/fail_compilation/bug9631.d
Outdated
TEST_OUTPUT: | ||
--- | ||
fail_compilation/bug9631.d(79): Error: function bug9631.arg.f `(int i, S s)` is not callable using argument types `(int, S)` | ||
fail_compilation/bug9631.d(79): cannot pass argument `y` of type `bug9631.tem!().S` to parameter `S s` of type `bug9631.S` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
function bug9631.arg.f `(int i, S s)` is not callable using argument types `(int, S)`
- Tick marks should surround the entire function declaration (e.g `bug9631.arg.f (int i, S s)`). That may be a difficult thing to do and I'd be willing to pass on the tick marks for now
- The function accepts
(int, S)
but the error message says it's not callable using(int, S)
. Does this need fully qualified names or something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cannot pass argument
y
of typebug9631.tem!().S
to parameterS s
of typebug9631.S
I suspect this line is supposed the clarify the first, but it's awfully confusing. Can't we have just one line with fully qualified type names?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bug9631.arg.f `(int i, S s)`
This was introduced by Walter before this PR. I tried to fix it but can't work out why exactly it happens.
test/fail_compilation/bug9631.d
Outdated
fail_compilation/bug9631.d(80): Error: function literal `__lambda2(S s)` is not callable using argument types `(S)` | ||
fail_compilation/bug9631.d(80): cannot pass argument `x` of type `bug9631.S` to parameter `S s` of type `bug9631.tem!().S` | ||
fail_compilation/bug9631.d(86): Error: constructor bug9631.arg.A.this `(S _param_0)` is not callable using argument types `(S)` | ||
fail_compilation/bug9631.d(86): cannot pass argument `S(0)` of type `bug9631.tem!().S` to parameter `S _param_0` of type `bug9631.S` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cannot pass argument `S(0)`
`S(0)` doesn't look like an argument; it looks like a function invocation OK, I get it now, though I'm not sure we're making much progress on clarifying these messages.
to parameter `S _param_0` of type `bug9631.S`
I think this should read "... to parameter `bug9631.S _param_0`" without redundantly specifying one unqualified type name `S` and one qualified type name `bug9631.S`
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
test/fail_compilation/diag8101b.d
Outdated
fail_compilation/diag8101b.d(18): `diag8101b.S.foo(int _param_0)` | ||
fail_compilation/diag8101b.d(19): `diag8101b.S.foo(int _param_0, int _param_1)` | ||
fail_compilation/diag8101b.d(29): Error: function diag8101b.S.bar `(int _param_0)` is not callable using argument types `(double)` | ||
fail_compilation/diag8101b.d(29): cannot pass argument `1.00000` of type `double` to parameter `int _param_0` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we shoot for something like:
function
diag8101b.S.bar (int _param_0)
is not callable using argument1.00000
of typedouble
to parameterint _param_0
You might even be able to make it less verbose with...
function
diag8101b.S.bar
is not callable using argument1.00000
of typedouble
to parameterint _param_0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's useful to see the full parameter list, so we know which function the compiler means. If we combine both messages I think there's too much information in one sentence.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's useful to see all the argument types too.
test/fail_compilation/diag8101b.d
Outdated
fail_compilation/diag8101b.d(17): `diag8101b.S.foo(int _param_0)` | ||
fail_compilation/diag8101b.d(18): `diag8101b.S.foo(int _param_0, int _param_1)` | ||
fail_compilation/diag8101b.d(33): Error: mutable method `diag8101b.S.bar` is not callable using a const object | ||
fail_compilation/diag8101b.d(27): Error: none of the overloads of `foo` are callable using argument types `(double)`, candidates are: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The term "argument types" seems odd here. What about...
none of the overloads of
foo
are callable using parameter list(double)
, candidates are:
This also removes the plural "types" with the singular parameter type oddity.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, it's talking about arguments so "argument list" would work. But this is not part of the PR, I expect argument types is used elsewhere too.
BTW, I also have code to do the same for deduced template function calls (if there are no overloads), but I'll wait until this is merged to submit. |
src/dmd/hdrgen.d
Outdated
parameter.accept(v); | ||
if (varargs) | ||
{ | ||
buf.writestring("..."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
need test case to cover this new line
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added test, turns out it was wrong for variadic parameters :-/
src/dmd/hdrgen.d
Outdated
* parameter = parameter to print. | ||
* varargs = kind of varargs, see TypeFunction.varargs. | ||
* fullQual = whether to fully qualify types. | ||
* Returns: Null-terminated string representing parameters. */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Please conform to the existing way Ddoc comments are formatted in the front end. To wit:
/****
* blah blah
*/
not:
/** blah blah
* blah blah */
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done for this module.
src/dmd/mtype.d
Outdated
@@ -9224,7 +9228,7 @@ const(char*)[2] toAutoQualChars(Type t1, Type t2) | |||
{ | |||
auto s1 = t1.toChars(); | |||
auto s2 = t2.toChars(); | |||
if (strcmp(s1, s2) == 0) | |||
if (!t1.equals(t2) && strcmp(s1, s2) == 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
when would the type strings be the same but they are different types?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When the strings aren't the full qualified type, e.g. S
vs tem!().S
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add comment to that effect.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
src/dmd/hdrgen.d
Outdated
@@ -3433,3 +3438,24 @@ extern (C++) const(char)* parametersTypeToChars(Parameters* parameters, int vara | |||
v.parametersToBuffer(parameters, varargs); | |||
return buf.extractString(); | |||
} | |||
|
|||
/** Pretty print function parameters. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This has the same description and return value as the previous function - what does it do different?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo, should be parameter. Fixed.
src/dmd/expressionsem.d
Outdated
|
||
.error(exp.loc, "`%s%s` is not callable using argument types `%s`", | ||
exp.e1.toChars(), parametersTypeToChars(tf.parameters, tf.varargs), buf.peekString()); | ||
showArgMismatch(exp.loc, exp.arguments, tf, failIndex); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It'd be nice to have test coverage for the new code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW, what does TOKvar mean? I'm trying to hit this case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TOKvar
distinguishes a VarExp
from other Expression types.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know how to test for the case when TOKvar is a function. Function pointers are handled differently.
src/dmd/dtemplate.d
Outdated
@@ -2325,8 +2325,10 @@ extern (C++) final class TypeDeduced : Type | |||
* tiargs initial list of template arguments | |||
* tthis if !NULL, the 'this' pointer argument | |||
* fargs arguments to function | |||
* failedIndex address to store argument index of first type mismatch |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
note that failedIndex
can be null
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've noted this for pMessage
(which replaced failedIndex
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be in Ddoc style:
Params:
- use
=
- then Ddoc can would throw an error about the non-existingfailedIndex
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Definitely an improvement.
Rebased to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Really cool!
@wilzbach Thanks for rebasing. I changed the ddoc comments to use |
Show the first argument that fails to match the function parameters. This is also part of: Issue 9631 - Error message not using fully qualified name when appropriate
Also hide separate parameter type when already shown.
Rebased again ;-) |
So yesterday I dusted off an old project and tried to compile. Sure thing, I ran out of memory. This project used to take 2, max 3 GBs of memory. Now it runs out of memory after reaching 7 GBs. As a result I started to bisect, which led me to this commit after a bit of gymnastic (having class Bar { this(int) {} }
void main () { scope b = new Bar; } but that was fixed by later refactoring. Second commit (ff99241) doesn't compile because it was blindly rebased after the Now the cherry on the top: this pull request (or more precisely, commit 6) allocates an error message for every matching failure during call resolution. And that memory is allocated with It comes down to commit 6, which eagerly generates error message. @ntrel what was the motivation for it ? |
@Geod24 Thanks for finding this. I think the problem is the call to |
When there's only one overload to consider: