From 48c6b49605e265e043e9a37fe6064ec603679619 Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Wed, 20 Dec 2017 16:05:47 +0000 Subject: [PATCH 01/10] Fix Issue 15613 - Parameter type mismatch error message not very helpful 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 --- src/dmd/dtemplate.d | 6 ++-- src/dmd/expressionsem.d | 15 ++++++---- src/dmd/func.d | 16 ++++++++++- src/dmd/hdrgen.d | 14 +++++++++ src/dmd/mtype.d | 12 +++++--- test/fail_compilation/bug9631.d | 50 +++++++++++++++++++++++++++++++++ test/fail_compilation/ice8255.d | 6 ++-- 7 files changed, 104 insertions(+), 15 deletions(-) diff --git a/src/dmd/dtemplate.d b/src/dmd/dtemplate.d index a4dbdc27554c..95613502434f 100644 --- a/src/dmd/dtemplate.d +++ b/src/dmd/dtemplate.d @@ -2329,8 +2329,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 */ -void functionResolve(Match* m, Dsymbol dstart, Loc loc, Scope* sc, Objects* tiargs, Type tthis, Expressions* fargs) +void functionResolve(Match* m, Dsymbol dstart, Loc loc, Scope* sc, Objects* tiargs, + Type tthis, Expressions* fargs, size_t* failedIndex = null) { version (none) { @@ -2416,7 +2418,7 @@ void functionResolve(Match* m, Dsymbol dstart, Loc loc, Scope* sc, Objects* tiar else return 0; // MATCH.nomatch } - MATCH mfa = tf.callMatch(tthis_fd, fargs); + MATCH mfa = tf.callMatch(tthis_fd, fargs, 0, failedIndex); //printf("test1: mfa = %d\n", mfa); if (mfa > MATCH.nomatch) { diff --git a/src/dmd/expressionsem.d b/src/dmd/expressionsem.d index 345f64343f97..81f69272f48c 100644 --- a/src/dmd/expressionsem.d +++ b/src/dmd/expressionsem.d @@ -3430,7 +3430,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); } - if (!tf.callMatch(null, exp.arguments)) + size_t failIndex; + if (!tf.callMatch(null, exp.arguments, 0, &failIndex)) { OutBuffer buf; buf.writeByte('('); @@ -3440,7 +3441,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor tthis.modToBuffer(&buf); //printf("tf = %s, args = %s\n", tf.deco, (*arguments)[0].type.deco); - .error(exp.loc, "%s `%s%s` is not callable using argument types `%s`", p, exp.e1.toChars(), parametersTypeToChars(tf.parameters, tf.varargs), buf.peekString()); + .error(exp.loc, "%s `%s%s` is not callable using argument types `%s`", + p, exp.e1.toChars(), parametersTypeToChars(tf.parameters, tf.varargs), buf.peekString()); + showArgMismatch(exp.loc, exp.arguments, tf, failIndex); return setError(); } // Purity and safety check should run after testing arguments matching @@ -3500,7 +3503,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { exp.f = exp.f.toAliasFunc(); TypeFunction tf = cast(TypeFunction)exp.f.type; - if (!tf.callMatch(null, exp.arguments)) + size_t failIndex; + if (!tf.callMatch(null, exp.arguments, 0, &failIndex)) { OutBuffer buf; buf.writeByte('('); @@ -3508,8 +3512,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor buf.writeByte(')'); //printf("tf = %s, args = %s\n", tf.deco, (*arguments)[0].type.deco); - .error(exp.loc, "`%s%s` is not callable using argument types `%s`", exp.e1.toChars(), parametersTypeToChars(tf.parameters, tf.varargs), buf.peekString()); - + .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); exp.f = null; } } diff --git a/src/dmd/func.d b/src/dmd/func.d index a99637fb2fd2..f915b802d8bf 100644 --- a/src/dmd/func.d +++ b/src/dmd/func.d @@ -2481,7 +2481,8 @@ extern (C++) FuncDeclaration resolveFuncCall(Loc loc, Scope* sc, Dsymbol s, Match m; m.last = MATCH.nomatch; - functionResolve(&m, s, loc, sc, tiargs, tthis, fargs); + size_t failIndex; + functionResolve(&m, s, loc, sc, tiargs, tthis, fargs, &failIndex); if (m.last > MATCH.nomatch && m.lastf) { @@ -2599,6 +2600,7 @@ extern (C++) FuncDeclaration resolveFuncCall(Loc loc, Scope* sc, Dsymbol s, .error(loc, "%s `%s%s%s` is not callable using argument types `%s`", fd.kind(), fd.toPrettyChars(), parametersTypeToChars(tf.parameters, tf.varargs), tf.modToChars(), fargsBuf.peekString()); + showArgMismatch(loc, fargs, tf, failIndex); } } @@ -3632,3 +3634,15 @@ extern (C++) final class DeleteDeclaration : FuncDeclaration v.visit(this); } } + +void showArgMismatch(Loc loc, Expressions* fargs, TypeFunction tf, size_t failIndex) +{ + if (failIndex < fargs.dim && failIndex < tf.parameters.dim) + { + auto arg = (*fargs)[failIndex]; + auto par = (*tf.parameters)[failIndex]; + auto ts = toAutoQualChars(arg.type, par.type); + errorSupplemental(loc, "cannot pass argument `%s` of type `%s` to parameter `%s` (of type `%s`)", + arg.toChars(), ts[0], parameterToChars(par, tf.varargs), ts[1]); + } +} diff --git a/src/dmd/hdrgen.d b/src/dmd/hdrgen.d index dbb5dc4fd86c..3e6ed2b5abbf 100644 --- a/src/dmd/hdrgen.d +++ b/src/dmd/hdrgen.d @@ -3429,3 +3429,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) +{ + OutBuffer buf; + HdrGenState hgs; + scope PrettyPrintVisitor v = new PrettyPrintVisitor(&buf, &hgs); + + parameter.accept(v); + if (varargs) + { + buf.writestring("..."); + } + return buf.extractString(); +} diff --git a/src/dmd/mtype.d b/src/dmd/mtype.d index 8770f0dcbb90..908a10280131 100644 --- a/src/dmd/mtype.d +++ b/src/dmd/mtype.d @@ -5890,10 +5890,11 @@ extern (C++) final class TypeFunction : TypeNext * Determine match level. * Input: * flag 1 performing a partial ordering match + * failedIndex address to store argument index of first type mismatch * Returns: * MATCHxxxx */ - MATCH callMatch(Type tthis, Expressions* args, int flag = 0) + MATCH callMatch(Type tthis, Expressions* args, int flag = 0, size_t* failedIndex = null) { //printf("TypeFunction::callMatch() %s\n", toChars()); MATCH match = MATCH.exact; // assume exact match @@ -5928,6 +5929,7 @@ extern (C++) final class TypeFunction : TypeNext } } + auto u = size_t.max; // used for failedIndex if no match size_t nparams = Parameter.dim(parameters); size_t nargs = args ? args.dim : 0; if (nparams == nargs) @@ -5941,7 +5943,7 @@ extern (C++) final class TypeFunction : TypeNext match = MATCH.convert; // match ... with a "conversion" match level } - for (size_t u = 0; u < nargs; u++) + for (u = 0; u < nargs; u++) { if (u >= nparams) break; @@ -5974,7 +5976,7 @@ extern (C++) final class TypeFunction : TypeNext } } - for (size_t u = 0; u < nparams; u++) + for (u = 0; u < nparams; u++) { MATCH m; @@ -6152,6 +6154,8 @@ extern (C++) final class TypeFunction : TypeNext Nomatch: //printf("no match\n"); + if (failedIndex) + *failedIndex = u; return MATCH.nomatch; } @@ -9237,7 +9241,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) { s1 = t1.toPrettyChars(true); s2 = t2.toPrettyChars(true); diff --git a/test/fail_compilation/bug9631.d b/test/fail_compilation/bug9631.d index d4113bcfd17e..da2d5f616fc6 100644 --- a/test/fail_compilation/bug9631.d +++ b/test/fail_compilation/bug9631.d @@ -58,3 +58,53 @@ void test3() S[1] sa = cast(S[1])ta; auto t2 = cast(tem!().S[])sa; } + +/* +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 implicitly convert expression `y` of type `bug9631.tem!().S` to `bug9631.S` +fail_compilation/bug9631.d(80): Error: function literal __lambda2 (S s) is not callable using argument types (S) +fail_compilation/bug9631.d(80): cannot implicitly convert expression `x` of type `bug9631.S` to `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 implicitly convert expression `S(0)` of type `bug9631.tem!().S` to `bug9631.S` +--- +*/ +void arg() +{ + S x; + tem!().S y; + + void f(int i, S s){}; + f(4, y); + (tem!().S s){}(x); + + struct A + { + this(S){} + } + A(tem!().S()); +} + +/* +TEST_OUTPUT: +--- +fail_compilation/bug9631.d(105): Error: function bug9631.targ.ft!().ft (S _param_0) is not callable using argument types (S) +fail_compilation/bug9631.d(105): cannot implicitly convert expression `x` of type `bug9631.S` to `bug9631.tem!().S` +fail_compilation/bug9631.d(106): Error: template bug9631.targ.ft cannot deduce function from argument types !()(S), candidates are: +fail_compilation/bug9631.d(104): bug9631.targ.ft()(tem!().S) +fail_compilation/bug9631.d(108): Error: template bug9631.targ.ft2 cannot deduce function from argument types !()(S, int), candidates are: +fail_compilation/bug9631.d(107): bug9631.targ.ft2(T)(S, T) +*/ +void targ() +{ + S x; + tem!().S y; + + void ft()(tem!().S){} + ft!()(x); + ft(x); + void ft2(T)(S, T){} + ft2(y, 1); +} + diff --git a/test/fail_compilation/ice8255.d b/test/fail_compilation/ice8255.d index 1fbb6fded54e..a550704bd58f 100644 --- a/test/fail_compilation/ice8255.d +++ b/test/fail_compilation/ice8255.d @@ -1,9 +1,9 @@ /* TEST_OUTPUT: --- -fail_compilation/ice8255.d(10): Error: function `ice8255.F!(G).F.f(ref G _param_0)` is not callable using argument types `(G)` -fail_compilation/ice8255.d(10): while evaluating `pragma(msg, F().f(G()))` ---- +fail_compilation/ice8255.d(11): Error: function `ice8255.F!(G).F.f(ref G _param_0)` is not callable using argument types `(G)` +fail_compilation/ice8255.d(11): cannot pass rvalue argument `G()` of type `G` to parameter `ref G _param_0` +fail_compilation/ice8255.d(11): while evaluating pragma(msg, F().f(G())) */ struct G {} struct F(T) { void f(ref T) {} } From ff99241a38068e85af6e2625e10ce78b2201de57 Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Fri, 29 Dec 2017 14:25:30 +0000 Subject: [PATCH 02/10] Fix Issue 11529 - Unclear error message when rvalue is passed as `ref' Also hide separate parameter type when already shown. --- src/dmd/func.d | 12 +++++++++--- test/fail_compilation/bug9631.d | 27 ++++++++++++++------------- test/fail_compilation/diag13082.d | 6 ++++-- test/fail_compilation/diag8101b.d | 17 +++++++++-------- test/fail_compilation/fail263.d | 3 ++- test/fail_compilation/fail322.d | 3 ++- test/fail_compilation/fail53.d | 3 ++- test/fail_compilation/fail55.d | 3 ++- test/fail_compilation/ice14923.d | 5 +++-- 9 files changed, 47 insertions(+), 32 deletions(-) diff --git a/src/dmd/func.d b/src/dmd/func.d index f915b802d8bf..1e41bc2fdc98 100644 --- a/src/dmd/func.d +++ b/src/dmd/func.d @@ -3641,8 +3641,14 @@ void showArgMismatch(Loc loc, Expressions* fargs, TypeFunction tf, size_t failIn { auto arg = (*fargs)[failIndex]; auto par = (*tf.parameters)[failIndex]; - auto ts = toAutoQualChars(arg.type, par.type); - errorSupplemental(loc, "cannot pass argument `%s` of type `%s` to parameter `%s` (of type `%s`)", - arg.toChars(), ts[0], parameterToChars(par, tf.varargs), ts[1]); + const rv = (!arg.isLvalue() && par.storageClass & (STCref | STCout)) ? "rvalue " : ""; + const pc = parameterToChars(par, tf.varargs); + const ts = toAutoQualChars(arg.type, par.type); + 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`"; + errorSupplemental(loc, msg.ptr, + rv.ptr, arg.toChars(), ts[0], pc, ts[1]); } } diff --git a/test/fail_compilation/bug9631.d b/test/fail_compilation/bug9631.d index da2d5f616fc6..89d985208fb9 100644 --- a/test/fail_compilation/bug9631.d +++ b/test/fail_compilation/bug9631.d @@ -62,12 +62,12 @@ void test3() /* 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 implicitly convert expression `y` of type `bug9631.tem!().S` to `bug9631.S` -fail_compilation/bug9631.d(80): Error: function literal __lambda2 (S s) is not callable using argument types (S) -fail_compilation/bug9631.d(80): cannot implicitly convert expression `x` of type `bug9631.S` to `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 implicitly convert expression `S(0)` of type `bug9631.tem!().S` to `bug9631.S` +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` +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` --- */ void arg() @@ -75,7 +75,7 @@ void arg() S x; tem!().S y; - void f(int i, S s){}; + void f(int i, S s); f(4, y); (tem!().S s){}(x); @@ -89,12 +89,13 @@ void arg() /* TEST_OUTPUT: --- -fail_compilation/bug9631.d(105): Error: function bug9631.targ.ft!().ft (S _param_0) is not callable using argument types (S) -fail_compilation/bug9631.d(105): cannot implicitly convert expression `x` of type `bug9631.S` to `bug9631.tem!().S` -fail_compilation/bug9631.d(106): Error: template bug9631.targ.ft cannot deduce function from argument types !()(S), candidates are: -fail_compilation/bug9631.d(104): bug9631.targ.ft()(tem!().S) -fail_compilation/bug9631.d(108): Error: template bug9631.targ.ft2 cannot deduce function from argument types !()(S, int), candidates are: -fail_compilation/bug9631.d(107): bug9631.targ.ft2(T)(S, T) +fail_compilation/bug9631.d(106): Error: function bug9631.targ.ft!().ft `(S _param_0)` is not callable using argument types `(S)` +fail_compilation/bug9631.d(106): cannot pass argument `x` of type `bug9631.S` to parameter `S _param_0` of type `bug9631.tem!().S` +fail_compilation/bug9631.d(107): Error: template `bug9631.targ.ft` cannot deduce function from argument types `!()(S)`, candidates are: +fail_compilation/bug9631.d(105): `bug9631.targ.ft()(tem!().S)` +fail_compilation/bug9631.d(109): Error: template `bug9631.targ.ft2` cannot deduce function from argument types `!()(S, int)`, candidates are: +fail_compilation/bug9631.d(108): `bug9631.targ.ft2(T)(S, T)` +--- */ void targ() { diff --git a/test/fail_compilation/diag13082.d b/test/fail_compilation/diag13082.d index 4b5e0b93ace9..7360a3df62f2 100644 --- a/test/fail_compilation/diag13082.d +++ b/test/fail_compilation/diag13082.d @@ -1,8 +1,10 @@ /* TEST_OUTPUT: --- -fail_compilation/diag13082.d(22): Error: constructor `diag13082.C.this(int a)` is not callable using argument types `(string)` -fail_compilation/diag13082.d(23): Error: constructor `diag13082.S.this(int a)` is not callable using argument types `(string)` +fail_compilation/diag13082.d(24): Error: constructor `diag13082.C.this(int a)` is not callable using argument types `(string)` +fail_compilation/diag13082.d(24): cannot pass argument `b` of type `string` to parameter `int a` +fail_compilation/diag13082.d(25): Error: constructor `diag13082.S.this(int a)` is not callable using argument types `(string)` +fail_compilation/diag13082.d(25): cannot pass argument `b` of type `string` to parameter `int a` --- */ diff --git a/test/fail_compilation/diag8101b.d b/test/fail_compilation/diag8101b.d index 83569aa06d6a..228ba169e8e5 100644 --- a/test/fail_compilation/diag8101b.d +++ b/test/fail_compilation/diag8101b.d @@ -1,14 +1,15 @@ /* TEST_OUTPUT: --- -fail_compilation/diag8101b.d(26): Error: none of the overloads of `foo` are callable using argument types `(double)`, candidates are: -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(28): Error: function `diag8101b.S.bar(int _param_0)` is not callable using argument types `(double)` -fail_compilation/diag8101b.d(31): Error: none of the overloads of `foo` are callable using a `const` object, candidates are: -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: +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` +fail_compilation/diag8101b.d(32): Error: none of the overloads of `foo` are callable using a `const` object, candidates are: +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(34): Error: mutable method `diag8101b.S.bar` is not callable using a `const` object --- */ diff --git a/test/fail_compilation/fail263.d b/test/fail_compilation/fail263.d index 7f70458999dc..8cf9b20ac2bb 100644 --- a/test/fail_compilation/fail263.d +++ b/test/fail_compilation/fail263.d @@ -1,7 +1,8 @@ /* TEST_OUTPUT: --- -fail_compilation/fail263.d(18): Error: function `fail263.f(byte* p)` is not callable using argument types `(const(byte)*)` +fail_compilation/fail263.d(19): Error: function `fail263.f(byte* p)` is not callable using argument types `(const(byte)*)` +fail_compilation/fail263.d(19): cannot pass argument `cast(const(byte)*)A` of type `const(byte)*` to parameter `byte* p` --- */ diff --git a/test/fail_compilation/fail322.d b/test/fail_compilation/fail322.d index 0415d56f9a4b..0e7ebaad5f1e 100644 --- a/test/fail_compilation/fail322.d +++ b/test/fail_compilation/fail322.d @@ -1,7 +1,8 @@ /* TEST_OUTPUT: --- -fail_compilation/fail322.d(10): Error: function `fail322.digestToString2(ref char[16] digest)` is not callable using argument types `(string)` +fail_compilation/fail322.d(11): Error: function `fail322.digestToString2(ref char[16] digest)` is not callable using argument types `(string)` +fail_compilation/fail322.d(11): cannot pass rvalue argument `"1234567890123456"` of type `string` to parameter `ref char[16] digest` --- */ diff --git a/test/fail_compilation/fail53.d b/test/fail_compilation/fail53.d index 11202b0ffeec..556896c76c35 100644 --- a/test/fail_compilation/fail53.d +++ b/test/fail_compilation/fail53.d @@ -1,7 +1,8 @@ /* TEST_OUTPUT: --- -fail_compilation/fail53.d(25): Error: function `object.Object.opEquals(Object o)` is not callable using argument types `(int)` +fail_compilation/fail53.d(26): Error: function `object.Object.opEquals(Object o)` is not callable using argument types `(int)` +fail_compilation/fail53.d(26): cannot pass argument `i` of type `int` to parameter `Object o` --- */ diff --git a/test/fail_compilation/fail55.d b/test/fail_compilation/fail55.d index 10a47ca0c6e7..290c2b6695f0 100644 --- a/test/fail_compilation/fail55.d +++ b/test/fail_compilation/fail55.d @@ -1,7 +1,8 @@ /* TEST_OUTPUT: --- -fail_compilation/fail55.d(22): Error: function `object.Object.opCmp(Object o)` is not callable using argument types `(int)` +fail_compilation/fail55.d(23): Error: function `object.Object.opCmp(Object o)` is not callable using argument types `(int)` +fail_compilation/fail55.d(23): cannot pass argument `0` of type `int` to parameter `Object o` --- */ diff --git a/test/fail_compilation/ice14923.d b/test/fail_compilation/ice14923.d index 77ab840a1c3a..2c9c6144f3f7 100644 --- a/test/fail_compilation/ice14923.d +++ b/test/fail_compilation/ice14923.d @@ -1,8 +1,9 @@ /* TEST_OUTPUT: --- -fail_compilation/ice14923.d(21): Error: function `ice14923.parse(C a)` is not callable using argument types `(A)` -fail_compilation/ice14923.d(21): instantiated from here: `bar!((b) => parse(b))` +fail_compilation/ice14923.d(22): Error: function `ice14923.parse(C a)` is not callable using argument types `(A)` +fail_compilation/ice14923.d(22): cannot pass argument `b` of type `ice14923.A` to parameter `C a` +fail_compilation/ice14923.d(22): instantiated from here: bar!((b) => parse(b)) --- */ From c48e834ff535fa4fd1c44da0dd457a721fde60e2 Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Mon, 1 Jan 2018 12:32:32 +0000 Subject: [PATCH 03/10] Fix null termination, add ddoc --- src/dmd/func.d | 8 +++++++- src/dmd/hdrgen.d | 10 ++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/dmd/func.d b/src/dmd/func.d index 1e41bc2fdc98..ce212c8b0c36 100644 --- a/src/dmd/func.d +++ b/src/dmd/func.d @@ -3635,6 +3635,12 @@ extern (C++) final class DeleteDeclaration : FuncDeclaration } } +/** Show supplemental error message for a function call with mismatched arguments. + * Params: + * loc = line information for error message + * fargs = arguments to function + * tf = function called + * failIndex = index of first argument mismatch */ void showArgMismatch(Loc loc, Expressions* fargs, TypeFunction tf, size_t failIndex) { if (failIndex < fargs.dim && failIndex < tf.parameters.dim) @@ -3647,7 +3653,7 @@ void showArgMismatch(Loc loc, Expressions* fargs, TypeFunction tf, size_t failIn 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`"; + msg ~= " of type `%s`\0"; errorSupplemental(loc, msg.ptr, rv.ptr, arg.toChars(), ts[0], pc, ts[1]); } diff --git a/src/dmd/hdrgen.d b/src/dmd/hdrgen.d index 3e6ed2b5abbf..054784be9b0b 100644 --- a/src/dmd/hdrgen.d +++ b/src/dmd/hdrgen.d @@ -3421,6 +3421,11 @@ extern (C++) void arrayObjectsToBuffer(OutBuffer* buf, Objects* objects) } } +/** Pretty print function parameters. + * 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) { OutBuffer buf; @@ -3430,6 +3435,11 @@ extern (C++) const(char)* parametersTypeToChars(Parameters* parameters, int vara return buf.extractString(); } +/** Pretty print function parameters. + * Params: + * 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) { OutBuffer buf; From 66a74ee34f06c64c5f9f1e398782a28c09a1b602 Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Tue, 2 Jan 2018 16:14:27 +0000 Subject: [PATCH 04/10] Fully qualify parameter instead of showing type separately; fix ddoc --- src/dmd/func.d | 17 +++++++++-------- src/dmd/hdrgen.d | 12 +++++++----- test/fail_compilation/bug9631.d | 8 ++++---- 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/dmd/func.d b/src/dmd/func.d index ce212c8b0c36..edb6481d4f0f 100644 --- a/src/dmd/func.d +++ b/src/dmd/func.d @@ -3648,13 +3648,14 @@ void showArgMismatch(Loc loc, Expressions* fargs, TypeFunction tf, size_t failIn auto arg = (*fargs)[failIndex]; auto par = (*tf.parameters)[failIndex]; const rv = (!arg.isLvalue() && par.storageClass & (STCref | STCout)) ? "rvalue " : ""; - const pc = parameterToChars(par, tf.varargs); - const ts = toAutoQualChars(arg.type, par.type); - 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`\0"; - errorSupplemental(loc, msg.ptr, - rv.ptr, arg.toChars(), ts[0], pc, ts[1]); + + // disambiguate when toChars() is the same + auto at = arg.type.toChars(); + bool qual = !arg.type.equals(par.type) && strcmp(at, par.type.toChars()) == 0; + if (qual) + at = arg.type.toPrettyChars(true); + + errorSupplemental(loc, "cannot pass %sargument `%s` of type `%s` to parameter `%s`", + rv.ptr, arg.toChars(), at, parameterToChars(par, tf.varargs, qual)); } } diff --git a/src/dmd/hdrgen.d b/src/dmd/hdrgen.d index 054784be9b0b..c3e24bc87cab 100644 --- a/src/dmd/hdrgen.d +++ b/src/dmd/hdrgen.d @@ -3424,8 +3424,8 @@ extern (C++) void arrayObjectsToBuffer(OutBuffer* buf, Objects* objects) /** Pretty print function parameters. * Params: * parameters = parameters to print, such as TypeFunction.parameters. - * varargs = Kind of varargs, see TypeFunction.varargs. - * Returns: NT string representing parameters. */ + * varargs = kind of varargs, see TypeFunction.varargs. + * Returns: Null-terminated string representing parameters. */ extern (C++) const(char)* parametersTypeToChars(Parameters* parameters, int varargs) { OutBuffer buf; @@ -3438,12 +3438,14 @@ extern (C++) const(char)* parametersTypeToChars(Parameters* parameters, int vara /** Pretty print function parameters. * Params: * 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) + * varargs = kind of varargs, see TypeFunction.varargs. + * fullQual = whether to fully qualify types. + * Returns: Null-terminated string representing parameters. */ +extern (C++) const(char)* parameterToChars(Parameter parameter, int varargs, bool fullQual) { OutBuffer buf; HdrGenState hgs; + hgs.fullQual = fullQual; scope PrettyPrintVisitor v = new PrettyPrintVisitor(&buf, &hgs); parameter.accept(v); diff --git a/test/fail_compilation/bug9631.d b/test/fail_compilation/bug9631.d index 89d985208fb9..a719635fcd18 100644 --- a/test/fail_compilation/bug9631.d +++ b/test/fail_compilation/bug9631.d @@ -63,11 +63,11 @@ void test3() 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` +fail_compilation/bug9631.d(79): cannot pass argument `y` of type `bug9631.tem!().S` to parameter `bug9631.S s` 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(80): cannot pass argument `x` of type `bug9631.S` to parameter `bug9631.tem!().S 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` +fail_compilation/bug9631.d(86): cannot pass argument `S(0)` of type `bug9631.tem!().S` to parameter `bug9631.S _param_0` --- */ void arg() @@ -90,7 +90,7 @@ void arg() TEST_OUTPUT: --- fail_compilation/bug9631.d(106): Error: function bug9631.targ.ft!().ft `(S _param_0)` is not callable using argument types `(S)` -fail_compilation/bug9631.d(106): cannot pass argument `x` of type `bug9631.S` to parameter `S _param_0` of type `bug9631.tem!().S` +fail_compilation/bug9631.d(106): cannot pass argument `x` of type `bug9631.S` to parameter `bug9631.tem!().S _param_0` fail_compilation/bug9631.d(107): Error: template `bug9631.targ.ft` cannot deduce function from argument types `!()(S)`, candidates are: fail_compilation/bug9631.d(105): `bug9631.targ.ft()(tem!().S)` fail_compilation/bug9631.d(109): Error: template `bug9631.targ.ft2` cannot deduce function from argument types `!()(S, int)`, candidates are: From 7421577faed191b3e00088431a752437196a8fae Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Thu, 4 Jan 2018 12:07:18 +0000 Subject: [PATCH 05/10] Fix backticks after rebase --- test/fail_compilation/bug9631.d | 6 +++--- test/fail_compilation/ice8255.d | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/test/fail_compilation/bug9631.d b/test/fail_compilation/bug9631.d index a719635fcd18..330fd50c3f79 100644 --- a/test/fail_compilation/bug9631.d +++ b/test/fail_compilation/bug9631.d @@ -62,11 +62,11 @@ void test3() /* 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): 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 `bug9631.S s` 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 `bug9631.tem!().S 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): 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 `bug9631.S _param_0` --- */ @@ -89,7 +89,7 @@ void arg() /* TEST_OUTPUT: --- -fail_compilation/bug9631.d(106): Error: function bug9631.targ.ft!().ft `(S _param_0)` is not callable using argument types `(S)` +fail_compilation/bug9631.d(106): Error: function `bug9631.targ.ft!().ft(S _param_0)` is not callable using argument types `(S)` fail_compilation/bug9631.d(106): cannot pass argument `x` of type `bug9631.S` to parameter `bug9631.tem!().S _param_0` fail_compilation/bug9631.d(107): Error: template `bug9631.targ.ft` cannot deduce function from argument types `!()(S)`, candidates are: fail_compilation/bug9631.d(105): `bug9631.targ.ft()(tem!().S)` diff --git a/test/fail_compilation/ice8255.d b/test/fail_compilation/ice8255.d index a550704bd58f..0db3abc395fc 100644 --- a/test/fail_compilation/ice8255.d +++ b/test/fail_compilation/ice8255.d @@ -3,7 +3,8 @@ TEST_OUTPUT: --- fail_compilation/ice8255.d(11): Error: function `ice8255.F!(G).F.f(ref G _param_0)` is not callable using argument types `(G)` fail_compilation/ice8255.d(11): cannot pass rvalue argument `G()` of type `G` to parameter `ref G _param_0` -fail_compilation/ice8255.d(11): while evaluating pragma(msg, F().f(G())) +fail_compilation/ice8255.d(11): while evaluating `pragma(msg, F().f(G()))` +--- */ struct G {} struct F(T) { void f(ref T) {} } From 2ef0b7dfe7ca9aa68b0588656292ce22d517296a Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Sat, 6 Jan 2018 12:39:30 +0000 Subject: [PATCH 06/10] Fix ddoc, fix variadic parameterToChars() & add test --- src/dmd/func.d | 2 +- src/dmd/hdrgen.d | 18 +++++++++++------- test/fail_compilation/bug15613.d | 18 ++++++++++++++++++ 3 files changed, 30 insertions(+), 8 deletions(-) create mode 100644 test/fail_compilation/bug15613.d diff --git a/src/dmd/func.d b/src/dmd/func.d index edb6481d4f0f..e014fe255856 100644 --- a/src/dmd/func.d +++ b/src/dmd/func.d @@ -3656,6 +3656,6 @@ void showArgMismatch(Loc loc, Expressions* fargs, TypeFunction tf, size_t failIn at = arg.type.toPrettyChars(true); errorSupplemental(loc, "cannot pass %sargument `%s` of type `%s` to parameter `%s`", - rv.ptr, arg.toChars(), at, parameterToChars(par, tf.varargs, qual)); + rv.ptr, arg.toChars(), at, parameterToChars(par, tf, qual)); } } diff --git a/src/dmd/hdrgen.d b/src/dmd/hdrgen.d index c3e24bc87cab..f7ca7fe61e31 100644 --- a/src/dmd/hdrgen.d +++ b/src/dmd/hdrgen.d @@ -3421,11 +3421,13 @@ extern (C++) void arrayObjectsToBuffer(OutBuffer* buf, Objects* objects) } } -/** Pretty print function parameters. +/************************************************************* + * Pretty print function parameters. * Params: * parameters = parameters to print, such as TypeFunction.parameters. * varargs = kind of varargs, see TypeFunction.varargs. - * Returns: Null-terminated string representing parameters. */ + * Returns: Null-terminated string representing parameters. + */ extern (C++) const(char)* parametersTypeToChars(Parameters* parameters, int varargs) { OutBuffer buf; @@ -3435,13 +3437,15 @@ extern (C++) const(char)* parametersTypeToChars(Parameters* parameters, int vara return buf.extractString(); } -/** Pretty print function parameters. +/************************************************************* + * Pretty print function parameter. * Params: * parameter = parameter to print. - * varargs = kind of varargs, see TypeFunction.varargs. + * tf = TypeFunction which holds parameter. * fullQual = whether to fully qualify types. - * Returns: Null-terminated string representing parameters. */ -extern (C++) const(char)* parameterToChars(Parameter parameter, int varargs, bool fullQual) + * Returns: Null-terminated string representing parameters. + */ +extern (C++) const(char)* parameterToChars(Parameter parameter, TypeFunction tf, bool fullQual) { OutBuffer buf; HdrGenState hgs; @@ -3449,7 +3453,7 @@ extern (C++) const(char)* parameterToChars(Parameter parameter, int varargs, boo scope PrettyPrintVisitor v = new PrettyPrintVisitor(&buf, &hgs); parameter.accept(v); - if (varargs) + if (tf.varargs == 2 && parameter == Parameter.getNth(tf.parameters, tf.parameters.dim - 1)) { buf.writestring("..."); } diff --git a/test/fail_compilation/bug15613.d b/test/fail_compilation/bug15613.d new file mode 100644 index 000000000000..31a6eb963512 --- /dev/null +++ b/test/fail_compilation/bug15613.d @@ -0,0 +1,18 @@ +/* +TEST_OUTPUT: +--- +fail_compilation\bug15613.d(16): Error: function `bug15613.f(int...)` is not callable using argument types `(typeof(null))` +fail_compilation\bug15613.d(16): cannot pass argument `null` of type `typeof(null)` to parameter `int...` +fail_compilation\bug15613.d(17): Error: function `bug15613.g(Object, ...)` is not callable using argument types `(int)` +fail_compilation\bug15613.d(17): cannot pass argument `8` of type `int` to parameter `Object` +--- +*/ + +void f(int...); +void g(Object, ...); + +void main() +{ + f(null); + g(8); +} From 15b1b503440caab6ba8d2879b80d3946d4d5ac23 Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Fri, 5 Jan 2018 11:36:59 +0000 Subject: [PATCH 07/10] Make callMatch set an error message; remove showArgMismatch --- src/dmd/dtemplate.d | 5 ++-- src/dmd/expressionsem.d | 14 ++++++---- src/dmd/func.d | 31 +++------------------ src/dmd/mtype.d | 48 ++++++++++++++++++++++++++------ test/fail_compilation/bug15613.d | 8 +++--- test/fail_compilation/fail322.d | 8 ++++-- 6 files changed, 65 insertions(+), 49 deletions(-) diff --git a/src/dmd/dtemplate.d b/src/dmd/dtemplate.d index 95613502434f..5f7d329ecc97 100644 --- a/src/dmd/dtemplate.d +++ b/src/dmd/dtemplate.d @@ -2330,9 +2330,10 @@ extern (C++) final class TypeDeduced : Type * tthis if !NULL, the 'this' pointer argument * fargs arguments to function * failedIndex address to store argument index of first type mismatch + * pMessage address to store error message, or null */ void functionResolve(Match* m, Dsymbol dstart, Loc loc, Scope* sc, Objects* tiargs, - Type tthis, Expressions* fargs, size_t* failedIndex = null) + Type tthis, Expressions* fargs, const(char)** pMessage = null) { version (none) { @@ -2418,7 +2419,7 @@ void functionResolve(Match* m, Dsymbol dstart, Loc loc, Scope* sc, Objects* tiar else return 0; // MATCH.nomatch } - MATCH mfa = tf.callMatch(tthis_fd, fargs, 0, failedIndex); + MATCH mfa = tf.callMatch(tthis_fd, fargs, 0, pMessage); //printf("test1: mfa = %d\n", mfa); if (mfa > MATCH.nomatch) { diff --git a/src/dmd/expressionsem.d b/src/dmd/expressionsem.d index 81f69272f48c..288b4fae7e57 100644 --- a/src/dmd/expressionsem.d +++ b/src/dmd/expressionsem.d @@ -3430,8 +3430,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); } - size_t failIndex; - if (!tf.callMatch(null, exp.arguments, 0, &failIndex)) + const(char)* failMessage; + if (!tf.callMatch(null, exp.arguments, 0, &failMessage)) { OutBuffer buf; buf.writeByte('('); @@ -3443,7 +3443,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor //printf("tf = %s, args = %s\n", tf.deco, (*arguments)[0].type.deco); .error(exp.loc, "%s `%s%s` is not callable using argument types `%s`", p, exp.e1.toChars(), parametersTypeToChars(tf.parameters, tf.varargs), buf.peekString()); - showArgMismatch(exp.loc, exp.arguments, tf, failIndex); + if (failMessage) + errorSupplemental(exp.loc, failMessage); return setError(); } // Purity and safety check should run after testing arguments matching @@ -3503,8 +3504,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { exp.f = exp.f.toAliasFunc(); TypeFunction tf = cast(TypeFunction)exp.f.type; - size_t failIndex; - if (!tf.callMatch(null, exp.arguments, 0, &failIndex)) + const(char)* failMessage; + if (!tf.callMatch(null, exp.arguments, 0, &failMessage)) { OutBuffer buf; buf.writeByte('('); @@ -3514,7 +3515,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor //printf("tf = %s, args = %s\n", tf.deco, (*arguments)[0].type.deco); .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); + if (failMessage) + errorSupplemental(exp.loc, failMessage); exp.f = null; } } diff --git a/src/dmd/func.d b/src/dmd/func.d index e014fe255856..844f49d58192 100644 --- a/src/dmd/func.d +++ b/src/dmd/func.d @@ -2481,8 +2481,8 @@ extern (C++) FuncDeclaration resolveFuncCall(Loc loc, Scope* sc, Dsymbol s, Match m; m.last = MATCH.nomatch; - size_t failIndex; - functionResolve(&m, s, loc, sc, tiargs, tthis, fargs, &failIndex); + const(char)* failMessage; + functionResolve(&m, s, loc, sc, tiargs, tthis, fargs, &failMessage); if (m.last > MATCH.nomatch && m.lastf) { @@ -2600,7 +2600,8 @@ extern (C++) FuncDeclaration resolveFuncCall(Loc loc, Scope* sc, Dsymbol s, .error(loc, "%s `%s%s%s` is not callable using argument types `%s`", fd.kind(), fd.toPrettyChars(), parametersTypeToChars(tf.parameters, tf.varargs), tf.modToChars(), fargsBuf.peekString()); - showArgMismatch(loc, fargs, tf, failIndex); + if (failMessage) + errorSupplemental(loc, failMessage); } } @@ -3635,27 +3636,3 @@ extern (C++) final class DeleteDeclaration : FuncDeclaration } } -/** Show supplemental error message for a function call with mismatched arguments. - * Params: - * loc = line information for error message - * fargs = arguments to function - * tf = function called - * failIndex = index of first argument mismatch */ -void showArgMismatch(Loc loc, Expressions* fargs, TypeFunction tf, size_t failIndex) -{ - if (failIndex < fargs.dim && failIndex < tf.parameters.dim) - { - auto arg = (*fargs)[failIndex]; - auto par = (*tf.parameters)[failIndex]; - const rv = (!arg.isLvalue() && par.storageClass & (STCref | STCout)) ? "rvalue " : ""; - - // disambiguate when toChars() is the same - auto at = arg.type.toChars(); - bool qual = !arg.type.equals(par.type) && strcmp(at, par.type.toChars()) == 0; - if (qual) - at = arg.type.toPrettyChars(true); - - errorSupplemental(loc, "cannot pass %sargument `%s` of type `%s` to parameter `%s`", - rv.ptr, arg.toChars(), at, parameterToChars(par, tf, qual)); - } -} diff --git a/src/dmd/mtype.d b/src/dmd/mtype.d index 908a10280131..a27b47707f6e 100644 --- a/src/dmd/mtype.d +++ b/src/dmd/mtype.d @@ -5885,16 +5885,33 @@ extern (C++) final class TypeFunction : TypeNext return t.merge(); } + // arguments get specially formatted + private const(char)* getParamError(const(char)* format, Expression arg, Parameter par) + { + // disambiguate when toChars() is the same + auto at = arg.type.toChars(); + bool qual = !arg.type.equals(par.type) && strcmp(at, par.type.toChars()) == 0; + if (qual) + at = arg.type.toPrettyChars(true); + OutBuffer as; + as.printf("`%s` of type `%s`", arg.toChars(), at); + OutBuffer ps; + ps.printf("`%s`", parameterToChars(par, this, qual)); + OutBuffer buf; + buf.printf(format, as.peekString(), ps.peekString()); + return buf.extractString(); + } + /******************************** * 'args' are being matched to function 'this' * Determine match level. * Input: * flag 1 performing a partial ordering match - * failedIndex address to store argument index of first type mismatch + * pMessage address to store error message, or null * Returns: * MATCHxxxx */ - MATCH callMatch(Type tthis, Expressions* args, int flag = 0, size_t* failedIndex = null) + MATCH callMatch(Type tthis, Expressions* args, int flag = 0, const(char)** pMessage = null) { //printf("TypeFunction::callMatch() %s\n", toChars()); MATCH match = MATCH.exact; // assume exact match @@ -5929,7 +5946,6 @@ extern (C++) final class TypeFunction : TypeNext } } - auto u = size_t.max; // used for failedIndex if no match size_t nparams = Parameter.dim(parameters); size_t nargs = args ? args.dim : 0; if (nparams == nargs) @@ -5943,7 +5959,7 @@ extern (C++) final class TypeFunction : TypeNext match = MATCH.convert; // match ... with a "conversion" match level } - for (u = 0; u < nargs; u++) + for (size_t u = 0; u < nargs; u++) { if (u >= nparams) break; @@ -5976,7 +5992,7 @@ extern (C++) final class TypeFunction : TypeNext } } - for (u = 0; u < nparams; u++) + for (size_t u = 0; u < nparams; u++) { MATCH m; @@ -6024,7 +6040,10 @@ extern (C++) final class TypeFunction : TypeNext if (m && !arg.isLvalue()) { if (p.storageClass & STC.out_) + { + if (pMessage) *pMessage = getParamError("cannot pass rvalue argument %s to parameter %s", arg, p); goto Nomatch; + } if (arg.op == TOK.string_ && tp.ty == Tsarray) { @@ -6046,7 +6065,10 @@ extern (C++) final class TypeFunction : TypeNext } } else + { + if (pMessage) *pMessage = getParamError("cannot pass rvalue argument %s to parameter %s", arg, p); goto Nomatch; + } } /* Find most derived alias this type being matched. @@ -6070,7 +6092,12 @@ extern (C++) final class TypeFunction : TypeNext * ref T[dim] <- an lvalue of const(T[dim]) argument */ if (!ta.constConv(tp)) + { + if (pMessage) *pMessage = getParamError( + arg.isLvalue() ? "cannot pass argument %s to parameter %s" : + "cannot pass rvalue argument %s to parameter %s", arg, p); goto Nomatch; + } } } @@ -6127,7 +6154,10 @@ extern (C++) final class TypeFunction : TypeNext m = arg.implicitConvTo(ta.next); if (m == MATCH.nomatch) + { + if (pMessage) *pMessage = getParamError("cannot pass argument %s to parameter %s", arg, p); goto Nomatch; + } if (m < match) match = m; } @@ -6139,9 +6169,12 @@ extern (C++) final class TypeFunction : TypeNext goto Ldone; default: + if (pMessage) *pMessage = getParamError("cannot pass argument %s to parameter %s", (*args)[u], p); goto Nomatch; } } + if (pMessage && u < nargs) + *pMessage = getParamError("cannot pass argument %s to parameter %s", (*args)[u], p); goto Nomatch; } if (m < match) @@ -6154,8 +6187,6 @@ extern (C++) final class TypeFunction : TypeNext Nomatch: //printf("no match\n"); - if (failedIndex) - *failedIndex = u; return MATCH.nomatch; } @@ -9228,7 +9259,7 @@ extern (C++) final class Parameter : RootObject extern (D) static immutable bool[SR.max + 1][SR.max + 1] covariant = covariantInit(); } -/** +/************************************************************* * For printing two types with qualification when necessary. * Params: * t1 = The first type to receive the type name for @@ -9241,6 +9272,7 @@ const(char*)[2] toAutoQualChars(Type t1, Type t2) { auto s1 = t1.toChars(); auto s2 = t2.toChars(); + // show qualification only if it's different if (!t1.equals(t2) && strcmp(s1, s2) == 0) { s1 = t1.toPrettyChars(true); diff --git a/test/fail_compilation/bug15613.d b/test/fail_compilation/bug15613.d index 31a6eb963512..e8072fdbaf87 100644 --- a/test/fail_compilation/bug15613.d +++ b/test/fail_compilation/bug15613.d @@ -1,10 +1,10 @@ /* TEST_OUTPUT: --- -fail_compilation\bug15613.d(16): Error: function `bug15613.f(int...)` is not callable using argument types `(typeof(null))` -fail_compilation\bug15613.d(16): cannot pass argument `null` of type `typeof(null)` to parameter `int...` -fail_compilation\bug15613.d(17): Error: function `bug15613.g(Object, ...)` is not callable using argument types `(int)` -fail_compilation\bug15613.d(17): cannot pass argument `8` of type `int` to parameter `Object` +fail_compilation/bug15613.d(16): Error: function `bug15613.f(int...)` is not callable using argument types `(typeof(null))` +fail_compilation/bug15613.d(16): cannot pass argument `null` of type `typeof(null)` to parameter `int...` +fail_compilation/bug15613.d(17): Error: function `bug15613.g(Object, ...)` is not callable using argument types `(int)` +fail_compilation/bug15613.d(17): cannot pass argument `8` of type `int` to parameter `Object` --- */ diff --git a/test/fail_compilation/fail322.d b/test/fail_compilation/fail322.d index 0e7ebaad5f1e..491111fe6102 100644 --- a/test/fail_compilation/fail322.d +++ b/test/fail_compilation/fail322.d @@ -1,14 +1,18 @@ /* TEST_OUTPUT: --- -fail_compilation/fail322.d(11): Error: function `fail322.digestToString2(ref char[16] digest)` is not callable using argument types `(string)` -fail_compilation/fail322.d(11): cannot pass rvalue argument `"1234567890123456"` of type `string` to parameter `ref char[16] digest` +fail_compilation/fail322.d(13): Error: function `fail322.digestToString2(ref char[16] digest)` is not callable using argument types `(string)` +fail_compilation/fail322.d(13): cannot pass rvalue argument `"1234567890123456"` of type `string` to parameter `ref char[16] digest` +fail_compilation/fail322.d(15): Error: function `fail322.digestToString2(ref char[16] digest)` is not callable using argument types `(const(char[16]))` +fail_compilation/fail322.d(15): cannot pass argument `s` of type `const(char[16])` to parameter `ref char[16] digest` --- */ void main() { digestToString2("1234567890123456"); + const char[16] s; + digestToString2(s); } void digestToString2(ref char[16] digest) From a693e6996211cb32236c38336c877f2916b9e0c8 Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Fri, 12 Jan 2018 12:22:41 +0000 Subject: [PATCH 08/10] Fix possible wrong argument index, minor tweaks --- src/dmd/mtype.d | 5 ++--- test/fail_compilation/ice14923.d | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/dmd/mtype.d b/src/dmd/mtype.d index a27b47707f6e..0f37b72a1afb 100644 --- a/src/dmd/mtype.d +++ b/src/dmd/mtype.d @@ -5888,7 +5888,7 @@ extern (C++) final class TypeFunction : TypeNext // arguments get specially formatted private const(char)* getParamError(const(char)* format, Expression arg, Parameter par) { - // disambiguate when toChars() is the same + // show qualification when toChars() is the same but types are different auto at = arg.type.toChars(); bool qual = !arg.type.equals(par.type) && strcmp(at, par.type.toChars()) == 0; if (qual) @@ -6169,8 +6169,7 @@ extern (C++) final class TypeFunction : TypeNext goto Ldone; default: - if (pMessage) *pMessage = getParamError("cannot pass argument %s to parameter %s", (*args)[u], p); - goto Nomatch; + break; } } if (pMessage && u < nargs) diff --git a/test/fail_compilation/ice14923.d b/test/fail_compilation/ice14923.d index 2c9c6144f3f7..e3b677e2cdb3 100644 --- a/test/fail_compilation/ice14923.d +++ b/test/fail_compilation/ice14923.d @@ -3,7 +3,7 @@ TEST_OUTPUT: --- fail_compilation/ice14923.d(22): Error: function `ice14923.parse(C a)` is not callable using argument types `(A)` fail_compilation/ice14923.d(22): cannot pass argument `b` of type `ice14923.A` to parameter `C a` -fail_compilation/ice14923.d(22): instantiated from here: bar!((b) => parse(b)) +fail_compilation/ice14923.d(22): instantiated from here: `bar!((b) => parse(b))` --- */ From 0948ed913a76b27bc7a5e9e284faaf32f99470f3 Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Mon, 15 Jan 2018 11:25:30 +0000 Subject: [PATCH 09/10] Fix triggering CallExp error message --- src/dmd/expressionsem.d | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/dmd/expressionsem.d b/src/dmd/expressionsem.d index 288b4fae7e57..e0b18cc16687 100644 --- a/src/dmd/expressionsem.d +++ b/src/dmd/expressionsem.d @@ -3498,7 +3498,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor assert(exp.f); tiargs = null; - if (ve.hasOverloads) + if (exp.f.overnext) exp.f = resolveFuncCall(exp.loc, sc, exp.f, tiargs, null, exp.arguments, 2); else { @@ -3513,8 +3513,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor buf.writeByte(')'); //printf("tf = %s, args = %s\n", tf.deco, (*arguments)[0].type.deco); - .error(exp.loc, "`%s%s` is not callable using argument types `%s`", - exp.e1.toChars(), parametersTypeToChars(tf.parameters, tf.varargs), buf.peekString()); + .error(exp.loc, "%s `%s%s` is not callable using argument types `%s`", + exp.f.kind(), exp.f.toPrettyChars(), parametersTypeToChars(tf.parameters, tf.varargs), buf.peekString()); if (failMessage) errorSupplemental(exp.loc, failMessage); exp.f = null; From 04f41db567cfd6ae8a86b3ce033117c47d1752da Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Fri, 19 Jan 2018 10:53:17 +0000 Subject: [PATCH 10/10] Convert ddoc Input -> Params, fix wrong param --- src/dmd/dtemplate.d | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/dmd/dtemplate.d b/src/dmd/dtemplate.d index 5f7d329ecc97..248a4f7dd3fc 100644 --- a/src/dmd/dtemplate.d +++ b/src/dmd/dtemplate.d @@ -2321,16 +2321,15 @@ extern (C++) final class TypeDeduced : Type /************************************************* * Given function arguments, figure out which template function * to expand, and return matching result. - * Input: - * m matching result - * dstart the root of overloaded function templates - * loc instantiation location - * sc instantiation scope - * 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 - * pMessage address to store error message, or null + * Params: + * m = matching result + * dstart = the root of overloaded function templates + * loc = instantiation location + * sc = instantiation scope + * tiargs = initial list of template arguments + * tthis = if !NULL, the 'this' pointer argument + * fargs = arguments to function + * pMessage = address to store error message, or null */ void functionResolve(Match* m, Dsymbol dstart, Loc loc, Scope* sc, Objects* tiargs, Type tthis, Expressions* fargs, const(char)** pMessage = null)