diff --git a/src/dmd/dtemplate.d b/src/dmd/dtemplate.d index a4dbdc27554c..248a4f7dd3fc 100644 --- a/src/dmd/dtemplate.d +++ b/src/dmd/dtemplate.d @@ -2321,16 +2321,18 @@ 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 + * 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) +void functionResolve(Match* m, Dsymbol dstart, Loc loc, Scope* sc, Objects* tiargs, + Type tthis, Expressions* fargs, const(char)** pMessage = 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, pMessage); //printf("test1: mfa = %d\n", mfa); if (mfa > MATCH.nomatch) { diff --git a/src/dmd/expressionsem.d b/src/dmd/expressionsem.d index 345f64343f97..e0b18cc16687 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)) + const(char)* failMessage; + if (!tf.callMatch(null, exp.arguments, 0, &failMessage)) { OutBuffer buf; buf.writeByte('('); @@ -3440,7 +3441,10 @@ 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()); + if (failMessage) + errorSupplemental(exp.loc, failMessage); return setError(); } // Purity and safety check should run after testing arguments matching @@ -3494,13 +3498,14 @@ 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 { exp.f = exp.f.toAliasFunc(); TypeFunction tf = cast(TypeFunction)exp.f.type; - if (!tf.callMatch(null, exp.arguments)) + const(char)* failMessage; + if (!tf.callMatch(null, exp.arguments, 0, &failMessage)) { OutBuffer buf; buf.writeByte('('); @@ -3508,8 +3513,10 @@ 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; } } diff --git a/src/dmd/func.d b/src/dmd/func.d index a99637fb2fd2..844f49d58192 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); + const(char)* failMessage; + functionResolve(&m, s, loc, sc, tiargs, tthis, fargs, &failMessage); if (m.last > MATCH.nomatch && m.lastf) { @@ -2599,6 +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()); + if (failMessage) + errorSupplemental(loc, failMessage); } } @@ -3632,3 +3635,4 @@ extern (C++) final class DeleteDeclaration : FuncDeclaration v.visit(this); } } + diff --git a/src/dmd/hdrgen.d b/src/dmd/hdrgen.d index dbb5dc4fd86c..f7ca7fe61e31 100644 --- a/src/dmd/hdrgen.d +++ b/src/dmd/hdrgen.d @@ -3421,6 +3421,13 @@ 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: Null-terminated string representing parameters. + */ extern (C++) const(char)* parametersTypeToChars(Parameters* parameters, int varargs) { OutBuffer buf; @@ -3429,3 +3436,26 @@ extern (C++) const(char)* parametersTypeToChars(Parameters* parameters, int vara v.parametersToBuffer(parameters, varargs); return buf.extractString(); } + +/************************************************************* + * Pretty print function parameter. + * Params: + * parameter = parameter to print. + * tf = TypeFunction which holds parameter. + * fullQual = whether to fully qualify types. + * Returns: Null-terminated string representing parameters. + */ +extern (C++) const(char)* parameterToChars(Parameter parameter, TypeFunction tf, bool fullQual) +{ + OutBuffer buf; + HdrGenState hgs; + hgs.fullQual = fullQual; + scope PrettyPrintVisitor v = new PrettyPrintVisitor(&buf, &hgs); + + parameter.accept(v); + if (tf.varargs == 2 && parameter == Parameter.getNth(tf.parameters, tf.parameters.dim - 1)) + { + buf.writestring("..."); + } + return buf.extractString(); +} diff --git a/src/dmd/mtype.d b/src/dmd/mtype.d index 8770f0dcbb90..0f37b72a1afb 100644 --- a/src/dmd/mtype.d +++ b/src/dmd/mtype.d @@ -5885,15 +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) + { + // 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) + 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 + * pMessage address to store error message, or null * Returns: * MATCHxxxx */ - MATCH callMatch(Type tthis, Expressions* args, int flag = 0) + 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 @@ -6022,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) { @@ -6044,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. @@ -6068,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; + } } } @@ -6125,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; } @@ -6137,9 +6169,11 @@ extern (C++) final class TypeFunction : TypeNext goto Ldone; default: - goto Nomatch; + break; } } + if (pMessage && u < nargs) + *pMessage = getParamError("cannot pass argument %s to parameter %s", (*args)[u], p); goto Nomatch; } if (m < match) @@ -9224,7 +9258,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 @@ -9237,7 +9271,8 @@ const(char*)[2] toAutoQualChars(Type t1, Type t2) { auto s1 = t1.toChars(); auto s2 = t2.toChars(); - if (strcmp(s1, s2) == 0) + // show qualification only if it's different + if (!t1.equals(t2) && strcmp(s1, s2) == 0) { s1 = t1.toPrettyChars(true); s2 = t2.toPrettyChars(true); diff --git a/test/fail_compilation/bug15613.d b/test/fail_compilation/bug15613.d new file mode 100644 index 000000000000..e8072fdbaf87 --- /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); +} diff --git a/test/fail_compilation/bug9631.d b/test/fail_compilation/bug9631.d index d4113bcfd17e..330fd50c3f79 100644 --- a/test/fail_compilation/bug9631.d +++ b/test/fail_compilation/bug9631.d @@ -58,3 +58,54 @@ 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 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): cannot pass argument `S(0)` of type `bug9631.tem!().S` to parameter `bug9631.S _param_0` +--- +*/ +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(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)` +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() +{ + 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/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..491111fe6102 100644 --- a/test/fail_compilation/fail322.d +++ b/test/fail_compilation/fail322.d @@ -1,13 +1,18 @@ /* 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(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) 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..e3b677e2cdb3 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))` --- */ diff --git a/test/fail_compilation/ice8255.d b/test/fail_compilation/ice8255.d index 1fbb6fded54e..0db3abc395fc 100644 --- a/test/fail_compilation/ice8255.d +++ b/test/fail_compilation/ice8255.d @@ -1,8 +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 {}