From e42e002c1e0b4d6a445e436061d4fe1a2a91bb55 Mon Sep 17 00:00:00 2001 From: dayllenger Date: Sat, 27 Apr 2019 05:11:12 +0300 Subject: [PATCH 1/8] add ability to visualize static condition as a tree, for better output --- src/dmd/staticcond.d | 255 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 206 insertions(+), 49 deletions(-) diff --git a/src/dmd/staticcond.d b/src/dmd/staticcond.d index 5521a37a3c52..0f65695c9293 100644 --- a/src/dmd/staticcond.d +++ b/src/dmd/staticcond.d @@ -23,6 +23,8 @@ import dmd.expressionsem; import dmd.globals; import dmd.identifier; import dmd.mtype; +import dmd.root.array; +import dmd.root.outbuffer; import dmd.tokens; import dmd.utils; @@ -35,82 +37,237 @@ import dmd.utils; * necessary. * Params: * sc = instantiating scope - * exp = original expression, for error messages + * original = original expression, for error messages * e = resulting expression * errors = set to `true` if errors occurred + * negatives = array to store negative clauses * Returns: * true if evaluates to true */ - -bool evalStaticCondition(Scope* sc, Expression exp, Expression e, ref bool errors) +bool evalStaticCondition(Scope* sc, Expression original, Expression e, out bool errors, Array!Expression* negatives = null) { - if (e.op == TOK.andAnd || e.op == TOK.orOr) + if (negatives) + negatives.setDim(0); + + bool impl(Expression e) { - LogicalExp aae = cast(LogicalExp)e; - bool result = evalStaticCondition(sc, exp, aae.e1, errors); - if (errors) - return false; - if (e.op == TOK.andAnd) + if (e.op == TOK.not) { - if (!result) + NotExp ne = cast(NotExp)e; + return !impl(ne.e1); + } + + if (e.op == TOK.andAnd || e.op == TOK.orOr) + { + LogicalExp aae = cast(LogicalExp)e; + bool result = impl(aae.e1); + if (errors) return false; + if (e.op == TOK.andAnd) + { + if (!result) + return false; + } + else + { + if (result) + return true; + } + result = impl(aae.e2); + return !errors && result; } - else + + if (e.op == TOK.question) { - if (result) - return true; + CondExp ce = cast(CondExp)e; + bool result = impl(ce.econd); + if (errors) + return false; + Expression leg = result ? ce.e1 : ce.e2; + result = impl(leg); + return !errors && result; } - result = evalStaticCondition(sc, exp, aae.e2, errors); - return !errors && result; - } - if (e.op == TOK.question) - { - CondExp ce = cast(CondExp)e; - bool result = evalStaticCondition(sc, exp, ce.econd, errors); - if (errors) + Expression before = e; + const uint nerrors = global.errors; + + sc = sc.startCTFE(); + sc.flags |= SCOPE.condition; + + e = e.expressionSemantic(sc); + e = resolveProperties(sc, e); + + sc = sc.endCTFE(); + e = e.optimize(WANTvalue); + + if (nerrors != global.errors || + e.op == TOK.error || + e.type.toBasetype() == Type.terror) + { + errors = true; return false; - Expression leg = result ? ce.e1 : ce.e2; - result = evalStaticCondition(sc, exp, leg, errors); - return !errors && result; - } + } - uint nerrors = global.errors; + e = resolveAliasThis(sc, e); - sc = sc.startCTFE(); - sc.flags |= SCOPE.condition; + if (!e.type.isBoolean()) + { + original.error("expression `%s` of type `%s` does not have a boolean value", + original.toChars(), e.type.toChars()); + errors = true; + return false; + } - e = e.expressionSemantic(sc); - e = resolveProperties(sc, e); + e = e.ctfeInterpret(); - sc = sc.endCTFE(); - e = e.optimize(WANTvalue); + if (e.isBool(true)) + return true; + else if (e.isBool(false)) + { + if (negatives) + negatives.push(before); + return false; + } - if (nerrors != global.errors || - e.op == TOK.error || - e.type.toBasetype() == Type.terror) - { + e.error("expression `%s` is not constant", e.toChars()); errors = true; return false; } + return impl(e); +} - e = resolveAliasThis(sc, e); +/******************************************** + * Format a static condition as a tree-like structure, marking failed and + * bypassed expressions. + * Params: + * original = original expression + * instantiated = instantiated expression + * negatives = array with negative clauses from `instantiated` expression + * Returns: + * formatted string or `null` if the expressions were `null` + */ +const(char)* visualizeStaticCondition(Expression original, Expression instantiated, const Expression[] negatives) +{ + if (!original || !instantiated) + return null; + + OutBuffer buf; + uint indent; + bool unreached; // indicates that we are printing unreached 'and' clauses + bool marked; // `unreached` mate - if (!e.type.isBoolean()) + static void printOr(uint indent, ref OutBuffer buf) { - exp.error("expression `%s` of type `%s` does not have a boolean value", exp.toChars(), e.type.toChars()); - errors = true; - return false; + buf.reserve(indent * 4 + 8); + foreach (i; 0 .. indent) + buf.writestring(" "); + buf.writestring(" or:\n"); } - e = e.ctfeInterpret(); + void impl(Expression orig, Expression e, bool inverted, bool orOperand) + { + TOK op = orig.op; - if (e.isBool(true)) - return true; - else if (e.isBool(false)) - return false; + // !(A && B) -> !A || !B + // !(A || B) -> !A && !B + if (inverted) + { + if (op == TOK.andAnd) + op = TOK.orOr; + else if (op == TOK.orOr) + op = TOK.andAnd; + } + + if (op == TOK.not) + { + NotExp no = cast(NotExp)orig; + NotExp ne = cast(NotExp)e; + impl(no.e1, ne.e1, !inverted, orOperand); + } + else if (op == TOK.andAnd) + { + BinExp bo = cast(BinExp)orig; + BinExp be = cast(BinExp)e; + impl(bo.e1, be.e1, inverted, false); + if (marked) + unreached = true; + impl(bo.e2, be.e2, inverted, false); + if (orOperand) + unreached = false; + } + else if (op == TOK.orOr) + { + if (!orOperand) // do not indent A || B || C twice + indent++; + BinExp bo = cast(BinExp)orig; + BinExp be = cast(BinExp)e; + impl(bo.e1, be.e1, inverted, true); + printOr(indent, buf); + impl(bo.e2, be.e2, inverted, true); + if (!orOperand) + indent--; + } + else if (op == TOK.question) + { + // rewrite (A ? B : C) as (A && B || !A && C) + if (!orOperand) + indent++; + CondExp co = cast(CondExp)orig; + CondExp ce = cast(CondExp)e; + impl(co.econd, ce.econd, inverted, false); + if (marked) + unreached = true; + impl(co.e1, ce.e1, inverted, false); + unreached = false; + printOr(indent, buf); + impl(co.econd, ce.econd, !inverted, false); + if (marked) + unreached = true; + impl(co.e2, ce.e2, inverted, false); + unreached = false; + if (!orOperand) + indent--; + } + else // 'primitive' expression + { + buf.reserve(indent * 4 + 4); + foreach (i; 0 .. indent) + buf.writestring(" "); + + // find its value; it may be not computed, if there was a short circuit, + // but we handle this case with `unreached` flag + bool value = true; + if (!unreached) + { + foreach (fe; negatives) + { + if (fe is e) + { + value = false; + break; + } + } + } + // print marks first + const unsatisfied = inverted ? value : !value; + marked = false; + if (unsatisfied && !unreached) + { + buf.writestring(" > "); + marked = true; + } + else if (unreached) + buf.writestring(" - "); + else + buf.writestring(" "); + // then the expression itself + if (inverted) + buf.writeByte('!'); + buf.writestring(orig.toChars); + buf.writenl(); + } + } - e.error("expression `%s` is not constant", e.toChars()); - errors = true; - return false; + impl(original, instantiated, false, true); + return buf.extractString(); } From 38fc241bc4098e4ab84f9830abed17f9f28b8232 Mon Sep 17 00:00:00 2001 From: dayllenger Date: Sat, 27 Apr 2019 05:12:24 +0300 Subject: [PATCH 2/8] enchance template constraint error output --- src/dmd/dtemplate.d | 73 +++++++++++++++++++++++++++++++++++++++++++-- src/dmd/func.d | 13 +++++++- 2 files changed, 82 insertions(+), 4 deletions(-) diff --git a/src/dmd/dtemplate.d b/src/dmd/dtemplate.d index d0353b2e3eea..2266258fd972 100644 --- a/src/dmd/dtemplate.d +++ b/src/dmd/dtemplate.d @@ -515,6 +515,8 @@ struct TemplatePrevious */ extern (C++) final class TemplateDeclaration : ScopeDsymbol { + import dmd.root.array : Array; + TemplateParameters* parameters; // array of TemplateParameter's TemplateParameters* origParameters; // originals for Ddoc @@ -538,6 +540,9 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol // threaded list of previous instantiation attempts on stack TemplatePrevious* previous; + private Expression lastConstraint; // the last failed constraint instantiation + private Array!Expression lastConstraintNegs; // its negative parts + extern (D) this(const ref Loc loc, Identifier ident, TemplateParameters* parameters, Expression constraint, Dsymbols* decldefs, bool ismixin = false, bool literal = false) { super(loc, ident); @@ -680,6 +685,40 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol return buf.extractChars(); } + /**************************** + * Similar to `toChars`, but does not print the template constraints + */ + const(char)* toCharsNoConstraints() + { + if (literal) + return Dsymbol.toChars(); + + OutBuffer buf; + HdrGenState hgs; + + buf.writestring(ident.toChars()); + buf.writeByte('('); + for (size_t i = 0; i < parameters.dim; i++) + { + TemplateParameter tp = (*parameters)[i]; + if (i) + buf.writestring(", "); + .toCBuffer(tp, &buf, &hgs); + } + buf.writeByte(')'); + + if (onemember) + { + FuncDeclaration fd = onemember.isFuncDeclaration(); + if (fd && fd.type) + { + TypeFunction tf = cast(TypeFunction)fd.type; + buf.writestring(parametersTypeToChars(tf.parameterList)); + } + } + return buf.extractString(); + } + override Prot prot() pure nothrow @nogc @safe { return protection; @@ -782,7 +821,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol fd.selectorParameter = hiddenParams.selectorParameter; } - Expression e = constraint.syntaxCopy(); + lastConstraint = constraint.syntaxCopy(); import dmd.staticcond; @@ -790,7 +829,12 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol ti.inst = ti; // temporary instantiation to enable genIdent() scx.flags |= SCOPE.constraint; bool errors; - bool result = evalStaticCondition(scx, constraint, e, errors); + const bool result = evalStaticCondition(scx, constraint, lastConstraint, errors, &lastConstraintNegs); + if (result) + { + lastConstraint = null; + lastConstraintNegs.setDim(0); + } ti.inst = null; ti.symtab = null; scx = scx.pop(); @@ -800,6 +844,19 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol return result; } + /**************************** + * Destructively get the error message from the last constraint evaluation + */ + const(char)* getConstraintEvalError() + { + import dmd.staticcond; + + const msg = visualizeStaticCondition(constraint, lastConstraint, lastConstraintNegs[]); + lastConstraint = null; + lastConstraintNegs.setDim(0); + return msg; + } + /****************************** * Create a scope for the parameters of the TemplateInstance * `ti` in the parent scope sc from the ScopeDsymbol paramsym. @@ -7073,7 +7130,17 @@ extern (C++) class TemplateInstance : ScopeDsymbol else if (tdecl && !tdecl.overnext) { // Only one template, so we can give better error message - error("does not match template declaration `%s`", tdecl.toChars()); + const(char)* msg = "does not match template declaration"; + const tmsg = tdecl.toCharsNoConstraints(); + const cmsg = tdecl.getConstraintEvalError(); + if (cmsg) + { + const char* txt = " whose parameters have the following constraints:"; + const char* sep = " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"; + error("%s `%s`,\n%s\n`%s\n%s%s`", msg, tmsg, txt, sep, cmsg, sep); + } + else + error("%s `%s`", msg, tmsg); } else .error(loc, "%s `%s.%s` does not match any template declaration", tempdecl.kind(), tempdecl.parent.toPrettyChars(), tempdecl.ident.toChars()); diff --git a/src/dmd/func.d b/src/dmd/func.d index 5113a62f6c82..e9a5edb9d0a1 100644 --- a/src/dmd/func.d +++ b/src/dmd/func.d @@ -2956,7 +2956,18 @@ if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration)) } else if (auto td = s.isTemplateDeclaration()) { - .errorSupplemental(td.loc, "`%s`", td.toPrettyChars()); + import dmd.staticcond; + + const tmsg = td.toCharsNoConstraints(); + const cmsg = td.getConstraintEvalError(); + if (cmsg) + { + const char* txt = " whose parameters have the following constraints:"; + const char* sep = " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"; + .errorSupplemental(td.loc, "`%s`,\n%s\n`%s\n%s%s`", tmsg, txt, sep, cmsg, sep); + } + else + .errorSupplemental(td.loc, "`%s`", tmsg); nextOverload = td.overnext; } From ad1cdb18840cca2ddb1beadc083adeded61bb074 Mon Sep 17 00:00:00 2001 From: dayllenger Date: Sat, 27 Apr 2019 05:15:02 +0300 Subject: [PATCH 3/8] add the Tip message about constraints --- src/dmd/dtemplate.d | 1 + src/dmd/errors.d | 30 ++++++++++++++++++++++++++++++ src/dmd/func.d | 6 ++++++ 3 files changed, 37 insertions(+) diff --git a/src/dmd/dtemplate.d b/src/dmd/dtemplate.d index 2266258fd972..8cecbd2e37ad 100644 --- a/src/dmd/dtemplate.d +++ b/src/dmd/dtemplate.d @@ -7138,6 +7138,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol const char* txt = " whose parameters have the following constraints:"; const char* sep = " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"; error("%s `%s`,\n%s\n`%s\n%s%s`", msg, tmsg, txt, sep, cmsg, sep); + .tip("not satisfied constraints are marked with `>`"); } else error("%s `%s`", msg, tmsg); diff --git a/src/dmd/errors.d b/src/dmd/errors.d index d167687579c4..83a6a47837fe 100644 --- a/src/dmd/errors.d +++ b/src/dmd/errors.d @@ -241,6 +241,7 @@ enum Classification gagged = Color.brightBlue, /// for gagged errors warning = Color.brightYellow, /// for warnings deprecation = Color.brightCyan, /// for deprecations + tip = Color.brightGreen, /// for tip messages } /** @@ -400,6 +401,20 @@ extern (C++) void message(const(char)* format, ...) va_end(ap); } +/** + * Print a tip message with the prefix and highlighting. + * Params: + * format = printf-style format specification + * ... = printf-style variadic arguments + */ +extern (C++) void tip(const(char)* format, ...) +{ + va_list ap; + va_start(ap, format); + vtip(format, ap); + va_end(ap); +} + /** * Just print to stderr, doesn't care about gagging. * (format,ap) text within backticks gets syntax highlighted. @@ -610,6 +625,21 @@ extern (C++) void vmessage(const ref Loc loc, const(char)* format, va_list ap) fflush(stdout); // ensure it gets written out in case of compiler aborts } +/** + * Same as $(D tip), but takes a va_list parameter. + * Params: + * format = printf-style format specification + * ap = printf-style variadic arguments + */ +extern (C++) void vtip(const(char)* format, va_list ap) +{ + if (!global.gag) + { + Loc loc = Loc.init; + verrorPrint(loc, Classification.tip, " Tip: ", format, ap); + } +} + /** * Same as $(D deprecationSupplemental), but takes a va_list parameter. * Params: diff --git a/src/dmd/func.d b/src/dmd/func.d index e9a5edb9d0a1..fcd92242e340 100644 --- a/src/dmd/func.d +++ b/src/dmd/func.d @@ -2939,6 +2939,7 @@ if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration)) { // max num of overloads to print (-v overrides this). int numToDisplay = 5; + bool hadConstraints; overloadApply(declaration, (Dsymbol s) { @@ -2965,6 +2966,7 @@ if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration)) const char* txt = " whose parameters have the following constraints:"; const char* sep = " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"; .errorSupplemental(td.loc, "`%s`,\n%s\n`%s\n%s%s`", tmsg, txt, sep, cmsg, sep); + hadConstraints = true; } else .errorSupplemental(td.loc, "`%s`", tmsg); @@ -2983,6 +2985,10 @@ if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration)) .errorSupplemental(loc, "... (%d more, -v to show) ...", num); return 1; // stop iterating }); + + static if (is(Decl == TemplateDeclaration)) + if (hadConstraints) + .tip("not satisfied constraints are marked with `>`"); } /************************************** From c5f8940ae3116decf8d4304f7c5f4b2821ebbb9a Mon Sep 17 00:00:00 2001 From: dayllenger Date: Sun, 28 Apr 2019 07:01:42 +0300 Subject: [PATCH 4/8] fix marking of unreached expressions, handle !(A ? B : C) case --- src/dmd/staticcond.d | 79 ++++++++++++++++++++++++-------------------- 1 file changed, 44 insertions(+), 35 deletions(-) diff --git a/src/dmd/staticcond.d b/src/dmd/staticcond.d index 0f65695c9293..8c091bdfc35b 100644 --- a/src/dmd/staticcond.d +++ b/src/dmd/staticcond.d @@ -153,8 +153,6 @@ const(char)* visualizeStaticCondition(Expression original, Expression instantiat OutBuffer buf; uint indent; - bool unreached; // indicates that we are printing unreached 'and' clauses - bool marked; // `unreached` mate static void printOr(uint indent, ref OutBuffer buf) { @@ -164,10 +162,12 @@ const(char)* visualizeStaticCondition(Expression original, Expression instantiat buf.writestring(" or:\n"); } - void impl(Expression orig, Expression e, bool inverted, bool orOperand) + // returns true if satisfied + bool impl(Expression orig, Expression e, bool inverted, bool orOperand, bool unreached) { TOK op = orig.op; + // lower all 'not' to the bottom // !(A && B) -> !A || !B // !(A || B) -> !A && !B if (inverted) @@ -182,18 +182,15 @@ const(char)* visualizeStaticCondition(Expression original, Expression instantiat { NotExp no = cast(NotExp)orig; NotExp ne = cast(NotExp)e; - impl(no.e1, ne.e1, !inverted, orOperand); + return impl(no.e1, ne.e1, !inverted, orOperand, unreached); } else if (op == TOK.andAnd) { BinExp bo = cast(BinExp)orig; BinExp be = cast(BinExp)e; - impl(bo.e1, be.e1, inverted, false); - if (marked) - unreached = true; - impl(bo.e2, be.e2, inverted, false); - if (orOperand) - unreached = false; + const r1 = impl(bo.e1, be.e1, inverted, false, unreached); + const r2 = impl(bo.e2, be.e2, inverted, false, unreached || !r1); + return r1 && r2; } else if (op == TOK.orOr) { @@ -201,32 +198,47 @@ const(char)* visualizeStaticCondition(Expression original, Expression instantiat indent++; BinExp bo = cast(BinExp)orig; BinExp be = cast(BinExp)e; - impl(bo.e1, be.e1, inverted, true); + const r1 = impl(bo.e1, be.e1, inverted, true, unreached); printOr(indent, buf); - impl(bo.e2, be.e2, inverted, true); + const r2 = impl(bo.e2, be.e2, inverted, true, unreached); if (!orOperand) indent--; + return r1 || r2; } else if (op == TOK.question) { - // rewrite (A ? B : C) as (A && B || !A && C) - if (!orOperand) - indent++; CondExp co = cast(CondExp)orig; CondExp ce = cast(CondExp)e; - impl(co.econd, ce.econd, inverted, false); - if (marked) - unreached = true; - impl(co.e1, ce.e1, inverted, false); - unreached = false; - printOr(indent, buf); - impl(co.econd, ce.econd, !inverted, false); - if (marked) - unreached = true; - impl(co.e2, ce.e2, inverted, false); - unreached = false; - if (!orOperand) - indent--; + if (!inverted) + { + // rewrite (A ? B : C) as (A && B || !A && C) + if (!orOperand) + indent++; + const r1 = impl(co.econd, ce.econd, inverted, false, unreached); + const r2 = impl(co.e1, ce.e1, inverted, false, unreached || !r1); + printOr(indent, buf); + const r3 = impl(co.econd, ce.econd, !inverted, false, unreached); + const r4 = impl(co.e2, ce.e2, inverted, false, unreached || !r3); + if (!orOperand) + indent--; + return r1 && r2 || r3 && r4; + } + else + { + // rewrite !(A ? B : C) as (!A || !B) && (A || !C) + if (!orOperand) + indent++; + const r1 = impl(co.econd, ce.econd, inverted, false, unreached); + printOr(indent, buf); + const r2 = impl(co.e1, ce.e1, inverted, false, unreached); + const r12 = r1 || r2; + const r3 = impl(co.econd, ce.econd, !inverted, false, unreached || !r12); + printOr(indent, buf); + const r4 = impl(co.e2, ce.e2, inverted, false, unreached || !r12); + if (!orOperand) + indent--; + return (r1 || r2) && (r3 || r4); + } } else // 'primitive' expression { @@ -249,13 +261,9 @@ const(char)* visualizeStaticCondition(Expression original, Expression instantiat } } // print marks first - const unsatisfied = inverted ? value : !value; - marked = false; - if (unsatisfied && !unreached) - { + const satisfied = inverted ? !value : value; + if (!satisfied && !unreached) buf.writestring(" > "); - marked = true; - } else if (unreached) buf.writestring(" - "); else @@ -265,9 +273,10 @@ const(char)* visualizeStaticCondition(Expression original, Expression instantiat buf.writeByte('!'); buf.writestring(orig.toChars); buf.writenl(); + return satisfied; } } - impl(original, instantiated, false, true); + impl(original, instantiated, false, true, false); return buf.extractString(); } From 5acd75fb5ff404cb9db0235e003048dcfcf7691b Mon Sep 17 00:00:00 2001 From: dayllenger Date: Mon, 29 Apr 2019 01:13:10 +0300 Subject: [PATCH 5/8] show full tree view of static conditions only in verbose mode --- src/dmd/dtemplate.d | 2 +- src/dmd/staticcond.d | 159 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 154 insertions(+), 7 deletions(-) diff --git a/src/dmd/dtemplate.d b/src/dmd/dtemplate.d index 8cecbd2e37ad..f2c38d660f9e 100644 --- a/src/dmd/dtemplate.d +++ b/src/dmd/dtemplate.d @@ -851,7 +851,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol { import dmd.staticcond; - const msg = visualizeStaticCondition(constraint, lastConstraint, lastConstraintNegs[]); + const msg = visualizeStaticCondition(constraint, lastConstraint, lastConstraintNegs[], global.params.verbose); lastConstraint = null; lastConstraintNegs.setDim(0); return msg; diff --git a/src/dmd/staticcond.d b/src/dmd/staticcond.d index 8c091bdfc35b..38105cc5bfd3 100644 --- a/src/dmd/staticcond.d +++ b/src/dmd/staticcond.d @@ -44,7 +44,7 @@ import dmd.utils; * Returns: * true if evaluates to true */ -bool evalStaticCondition(Scope* sc, Expression original, Expression e, out bool errors, Array!Expression* negatives = null) +bool evalStaticCondition(Scope* sc, Expression original, Expression e, out bool errors, Expressions* negatives = null) { if (negatives) negatives.setDim(0); @@ -143,15 +143,31 @@ bool evalStaticCondition(Scope* sc, Expression original, Expression e, out bool * original = original expression * instantiated = instantiated expression * negatives = array with negative clauses from `instantiated` expression + * full = controls whether it shows the full output or only failed parts * Returns: - * formatted string or `null` if the expressions were `null` + * formatted string or `null` if the expressions were `null`, or if the + * instantiated expression is not based on the original one */ -const(char)* visualizeStaticCondition(Expression original, Expression instantiated, const Expression[] negatives) +const(char)* visualizeStaticCondition(Expression original, Expression instantiated, + const Expression[] negatives, bool full) { - if (!original || !instantiated) + if (!original || !instantiated || original.loc !is instantiated.loc) return null; OutBuffer buf; + + if (full) + visualizeFull(original, instantiated, negatives, buf); + else + visualizeShort(original, instantiated, negatives, buf); + + return buf.extractString(); +} + +private void visualizeFull(Expression original, Expression instantiated, + const Expression[] negatives, ref OutBuffer buf) +{ + // tree-like structure; traverse and format simultaneously uint indent; static void printOr(uint indent, ref OutBuffer buf) @@ -182,12 +198,14 @@ const(char)* visualizeStaticCondition(Expression original, Expression instantiat { NotExp no = cast(NotExp)orig; NotExp ne = cast(NotExp)e; + assert(ne); return impl(no.e1, ne.e1, !inverted, orOperand, unreached); } else if (op == TOK.andAnd) { BinExp bo = cast(BinExp)orig; BinExp be = cast(BinExp)e; + assert(be); const r1 = impl(bo.e1, be.e1, inverted, false, unreached); const r2 = impl(bo.e2, be.e2, inverted, false, unreached || !r1); return r1 && r2; @@ -198,6 +216,7 @@ const(char)* visualizeStaticCondition(Expression original, Expression instantiat indent++; BinExp bo = cast(BinExp)orig; BinExp be = cast(BinExp)e; + assert(be); const r1 = impl(bo.e1, be.e1, inverted, true, unreached); printOr(indent, buf); const r2 = impl(bo.e2, be.e2, inverted, true, unreached); @@ -209,6 +228,7 @@ const(char)* visualizeStaticCondition(Expression original, Expression instantiat { CondExp co = cast(CondExp)orig; CondExp ce = cast(CondExp)e; + assert(ce); if (!inverted) { // rewrite (A ? B : C) as (A && B || !A && C) @@ -260,7 +280,7 @@ const(char)* visualizeStaticCondition(Expression original, Expression instantiat } } } - // print marks first + // write the marks first const satisfied = inverted ? !value : value; if (!satisfied && !unreached) buf.writestring(" > "); @@ -278,5 +298,132 @@ const(char)* visualizeStaticCondition(Expression original, Expression instantiat } impl(original, instantiated, false, true, false); - return buf.extractString(); +} + +private void visualizeShort(Expression original, Expression instantiated, + const Expression[] negatives, ref OutBuffer buf) +{ + // simple list; somewhat similar to long version, so no comments + // one difference is that it needs to hold items to display in a stack + + static struct Item + { + Expression orig; + bool inverted; + } + + Array!Item stack; + + bool impl(Expression orig, Expression e, bool inverted) + { + TOK op = orig.op; + + if (inverted) + { + if (op == TOK.andAnd) + op = TOK.orOr; + else if (op == TOK.orOr) + op = TOK.andAnd; + } + + if (op == TOK.not) + { + NotExp no = cast(NotExp)orig; + NotExp ne = cast(NotExp)e; + assert(ne); + return impl(no.e1, ne.e1, !inverted); + } + else if (op == TOK.andAnd) + { + BinExp bo = cast(BinExp)orig; + BinExp be = cast(BinExp)e; + assert(be); + bool r = impl(bo.e1, be.e1, inverted); + r = r && impl(bo.e2, be.e2, inverted); + return r; + } + else if (op == TOK.orOr) + { + BinExp bo = cast(BinExp)orig; + BinExp be = cast(BinExp)e; + assert(be); + const lbefore = stack.length; + bool r = impl(bo.e1, be.e1, inverted); + r = r || impl(bo.e2, be.e2, inverted); + if (r) + stack.setDim(lbefore); // purge added positive items + return r; + } + else if (op == TOK.question) + { + CondExp co = cast(CondExp)orig; + CondExp ce = cast(CondExp)e; + assert(ce); + if (!inverted) + { + const lbefore = stack.length; + bool a = impl(co.econd, ce.econd, inverted); + a = a && impl(co.e1, ce.e1, inverted); + bool b; + if (!a) + { + b = impl(co.econd, ce.econd, !inverted); + b = b && impl(co.e2, ce.e2, inverted); + } + const r = a || b; + if (r) + stack.setDim(lbefore); + return r; + } + else + { + bool a; + { + const lbefore = stack.length; + a = impl(co.econd, ce.econd, inverted); + a = a || impl(co.e1, ce.e1, inverted); + if (a) + stack.setDim(lbefore); + } + bool b; + if (a) + { + const lbefore = stack.length; + b = impl(co.econd, ce.econd, !inverted); + b = b || impl(co.e2, ce.e2, inverted); + if (b) + stack.setDim(lbefore); + } + return a && b; + } + } + else // 'primitive' expression + { + bool value = true; + foreach (fe; negatives) + { + if (fe is e) + { + value = false; + break; + } + } + const satisfied = inverted ? !value : value; + if (!satisfied) + stack.push(Item(orig, inverted)); + return satisfied; + } + } + + impl(original, instantiated, false); + + foreach (item; stack) + { + // write the expression only + buf.writestring(" "); + if (item.inverted) + buf.writeByte('!'); + buf.writestring(item.orig.toChars); + buf.writenl(); + } } From c19c13eb32aaebae3059d6c6732a964dbb3e7b94 Mon Sep 17 00:00:00 2001 From: dayllenger Date: Mon, 29 Apr 2019 23:19:30 +0300 Subject: [PATCH 6/8] put short constraint message into shape, show instantiation arguments --- src/dmd/dtemplate.d | 135 +++++++++++++++++++++++++++++++++++++------ src/dmd/func.d | 18 ++---- src/dmd/staticcond.d | 29 ++++++---- 3 files changed, 141 insertions(+), 41 deletions(-) diff --git a/src/dmd/dtemplate.d b/src/dmd/dtemplate.d index f2c38d660f9e..bc9998f3fa5c 100644 --- a/src/dmd/dtemplate.d +++ b/src/dmd/dtemplate.d @@ -540,8 +540,9 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol // threaded list of previous instantiation attempts on stack TemplatePrevious* previous; - private Expression lastConstraint; // the last failed constraint instantiation - private Array!Expression lastConstraintNegs; // its negative parts + private Expression lastConstraint; /// the constraint after the last failed evaluation + private Array!Expression lastConstraintNegs; /// its negative parts + private Objects* lastConstraintTiargs; /// template instance arguments for `lastConstraint` extern (D) this(const ref Loc loc, Identifier ident, TemplateParameters* parameters, Expression constraint, Dsymbols* decldefs, bool ismixin = false, bool literal = false) { @@ -698,10 +699,9 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol buf.writestring(ident.toChars()); buf.writeByte('('); - for (size_t i = 0; i < parameters.dim; i++) + foreach (i, tp; *parameters) { - TemplateParameter tp = (*parameters)[i]; - if (i) + if (i > 0) buf.writestring(", "); .toCBuffer(tp, &buf, &hgs); } @@ -712,11 +712,11 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol FuncDeclaration fd = onemember.isFuncDeclaration(); if (fd && fd.type) { - TypeFunction tf = cast(TypeFunction)fd.type; + TypeFunction tf = fd.type.isTypeFunction(); buf.writestring(parametersTypeToChars(tf.parameterList)); } } - return buf.extractString(); + return buf.extractChars(); } override Prot prot() pure nothrow @nogc @safe @@ -822,6 +822,8 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol } lastConstraint = constraint.syntaxCopy(); + lastConstraintTiargs = ti.tiargs; + lastConstraintNegs.setDim(0); import dmd.staticcond; @@ -830,9 +832,10 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol scx.flags |= SCOPE.constraint; bool errors; const bool result = evalStaticCondition(scx, constraint, lastConstraint, errors, &lastConstraintNegs); - if (result) + if (result || errors) { lastConstraint = null; + lastConstraintTiargs = null; lastConstraintNegs.setDim(0); } ti.inst = null; @@ -846,15 +849,111 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol /**************************** * Destructively get the error message from the last constraint evaluation + * Params: + * tip = tip to show after printing all overloads */ - const(char)* getConstraintEvalError() + const(char)* getConstraintEvalError(ref const(char)* tip) { import dmd.staticcond; - const msg = visualizeStaticCondition(constraint, lastConstraint, lastConstraintNegs[], global.params.verbose); - lastConstraint = null; - lastConstraintNegs.setDim(0); - return msg; + // there will be a full tree view in verbose mode, and more compact list in the usual + const full = global.params.verbose; + uint count; + const msg = visualizeStaticCondition(constraint, lastConstraint, lastConstraintNegs[], full, count); + scope (exit) + { + lastConstraint = null; + lastConstraintTiargs = null; + lastConstraintNegs.setDim(0); + } + if (msg) + { + OutBuffer buf; + + assert(parameters && lastConstraintTiargs); + if (parameters.length > 0) + { + formatParamsWithTiargs(*lastConstraintTiargs, buf); + buf.writenl(); + } + if (!full) + { + // choosing singular/plural + const s = (count == 1) ? + " must satisfy the following constraint:" : + " must satisfy one of the following constraints:"; + buf.writestring(s); + buf.writenl(); + // the constraints + buf.writeByte('`'); + buf.writestring(msg); + buf.writeByte('`'); + } + else + { + buf.writestring(" whose parameters have the following constraints:"); + buf.writenl(); + const sep = " `~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`"; + buf.writestring(sep); + buf.writenl(); + // the constraints + buf.writeByte('`'); + buf.writestring(msg); + buf.writeByte('`'); + buf.writestring(sep); + tip = "not satisfied constraints are marked with `>`"; + } + return buf.extractChars(); + } + else + return null; + } + + private void formatParamsWithTiargs(ref Objects tiargs, ref OutBuffer buf) + { + buf.writestring(" with `"); + + // write usual arguments line-by-line + // skips trailing default ones - they are not present in `tiargs` + const bool variadic = isVariadic() !is null; + const end = cast(int)parameters.length - (variadic ? 1 : 0); + uint i; + for (; i < tiargs.length && i < end; i++) + { + if (i > 0) + { + buf.writeByte(','); + buf.writenl(); + buf.writestring(" "); + } + buf.write((*parameters)[i]); + buf.writestring(" = "); + buf.write(tiargs[i]); + } + // write remaining variadic arguments on the last line + if (variadic) + { + if (i > 0) + { + buf.writeByte(','); + buf.writenl(); + buf.writestring(" "); + } + buf.write((*parameters)[end]); + buf.writestring(" = "); + buf.writeByte('('); + if (cast(int)tiargs.length - end > 0) + { + buf.write(tiargs[end]); + foreach (j; parameters.length .. tiargs.length) + { + buf.writestring(", "); + buf.write(tiargs[j]); + } + } + buf.writeByte(')'); + } + buf.writeByte('`'); } /****************************** @@ -7131,14 +7230,14 @@ extern (C++) class TemplateInstance : ScopeDsymbol { // Only one template, so we can give better error message const(char)* msg = "does not match template declaration"; + const(char)* tip; const tmsg = tdecl.toCharsNoConstraints(); - const cmsg = tdecl.getConstraintEvalError(); + const cmsg = tdecl.getConstraintEvalError(tip); if (cmsg) { - const char* txt = " whose parameters have the following constraints:"; - const char* sep = " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"; - error("%s `%s`,\n%s\n`%s\n%s%s`", msg, tmsg, txt, sep, cmsg, sep); - .tip("not satisfied constraints are marked with `>`"); + error("%s `%s`\n%s", msg, tmsg, cmsg); + if (tip) + .tip(tip); } else error("%s `%s`", msg, tmsg); diff --git a/src/dmd/func.d b/src/dmd/func.d index fcd92242e340..b265133cca12 100644 --- a/src/dmd/func.d +++ b/src/dmd/func.d @@ -2939,7 +2939,7 @@ if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration)) { // max num of overloads to print (-v overrides this). int numToDisplay = 5; - bool hadConstraints; + const(char)* constraintsTip; overloadApply(declaration, (Dsymbol s) { @@ -2960,14 +2960,9 @@ if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration)) import dmd.staticcond; const tmsg = td.toCharsNoConstraints(); - const cmsg = td.getConstraintEvalError(); + const cmsg = td.getConstraintEvalError(constraintsTip); if (cmsg) - { - const char* txt = " whose parameters have the following constraints:"; - const char* sep = " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"; - .errorSupplemental(td.loc, "`%s`,\n%s\n`%s\n%s%s`", tmsg, txt, sep, cmsg, sep); - hadConstraints = true; - } + .errorSupplemental(td.loc, "`%s`\n%s", tmsg, cmsg); else .errorSupplemental(td.loc, "`%s`", tmsg); nextOverload = td.overnext; @@ -2985,10 +2980,9 @@ if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration)) .errorSupplemental(loc, "... (%d more, -v to show) ...", num); return 1; // stop iterating }); - - static if (is(Decl == TemplateDeclaration)) - if (hadConstraints) - .tip("not satisfied constraints are marked with `>`"); + // should be only in verbose mode + if (constraintsTip) + .tip(constraintsTip); } /************************************** diff --git a/src/dmd/staticcond.d b/src/dmd/staticcond.d index 38105cc5bfd3..4c7e4a89168a 100644 --- a/src/dmd/staticcond.d +++ b/src/dmd/staticcond.d @@ -144,12 +144,13 @@ bool evalStaticCondition(Scope* sc, Expression original, Expression e, out bool * instantiated = instantiated expression * negatives = array with negative clauses from `instantiated` expression * full = controls whether it shows the full output or only failed parts + * itemCount = returns the number of written clauses * Returns: * formatted string or `null` if the expressions were `null`, or if the * instantiated expression is not based on the original one */ const(char)* visualizeStaticCondition(Expression original, Expression instantiated, - const Expression[] negatives, bool full) + const Expression[] negatives, bool full, ref uint itemCount) { if (!original || !instantiated || original.loc !is instantiated.loc) return null; @@ -157,17 +158,18 @@ const(char)* visualizeStaticCondition(Expression original, Expression instantiat OutBuffer buf; if (full) - visualizeFull(original, instantiated, negatives, buf); + itemCount = visualizeFull(original, instantiated, negatives, buf); else - visualizeShort(original, instantiated, negatives, buf); + itemCount = visualizeShort(original, instantiated, negatives, buf); - return buf.extractString(); + return buf.extractChars(); } -private void visualizeFull(Expression original, Expression instantiated, +private uint visualizeFull(Expression original, Expression instantiated, const Expression[] negatives, ref OutBuffer buf) { // tree-like structure; traverse and format simultaneously + uint count; uint indent; static void printOr(uint indent, ref OutBuffer buf) @@ -293,14 +295,16 @@ private void visualizeFull(Expression original, Expression instantiated, buf.writeByte('!'); buf.writestring(orig.toChars); buf.writenl(); + count++; return satisfied; } } impl(original, instantiated, false, true, false); + return count; } -private void visualizeShort(Expression original, Expression instantiated, +private uint visualizeShort(Expression original, Expression instantiated, const Expression[] negatives, ref OutBuffer buf) { // simple list; somewhat similar to long version, so no comments @@ -417,13 +421,16 @@ private void visualizeShort(Expression original, Expression instantiated, impl(original, instantiated, false); - foreach (item; stack) + foreach (i; 0 .. stack.length) { // write the expression only - buf.writestring(" "); - if (item.inverted) + buf.writestring(" "); + if (stack[i].inverted) buf.writeByte('!'); - buf.writestring(item.orig.toChars); - buf.writenl(); + buf.writestring(stack[i].orig.toChars); + // here with no trailing newline + if (i + 1 < stack.length) + buf.writenl(); } + return cast(uint)stack.length; } From cc5e0a624843c246f48925cb62d63ce1408869a1 Mon Sep 17 00:00:00 2001 From: dayllenger Date: Tue, 21 May 2019 20:28:52 +0300 Subject: [PATCH 7/8] add tests for new template constraints error messages --- test/fail_compilation/constraints_aggr.d | 44 ++++++++ test/fail_compilation/constraints_defs.d | 55 ++++++++++ test/fail_compilation/constraints_func1.d | 92 +++++++++++++++++ test/fail_compilation/constraints_func2.d | 107 ++++++++++++++++++++ test/fail_compilation/constraints_func3.d | 59 +++++++++++ test/fail_compilation/constraints_tmpl.d | 43 ++++++++ test/fail_compilation/imports/constraints.d | 73 +++++++++++++ 7 files changed, 473 insertions(+) create mode 100755 test/fail_compilation/constraints_aggr.d create mode 100755 test/fail_compilation/constraints_defs.d create mode 100755 test/fail_compilation/constraints_func1.d create mode 100755 test/fail_compilation/constraints_func2.d create mode 100755 test/fail_compilation/constraints_func3.d create mode 100755 test/fail_compilation/constraints_tmpl.d create mode 100755 test/fail_compilation/imports/constraints.d diff --git a/test/fail_compilation/constraints_aggr.d b/test/fail_compilation/constraints_aggr.d new file mode 100755 index 000000000000..83e64d70b683 --- /dev/null +++ b/test/fail_compilation/constraints_aggr.d @@ -0,0 +1,44 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/constraints_aggr.d(31): Error: template `imports.constraints.C.f` cannot deduce function from argument types `!()(int)`, candidates are: +fail_compilation/imports/constraints.d(60): `f(T)(T v)` + with `T = int` + must satisfy the following constraint: +` !P!T` +fail_compilation/constraints_aggr.d(32): Error: template `imports.constraints.C.g` cannot deduce function from argument types `!()()`, candidates are: +fail_compilation/imports/constraints.d(63): `g(this T)()` + with `T = imports.constraints.C` + must satisfy the following constraint: +` N!T` +fail_compilation/constraints_aggr.d(34): Error: template instance `imports.constraints.S!int` does not match template declaration `S(T)` + with `T = int` + must satisfy the following constraint: +` N!T` +fail_compilation/constraints_aggr.d(43): Error: template instance `imports.constraints.BitFlags!(Enum)` does not match template declaration `BitFlags(E, bool unsafe = false)` + with `E = Enum` + must satisfy one of the following constraints: +` unsafe + N!E` +--- +*/ + +void main() +{ + import imports.constraints; + + C c = new C; + c.f(0); + c.g(); + + S!int; + + enum Enum + { + A = 1, + B = 2, + C = 4, + BC = B|C + } + BitFlags!Enum flags; +} diff --git a/test/fail_compilation/constraints_defs.d b/test/fail_compilation/constraints_defs.d new file mode 100755 index 000000000000..67f12df69cc6 --- /dev/null +++ b/test/fail_compilation/constraints_defs.d @@ -0,0 +1,55 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/constraints_defs.d(48): Error: template instance `constraints_defs.main.def!(int, 0, (a) => a)` does not match template declaration `def(T, int i = 5, alias R)()` + with `T = int, + i = 0, + R = __lambda1` + must satisfy the following constraint: +` N!T` +fail_compilation/constraints_defs.d(49): Error: template instance `imports.constraints.defa!int` does not match template declaration `defa(T, U = int)()` + with `T = int` + must satisfy the following constraint: +` N!T` +fail_compilation/constraints_defs.d(50): Error: template instance `imports.constraints.defv!()` does not match template declaration `defv(T = bool, int i = 5, Ts...)()` + with `Ts = ()` + must satisfy the following constraint: +` N!T` +fail_compilation/constraints_defs.d(51): Error: template instance `imports.constraints.defv!int` does not match template declaration `defv(T = bool, int i = 5, Ts...)()` + with `T = int, + Ts = ()` + must satisfy the following constraint: +` N!T` +fail_compilation/constraints_defs.d(52): Error: template instance `imports.constraints.defv!(int, 0)` does not match template declaration `defv(T = bool, int i = 5, Ts...)()` + with `T = int, + i = 0, + Ts = ()` + must satisfy the following constraint: +` N!T` +fail_compilation/constraints_defs.d(53): Error: template instance `imports.constraints.defv!(int, 0, bool)` does not match template declaration `defv(T = bool, int i = 5, Ts...)()` + with `T = int, + i = 0, + Ts = (bool)` + must satisfy the following constraint: +` N!T` +fail_compilation/constraints_defs.d(54): Error: template instance `imports.constraints.defv!(int, 0, bool, float)` does not match template declaration `defv(T = bool, int i = 5, Ts...)()` + with `T = int, + i = 0, + Ts = (bool, float)` + must satisfy the following constraint: +` N!T` +--- +*/ + +void main() +{ + import imports.constraints; + + def!(int, 0, a => a)(); + defa!(int)(); + defv!()(); + defv!(int)(); + defv!(int, 0)(); + defv!(int, 0, bool)(); + defv!(int, 0, bool, float)(); +} diff --git a/test/fail_compilation/constraints_func1.d b/test/fail_compilation/constraints_func1.d new file mode 100755 index 000000000000..9470e7732cf1 --- /dev/null +++ b/test/fail_compilation/constraints_func1.d @@ -0,0 +1,92 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/constraints_func1.d(78): Error: template `imports.constraints.test1` cannot deduce function from argument types `!()(int)`, candidates are: +fail_compilation/imports/constraints.d(9): `test1(T)(T v)` + with `T = int` + must satisfy the following constraint: +` N!T` +fail_compilation/constraints_func1.d(79): Error: template `imports.constraints.test2` cannot deduce function from argument types `!()(int)`, candidates are: +fail_compilation/imports/constraints.d(10): `test2(T)(T v)` + with `T = int` + must satisfy the following constraint: +` !P!T` +fail_compilation/constraints_func1.d(80): Error: template `imports.constraints.test3` cannot deduce function from argument types `!()(int)`, candidates are: +fail_compilation/imports/constraints.d(11): `test3(T)(T v)` + with `T = int` + must satisfy the following constraint: +` N!T` +fail_compilation/constraints_func1.d(81): Error: template `imports.constraints.test4` cannot deduce function from argument types `!()(int)`, candidates are: +fail_compilation/imports/constraints.d(12): `test4(T)(T v)` + with `T = int` + must satisfy the following constraint: +` N!T` +fail_compilation/constraints_func1.d(82): Error: template `imports.constraints.test5` cannot deduce function from argument types `!()(int)`, candidates are: +fail_compilation/imports/constraints.d(13): `test5(T)(T v)` + with `T = int` + must satisfy one of the following constraints: +` N!T + N!T` +fail_compilation/constraints_func1.d(83): Error: template `imports.constraints.test6` cannot deduce function from argument types `!()(int)`, candidates are: +fail_compilation/imports/constraints.d(14): `test6(T)(T v)` + with `T = int` + must satisfy one of the following constraints: +` N!T + N!T + !P!T` +fail_compilation/constraints_func1.d(84): Error: template `imports.constraints.test7` cannot deduce function from argument types `!()(int)`, candidates are: +fail_compilation/imports/constraints.d(15): `test7(T)(T v)` + with `T = int` + must satisfy one of the following constraints: +` N!T + N!T` +fail_compilation/constraints_func1.d(85): Error: template `imports.constraints.test8` cannot deduce function from argument types `!()(int)`, candidates are: +fail_compilation/imports/constraints.d(16): `test8(T)(T v)` + with `T = int` + must satisfy the following constraint: +` N!T` +fail_compilation/constraints_func1.d(86): Error: template `imports.constraints.test9` cannot deduce function from argument types `!()(int)`, candidates are: +fail_compilation/imports/constraints.d(17): `test9(T)(T v)` + with `T = int` + must satisfy the following constraint: +` !P!T` +fail_compilation/constraints_func1.d(87): Error: template `imports.constraints.test10` cannot deduce function from argument types `!()(int)`, candidates are: +fail_compilation/imports/constraints.d(18): `test10(T)(T v)` + with `T = int` + must satisfy the following constraint: +` !P!T` +fail_compilation/constraints_func1.d(88): Error: template `imports.constraints.test11` cannot deduce function from argument types `!()(int)`, candidates are: +fail_compilation/imports/constraints.d(19): `test11(T)(T v)` + with `T = int` + must satisfy one of the following constraints: +` N!T + !P!T` +fail_compilation/constraints_func1.d(89): Error: template `imports.constraints.test12` cannot deduce function from argument types `!()(int)`, candidates are: +fail_compilation/imports/constraints.d(20): `test12(T)(T v)` + with `T = int` + must satisfy the following constraint: +` !P!T` +fail_compilation/constraints_func1.d(91): Error: template `imports.constraints.test1` cannot deduce function from argument types `!()(int, int)`, candidates are: +fail_compilation/imports/constraints.d(9): `test1(T)(T v)` +--- +*/ + +void main() +{ + import imports.constraints; + + test1(0); + test2(0); + test3(0); + test4(0); + test5(0); + test6(0); + test7(0); + test8(0); + test9(0); + test10(0); + test11(0); + test12(0); + + test1(0, 0); +} diff --git a/test/fail_compilation/constraints_func2.d b/test/fail_compilation/constraints_func2.d new file mode 100755 index 000000000000..d38965476ea9 --- /dev/null +++ b/test/fail_compilation/constraints_func2.d @@ -0,0 +1,107 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/constraints_func2.d(93): Error: template `imports.constraints.test13` cannot deduce function from argument types `!()(int)`, candidates are: +fail_compilation/imports/constraints.d(23): `test13(T)(T v)` + with `T = int` + must satisfy one of the following constraints: +` N!T + !P!T` +fail_compilation/constraints_func2.d(94): Error: template `imports.constraints.test14` cannot deduce function from argument types `!()(int)`, candidates are: +fail_compilation/imports/constraints.d(24): `test14(T)(T v)` + with `T = int` + must satisfy one of the following constraints: +` !P!T + N!T` +fail_compilation/constraints_func2.d(95): Error: template `imports.constraints.test15` cannot deduce function from argument types `!()(int)`, candidates are: +fail_compilation/imports/constraints.d(25): `test15(T)(T v)` + with `T = int` + must satisfy one of the following constraints: +` !P!T + !P!T` +fail_compilation/constraints_func2.d(96): Error: template `imports.constraints.test16` cannot deduce function from argument types `!()(int)`, candidates are: +fail_compilation/imports/constraints.d(26): `test16(T)(T v)` + with `T = int` + must satisfy one of the following constraints: +` N!T + N!T` +fail_compilation/constraints_func2.d(97): Error: template `imports.constraints.test17` cannot deduce function from argument types `!()(int)`, candidates are: +fail_compilation/imports/constraints.d(27): `test17(T)(T v)` + with `T = int` + must satisfy the following constraint: +` N!T` +fail_compilation/constraints_func2.d(98): Error: template `imports.constraints.test18` cannot deduce function from argument types `!()(int)`, candidates are: +fail_compilation/imports/constraints.d(28): `test18(T)(T v)` + with `T = int` + must satisfy one of the following constraints: +` N!T + N!T` +fail_compilation/constraints_func2.d(99): Error: template `imports.constraints.test19` cannot deduce function from argument types `!()(int)`, candidates are: +fail_compilation/imports/constraints.d(29): `test19(T)(T v)` + with `T = int` + must satisfy one of the following constraints: +` N!T + !P!T + N!T` +fail_compilation/constraints_func2.d(100): Error: template `imports.constraints.test20` cannot deduce function from argument types `!()(int)`, candidates are: +fail_compilation/imports/constraints.d(30): `test20(T)(T v)` + with `T = int` + must satisfy the following constraint: +` N!T` +fail_compilation/constraints_func2.d(101): Error: template `imports.constraints.test21` cannot deduce function from argument types `!()(int)`, candidates are: +fail_compilation/imports/constraints.d(31): `test21(T)(T v)` + with `T = int` + must satisfy one of the following constraints: +` N!T + N!T` +fail_compilation/constraints_func2.d(102): Error: template `imports.constraints.test22` cannot deduce function from argument types `!()(int)`, candidates are: +fail_compilation/imports/constraints.d(32): `test22(T)(T v)` + with `T = int` + must satisfy one of the following constraints: +` !P!T + !P!T` +fail_compilation/constraints_func2.d(103): Error: template `imports.constraints.test23` cannot deduce function from argument types `!()(int)`, candidates are: +fail_compilation/imports/constraints.d(33): `test23(T)(T v)` + with `T = int` + must satisfy one of the following constraints: +` !P!T + N!T + !P!T` +fail_compilation/constraints_func2.d(104): Error: template `imports.constraints.test24` cannot deduce function from argument types `!()(int)`, candidates are: +fail_compilation/imports/constraints.d(34): `test24(R)(R r)` + with `R = int` + must satisfy the following constraint: +` __traits(hasMember, R, "stuff")` +fail_compilation/constraints_func2.d(105): Error: template `imports.constraints.test25` cannot deduce function from argument types `!()(int)`, candidates are: +fail_compilation/imports/constraints.d(35): `test25(T)(T v)` + with `T = int` + must satisfy the following constraint: +` N!T` +fail_compilation/constraints_func2.d(106): Error: template `imports.constraints.test26` cannot deduce function from argument types `!(float)(int)`, candidates are: +fail_compilation/imports/constraints.d(36): `test26(T, U)(U u)` + with `T = float, + U = int` + must satisfy the following constraint: +` N!U` +--- +*/ + +void main() +{ + import imports.constraints; + + test13(0); + test14(0); + test15(0); + test16(0); + test17(0); + test18(0); + test19(0); + test20(0); + test21(0); + test22(0); + test23(0); + test24(0); + test25(0); + test26!float(5); +} diff --git a/test/fail_compilation/constraints_func3.d b/test/fail_compilation/constraints_func3.d new file mode 100755 index 000000000000..c52e6b3ee5a8 --- /dev/null +++ b/test/fail_compilation/constraints_func3.d @@ -0,0 +1,59 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/constraints_func3.d(52): Error: template `imports.constraints.overload` cannot deduce function from argument types `!()(int)`, candidates are: +fail_compilation/imports/constraints.d(39): `overload(T)(T v)` + with `T = int` + must satisfy the following constraint: +` N!T` +fail_compilation/imports/constraints.d(40): `overload(T)(T v)` + with `T = int` + must satisfy the following constraint: +` !P!T` +fail_compilation/imports/constraints.d(41): `overload(T)(T v1, T v2)` +fail_compilation/imports/constraints.d(42): `overload(T, V)(T v1, V v2)` +fail_compilation/constraints_func3.d(53): Error: template `imports.constraints.overload` cannot deduce function from argument types `!()(int, string)`, candidates are: +fail_compilation/imports/constraints.d(39): `overload(T)(T v)` +fail_compilation/imports/constraints.d(40): `overload(T)(T v)` +fail_compilation/imports/constraints.d(41): `overload(T)(T v1, T v2)` +fail_compilation/imports/constraints.d(42): `overload(T, V)(T v1, V v2)` + with `T = int, + V = string` + must satisfy one of the following constraints: +` N!T + N!V` +fail_compilation/constraints_func3.d(55): Error: template `imports.constraints.variadic` cannot deduce function from argument types `!()()`, candidates are: +fail_compilation/imports/constraints.d(43): `variadic(A, T...)(A a, T v)` +fail_compilation/constraints_func3.d(56): Error: template `imports.constraints.variadic` cannot deduce function from argument types `!()(int)`, candidates are: +fail_compilation/imports/constraints.d(43): `variadic(A, T...)(A a, T v)` + with `A = int, + T = ()` + must satisfy the following constraint: +` N!int` +fail_compilation/constraints_func3.d(57): Error: template `imports.constraints.variadic` cannot deduce function from argument types `!()(int, int)`, candidates are: +fail_compilation/imports/constraints.d(43): `variadic(A, T...)(A a, T v)` + with `A = int, + T = (int)` + must satisfy the following constraint: +` N!int` +fail_compilation/constraints_func3.d(58): Error: template `imports.constraints.variadic` cannot deduce function from argument types `!()(int, int, int)`, candidates are: +fail_compilation/imports/constraints.d(43): `variadic(A, T...)(A a, T v)` + with `A = int, + T = (int, int)` + must satisfy the following constraint: +` N!int` +--- +*/ + +void main() +{ + import imports.constraints; + + overload(0); + overload(0, ""); + + variadic(); + variadic(0); + variadic(0, 1); + variadic(0, 1, 2); +} diff --git a/test/fail_compilation/constraints_tmpl.d b/test/fail_compilation/constraints_tmpl.d new file mode 100755 index 000000000000..9054efeb465a --- /dev/null +++ b/test/fail_compilation/constraints_tmpl.d @@ -0,0 +1,43 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/constraints_tmpl.d(34): Error: template instance `imports.constraints.dummy!()` does not match template declaration `dummy()()` + must satisfy the following constraint: +` false` +fail_compilation/constraints_tmpl.d(36): Error: template instance `imports.constraints.message_nice!(int, int)` does not match template declaration `message_nice(T, U)()` + with `T = int, + U = int` + must satisfy the following constraint: +` N!U` +fail_compilation/constraints_tmpl.d(37): Error: template instance `imports.constraints.message_ugly!int` does not match template declaration `message_ugly(T)(T v)` + with `T = int` + must satisfy the following constraint: +` N!T` +fail_compilation/constraints_tmpl.d(39): Error: template instance `args!int` does not match template declaration `args(T, U)()` +fail_compilation/constraints_tmpl.d(40): Error: template instance `imports.constraints.args!(int, float)` does not match template declaration `args(T, U)()` + with `T = int, + U = float` + must satisfy one of the following constraints: +` N!T + N!U` +fail_compilation/constraints_tmpl.d(42): Error: template instance `constraints_tmpl.main.lambda!((a) => a)` does not match template declaration `lambda(alias pred)()` + with `pred = __lambda1` + must satisfy the following constraint: +` N!int` +--- +*/ + +void main() +{ + import imports.constraints; + + dummy!(); + + message_nice!(int, int); + message_ugly!int; + + args!int; + args!(int, float); + + lambda!(a => a)(); +} diff --git a/test/fail_compilation/imports/constraints.d b/test/fail_compilation/imports/constraints.d new file mode 100755 index 000000000000..a19e89ac00cc --- /dev/null +++ b/test/fail_compilation/imports/constraints.d @@ -0,0 +1,73 @@ +module imports.constraints; + +// can be shared between usual and verbose output versions + +enum P(T) = true; +enum N(T) = false; + +// constraints_func1 +void test1(T)(T v) if (N!T); +void test2(T)(T v) if (!P!T); +void test3(T)(T v) if (P!T && N!T); +void test4(T)(T v) if (P!T && N!T && P!T); +void test5(T)(T v) if (N!T || N!T); +void test6(T)(T v) if (N!T || N!T || !P!T); +void test7(T)(T v) if (N!T || P!T && N!T); +void test8(T)(T v) if ((N!T || P!T) && N!T); +void test9(T)(T v) if (!P!T && !N!T); +void test10(T)(T v) if (!N!T && !P!T); +void test11(T)(T v) if (!(!N!T && P!T)); +void test12(T)(T v) if (!(N!T || P!T)); + +// constraints_func2 +void test13(T)(T v) if (P!T ? N!T : P!T); // P!T && N!T || !P!T && P!T +void test14(T)(T v) if (!P!T ? P!T : N!T); +void test15(T)(T v) if (!(P!T ? P!T : N!T)); // (!P!T || !P!T) && (P!T || !N!T) +void test16(T)(T v) if (N!T && P!T || N!T); +void test17(T)(T v) if (N!T && P!T && (P!T || P!T)); +void test18(T)(T v) if ((N!T || P!T && N!T) && P!T); +void test19(T)(T v) if ((N!T ? P!T : !P!T) ? P!T : N!T); // (N!T && P!T || !N!T && !P!T) && P!T || (!N!T || !P!T) && (N!T || P!T) && N!T +void test20(T)(T v) if (N!T && (P!T && N!T || N!T)); +void test21(T)(T v) if (P!T && (N!T && P!T || N!T)); +void test22(T)(T v) if ((!P!T || !P!T && P!T) && (N!T || !P!T)); +void test23(T)(T v) if (!P!T || P!T && N!T || !P!T); +void test24(R)(R r) if (__traits(hasMember, R, "stuff")); +int test25(T)(T v) if (N!T); +float test26(T, U)(U u) if (N!U); + +// constraints_func3 +void overload(T)(T v) if (N!T); +void overload(T)(T v) if (!P!T); +void overload(T)(T v1, T v2) if (N!T); +void overload(T, V)(T v1, V v2) if (N!T || N!V); +void variadic(A, T...)(A a, T v) if (N!int); + +// constraints_tmpl +void dummy()() if (false); +void message_nice(T, U)() if (P!T && "message 1" && N!U && "message 2"); +void message_ugly(T)(T v) if (!N!T && (T.stringof ~ " must be that") && N!T); +void args(T, U)() if (N!T || N!U); +void lambda(alias pred)() if (N!int); + +// constraints_defs +void def(T, int i = 5, alias R)() if (N!T); +void defa(T, U = int)() if (N!T); +void defv(T = bool, int i = 5, Ts...)() if (N!T); + +// constraints_aggr +class C +{ + void f(T)(T v) if (P!T && !P!T) + {} + + void g(this T)() if (N!T) + {} +} + +template S(T) if (N!T) +{ + alias S = T; +} + +struct BitFlags(E, bool unsafe = false) if (unsafe || N!E) +{} From 97ef16b0cc0b79f42e4a23972cbb7a8c566fe7d7 Mon Sep 17 00:00:00 2001 From: dayllenger Date: Tue, 4 Jun 2019 12:26:23 +0300 Subject: [PATCH 8/8] update tests (error messages) --- test/fail_compilation/b6227.d | 2 +- test/fail_compilation/bug9631.d | 4 ++-- test/fail_compilation/diag13942.d | 2 +- test/fail_compilation/diag16977.d | 15 +++++++++------ test/fail_compilation/diag8101.d | 16 ++++++++-------- test/fail_compilation/diag8648.d | 6 +++--- test/fail_compilation/diag9004.d | 2 +- test/fail_compilation/diag9880.d | 5 ++++- test/fail_compilation/fail11125.d | 10 ++++++++-- test/fail_compilation/fail12744.d | 4 ++-- test/fail_compilation/fail14669.d | 2 +- test/fail_compilation/fail162.d | 2 +- test/fail_compilation/fail236.d | 2 +- test/fail_compilation/fail319.d | 5 ++++- test/fail_compilation/fail8009.d | 2 +- test/fail_compilation/fail95.d | 2 +- test/fail_compilation/ice14130.d | 2 +- test/fail_compilation/ice14907.d | 2 +- test/fail_compilation/ice6538.d | 2 +- test/fail_compilation/ice9284.d | 2 +- test/fail_compilation/test19107.d | 8 ++++++-- test/fail_compilation/test8556.d | 7 +++++-- test/fail_compilation/test9176.d | 2 +- 23 files changed, 64 insertions(+), 42 deletions(-) diff --git a/test/fail_compilation/b6227.d b/test/fail_compilation/b6227.d index 2c12b15617c7..42177950170a 100644 --- a/test/fail_compilation/b6227.d +++ b/test/fail_compilation/b6227.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- fail_compilation/b6227.d(16): Error: Comparison between different enumeration types `X` and `Y`; If this behavior is intended consider using `std.conv.asOriginalType` -fail_compilation/b6227.d(16): while evaluating: `static assert(!false)` +fail_compilation/b6227.d(16): while evaluating: `static assert(!(cast(X)0 != cast(Y)0))` fail_compilation/b6227.d(17): Error: Comparison between different enumeration types `X` and `Y`; If this behavior is intended consider using `std.conv.asOriginalType` fail_compilation/b6227.d(17): while evaluating: `static assert(cast(X)0 == cast(Y)0)` --- diff --git a/test/fail_compilation/bug9631.d b/test/fail_compilation/bug9631.d index 330fd50c3f79..c7ac4e87596b 100644 --- a/test/fail_compilation/bug9631.d +++ b/test/fail_compilation/bug9631.d @@ -92,9 +92,9 @@ 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(105): `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)` +fail_compilation/bug9631.d(108): `ft2(T)(S, T)` --- */ void targ() diff --git a/test/fail_compilation/diag13942.d b/test/fail_compilation/diag13942.d index 7b27c6fcb3ff..b41e6feafcc7 100644 --- a/test/fail_compilation/diag13942.d +++ b/test/fail_compilation/diag13942.d @@ -3,7 +3,7 @@ TEST_OUTPUT: --- fail_compilation/diag13942.d(18): Error: template instance `isRawStaticArray!()` does not match template declaration `isRawStaticArray(T, A...)` fail_compilation/diag13942.d(26): Error: template `diag13942.to!double.to` cannot deduce function from argument types `!()()`, candidates are: -fail_compilation/diag13942.d(17): `diag13942.to!double.to(A...)(A args) if (!isRawStaticArray!A)` +fail_compilation/diag13942.d(17): `to(A...)(A args)` --- */ diff --git a/test/fail_compilation/diag16977.d b/test/fail_compilation/diag16977.d index 9c9b5db6e96e..142051be0534 100644 --- a/test/fail_compilation/diag16977.d +++ b/test/fail_compilation/diag16977.d @@ -1,12 +1,15 @@ /* TEST_OUTPUT: --- -fail_compilation/diag16977.d(22): Error: undefined identifier `undefined`, did you mean function `undefinedId`? -fail_compilation/diag16977.d(23): Error: cannot implicitly convert expression `"\x01string"` of type `string` to `int` -fail_compilation/diag16977.d(24): Error: template `diag16977.templ` cannot deduce function from argument types `!()(int)`, candidates are: -fail_compilation/diag16977.d(17): `diag16977.templ(S)(S s) if (false)` -fail_compilation/diag16977.d(25): Error: cannot implicitly convert expression `5` of type `int` to `string` -fail_compilation/diag16977.d(27): Error: template instance `diag16977.test.funcTemplate!string` error instantiating +fail_compilation/diag16977.d(25): Error: undefined identifier `undefined`, did you mean function `undefinedId`? +fail_compilation/diag16977.d(26): Error: cannot implicitly convert expression `"\x01string"` of type `string` to `int` +fail_compilation/diag16977.d(27): Error: template `diag16977.templ` cannot deduce function from argument types `!()(int)`, candidates are: +fail_compilation/diag16977.d(20): `templ(S)(S s)` + with `S = int` + must satisfy the following constraint: +` false` +fail_compilation/diag16977.d(28): Error: cannot implicitly convert expression `5` of type `int` to `string` +fail_compilation/diag16977.d(30): Error: template instance `diag16977.test.funcTemplate!string` error instantiating --- */ diff --git a/test/fail_compilation/diag8101.d b/test/fail_compilation/diag8101.d index 3b2401ad8cf5..c795748ef6d5 100644 --- a/test/fail_compilation/diag8101.d +++ b/test/fail_compilation/diag8101.d @@ -14,16 +14,16 @@ fail_compilation/diag8101.d(39): `diag8101.f_2(int, int, int, int)` fail_compilation/diag8101.d(40): `diag8101.f_2(int, int, int, int, int)` fail_compilation/diag8101.d(59): ... (1 more, -v to show) ... fail_compilation/diag8101.d(61): Error: template `diag8101.t_0` cannot deduce function from argument types `!()()`, candidates are: -fail_compilation/diag8101.d(43): `diag8101.t_0(T1)()` +fail_compilation/diag8101.d(43): `t_0(T1)()` fail_compilation/diag8101.d(62): Error: template `diag8101.t_1` cannot deduce function from argument types `!()()`, candidates are: -fail_compilation/diag8101.d(45): `diag8101.t_1(T1)()` -fail_compilation/diag8101.d(46): `diag8101.t_1(T1, T2)()` +fail_compilation/diag8101.d(45): `t_1(T1)()` +fail_compilation/diag8101.d(46): `t_1(T1, T2)()` fail_compilation/diag8101.d(63): Error: template `diag8101.t_2` cannot deduce function from argument types `!()()`, candidates are: -fail_compilation/diag8101.d(48): `diag8101.t_2(T1)()` -fail_compilation/diag8101.d(49): `diag8101.t_2(T1, T2)()` -fail_compilation/diag8101.d(50): `diag8101.t_2(T1, T2, T3)()` -fail_compilation/diag8101.d(51): `diag8101.t_2(T1, T2, T3, T4)()` -fail_compilation/diag8101.d(52): `diag8101.t_2(T1, T2, T3, T4, T5)()` +fail_compilation/diag8101.d(48): `t_2(T1)()` +fail_compilation/diag8101.d(49): `t_2(T1, T2)()` +fail_compilation/diag8101.d(50): `t_2(T1, T2, T3)()` +fail_compilation/diag8101.d(51): `t_2(T1, T2, T3, T4)()` +fail_compilation/diag8101.d(52): `t_2(T1, T2, T3, T4, T5)()` fail_compilation/diag8101.d(63): ... (1 more, -v to show) ... --- */ diff --git a/test/fail_compilation/diag8648.d b/test/fail_compilation/diag8648.d index 1f175df3052d..c38d34cfd75e 100644 --- a/test/fail_compilation/diag8648.d +++ b/test/fail_compilation/diag8648.d @@ -3,13 +3,13 @@ TEST_OUTPUT: --- fail_compilation/diag8648.d(18): Error: undefined identifier `X` fail_compilation/diag8648.d(29): Error: template `diag8648.foo` cannot deduce function from argument types `!()(Foo!(int, 1))`, candidates are: -fail_compilation/diag8648.d(18): `diag8648.foo(T, n)(X!(T, n))` +fail_compilation/diag8648.d(18): `foo(T, n)(X!(T, n))` fail_compilation/diag8648.d(20): Error: undefined identifier `a` fail_compilation/diag8648.d(31): Error: template `diag8648.bar` cannot deduce function from argument types `!()(Foo!(int, 1))`, candidates are: -fail_compilation/diag8648.d(20): `diag8648.bar(T)(Foo!(T, a))` +fail_compilation/diag8648.d(20): `bar(T)(Foo!(T, a))` fail_compilation/diag8648.d(20): Error: undefined identifier `a` fail_compilation/diag8648.d(32): Error: template `diag8648.bar` cannot deduce function from argument types `!()(Foo!(int, f))`, candidates are: -fail_compilation/diag8648.d(20): `diag8648.bar(T)(Foo!(T, a))` +fail_compilation/diag8648.d(20): `bar(T)(Foo!(T, a))` --- */ diff --git a/test/fail_compilation/diag9004.d b/test/fail_compilation/diag9004.d index 5276940d3884..603656bd7dee 100644 --- a/test/fail_compilation/diag9004.d +++ b/test/fail_compilation/diag9004.d @@ -2,7 +2,7 @@ TEST_OUTPUT: --- fail_compilation/diag9004.d(21): Error: template `diag9004.bar` cannot deduce function from argument types `!()(Foo!int, int)`, candidates are: -fail_compilation/diag9004.d(14): `diag9004.bar(FooT)(FooT foo, FooT.T x)` +fail_compilation/diag9004.d(14): `bar(FooT)(FooT foo, FooT.T x)` --- */ diff --git a/test/fail_compilation/diag9880.d b/test/fail_compilation/diag9880.d index 1ad964704dd6..597b94eb13d2 100644 --- a/test/fail_compilation/diag9880.d +++ b/test/fail_compilation/diag9880.d @@ -1,7 +1,10 @@ /* TEST_OUTPUT: --- -fail_compilation/diag9880.d(9): Error: template instance `diag9880.foo!string` does not match template declaration `foo(T)(int) if (is(T == int))` +fail_compilation/diag9880.d(12): Error: template instance `diag9880.foo!string` does not match template declaration `foo(T)(int)` + with `T = string` + must satisfy the following constraint: +` is(T == int)` --- */ diff --git a/test/fail_compilation/fail11125.d b/test/fail_compilation/fail11125.d index 49c452cc4428..e04e3f14f080 100644 --- a/test/fail_compilation/fail11125.d +++ b/test/fail_compilation/fail11125.d @@ -1,8 +1,14 @@ /* TEST_OUTPUT: --- -fail_compilation/fail11125.d(20): Error: template instance `fail11125.filter!(function (int a) => a + 1)` does not match template declaration `filter(alias predfun) if (is(ReturnType!predfun == bool))` -fail_compilation/fail11125.d(21): Error: template instance `fail11125.filter!(function (int a) => a + 1)` does not match template declaration `filter(alias predfun) if (is(ReturnType!predfun == bool))` +fail_compilation/fail11125.d(26): Error: template instance `fail11125.filter!(function (int a) => a + 1)` does not match template declaration `filter(alias predfun)` + with `predfun = __lambda1` + must satisfy the following constraint: +` is(ReturnType!predfun == bool)` +fail_compilation/fail11125.d(27): Error: template instance `fail11125.filter!(function (int a) => a + 1)` does not match template declaration `filter(alias predfun)` + with `predfun = __lambda2` + must satisfy the following constraint: +` is(ReturnType!predfun == bool)` --- */ diff --git a/test/fail_compilation/fail12744.d b/test/fail_compilation/fail12744.d index 4575582ddf56..0371e357c753 100644 --- a/test/fail_compilation/fail12744.d +++ b/test/fail_compilation/fail12744.d @@ -15,10 +15,10 @@ fail_compilation/fail12744.d(40): Error: incompatible parameter storage classes fail_compilation/fail12744.d(62): Error: template instance `fail12744.bar12744L!(foo12744O)` error instantiating fail_compilation/fail12744.d(41): Error: incompatible parameter storage classes `auto ref` and `out` fail_compilation/fail12744.d(67): Error: template `fail12744.bar12744A` cannot deduce function from argument types `!(foo12744O)(int)`, candidates are: -fail_compilation/fail12744.d(41): `fail12744.bar12744A(alias f)(auto ref PTT12744!f args)` +fail_compilation/fail12744.d(41): `bar12744A(alias f)(auto ref PTT12744!f args)` fail_compilation/fail12744.d(41): Error: incompatible parameter storage classes `auto ref` and `lazy` fail_compilation/fail12744.d(68): Error: template `fail12744.bar12744A` cannot deduce function from argument types `!(foo12744L)(int)`, candidates are: -fail_compilation/fail12744.d(41): `fail12744.bar12744A(alias f)(auto ref PTT12744!f args)` +fail_compilation/fail12744.d(41): `bar12744A(alias f)(auto ref PTT12744!f args)` --- */ template PTT12744(func...) diff --git a/test/fail_compilation/fail14669.d b/test/fail_compilation/fail14669.d index 5c730b8fee71..bc8f40baf274 100644 --- a/test/fail_compilation/fail14669.d +++ b/test/fail_compilation/fail14669.d @@ -5,7 +5,7 @@ fail_compilation/fail14669.d(11): Error: `auto` can only be used as part of `aut fail_compilation/fail14669.d(16): Error: template instance `fail14669.foo1!()` error instantiating fail_compilation/fail14669.d(12): Error: `auto` can only be used as part of `auto ref` for template function parameters fail_compilation/fail14669.d(17): Error: template `fail14669.foo2` cannot deduce function from argument types `!()(int)`, candidates are: -fail_compilation/fail14669.d(12): `fail14669.foo2()(auto int a)` +fail_compilation/fail14669.d(12): `foo2()(auto int a)` --- */ void foo1()(auto int a) {} diff --git a/test/fail_compilation/fail162.d b/test/fail_compilation/fail162.d index f94734f63550..587442210b37 100644 --- a/test/fail_compilation/fail162.d +++ b/test/fail_compilation/fail162.d @@ -2,7 +2,7 @@ TEST_OUTPUT: --- fail_compilation/fail162.d(25): Error: template `fail162.testHelper` cannot deduce function from argument types `!()(string, string)`, candidates are: -fail_compilation/fail162.d(10): `fail162.testHelper(A...)()` +fail_compilation/fail162.d(10): `testHelper(A...)()` fail_compilation/fail162.d(30): Error: template instance `fail162.test!("hello", "world")` error instantiating --- */ diff --git a/test/fail_compilation/fail236.d b/test/fail_compilation/fail236.d index 53407bdfac8c..d6ce27dd12ab 100644 --- a/test/fail_compilation/fail236.d +++ b/test/fail_compilation/fail236.d @@ -3,7 +3,7 @@ TEST_OUTPUT: --- fail_compilation/fail236.d(14): Error: undefined identifier `x` fail_compilation/fail236.d(22): Error: template `fail236.Templ2` cannot deduce function from argument types `!()(int)`, candidates are: -fail_compilation/fail236.d(12): `fail236.Templ2(alias a)(x)` +fail_compilation/fail236.d(12): `Templ2(alias a)(x)` --- */ diff --git a/test/fail_compilation/fail319.d b/test/fail_compilation/fail319.d index d82a5e0e9f7d..cf56feecc53f 100644 --- a/test/fail_compilation/fail319.d +++ b/test/fail_compilation/fail319.d @@ -1,7 +1,10 @@ /* TEST_OUTPUT: --- -fail_compilation/fail319.d(13): Error: template instance `fail319.f!(int, int)` does not match template declaration `f(T...)() if (T.length > 20)` +fail_compilation/fail319.d(16): Error: template instance `fail319.f!(int, int)` does not match template declaration `f(T...)()` + with `T = (int, int)` + must satisfy the following constraint: +` T.length > 20` --- */ diff --git a/test/fail_compilation/fail8009.d b/test/fail_compilation/fail8009.d index fa402838b934..19a0712f8382 100644 --- a/test/fail_compilation/fail8009.d +++ b/test/fail_compilation/fail8009.d @@ -2,7 +2,7 @@ TEST_OUTPUT: --- fail_compilation/fail8009.d(9): Error: template `fail8009.filter` cannot deduce function from argument types `!()(void)`, candidates are: -fail_compilation/fail8009.d(8): `fail8009.filter(R)(scope bool delegate(ref BAD!R) func)` +fail_compilation/fail8009.d(8): `filter(R)(scope bool delegate(ref BAD!R) func)` --- */ void filter(R)(scope bool delegate(ref BAD!R) func) { } diff --git a/test/fail_compilation/fail95.d b/test/fail_compilation/fail95.d index 502aca3b6028..f6beb0382310 100644 --- a/test/fail_compilation/fail95.d +++ b/test/fail_compilation/fail95.d @@ -2,7 +2,7 @@ TEST_OUTPUT: --- fail_compilation/fail95.d(19): Error: template `fail95.A` cannot deduce function from argument types `!()(int)`, candidates are: -fail_compilation/fail95.d(11): `fail95.A(alias T)(T)` +fail_compilation/fail95.d(11): `A(alias T)(T)` --- */ diff --git a/test/fail_compilation/ice14130.d b/test/fail_compilation/ice14130.d index 14e94a52f41c..89fbcfcb500a 100644 --- a/test/fail_compilation/ice14130.d +++ b/test/fail_compilation/ice14130.d @@ -3,7 +3,7 @@ TEST_OUTPUT: --- fail_compilation/ice14130.d(10): Error: undefined identifier `Undef` fail_compilation/ice14130.d(14): Error: template `ice14130.foo` cannot deduce function from argument types `!()(int)`, candidates are: -fail_compilation/ice14130.d(10): `ice14130.foo(R, F = Undef)(R r, F s = 0)` +fail_compilation/ice14130.d(10): `foo(R, F = Undef)(R r, F s = 0)` --- */ diff --git a/test/fail_compilation/ice14907.d b/test/fail_compilation/ice14907.d index 2d3c6f138b36..05aaeaf8b926 100644 --- a/test/fail_compilation/ice14907.d +++ b/test/fail_compilation/ice14907.d @@ -7,7 +7,7 @@ fail_compilation/ice14907.d(15): Error: template `ice14907.f(int v = f)()` recur fail_compilation/ice14907.d(20): while looking for match for `f!()` fail_compilation/ice14907.d(15): Error: template `ice14907.f(int v = f)()` recursive template expansion fail_compilation/ice14907.d(21): Error: template `ice14907.f` cannot deduce function from argument types `!()()`, candidates are: -fail_compilation/ice14907.d(15): `ice14907.f(int v = f)()` +fail_compilation/ice14907.d(15): `f(int v = f)()` --- */ diff --git a/test/fail_compilation/ice6538.d b/test/fail_compilation/ice6538.d index e62240e2aad5..940ea31395b0 100644 --- a/test/fail_compilation/ice6538.d +++ b/test/fail_compilation/ice6538.d @@ -8,7 +8,7 @@ TEST_OUTPUT: --- fail_compilation/ice6538.d(23): Error: expression `super` is not a valid template value argument fail_compilation/ice6538.d(28): Error: template `ice6538.D.foo` cannot deduce function from argument types `!()()`, candidates are: -fail_compilation/ice6538.d(23): `ice6538.D.foo()() if (Sym!(super))` +fail_compilation/ice6538.d(23): `foo()()` --- */ diff --git a/test/fail_compilation/ice9284.d b/test/fail_compilation/ice9284.d index a1f25aa9c736..06e7d1131e20 100644 --- a/test/fail_compilation/ice9284.d +++ b/test/fail_compilation/ice9284.d @@ -2,7 +2,7 @@ TEST_OUTPUT: --- fail_compilation/ice9284.d(14): Error: template `ice9284.C.__ctor` cannot deduce function from argument types `!()(int)`, candidates are: -fail_compilation/ice9284.d(12): `ice9284.C.__ctor()(string)` +fail_compilation/ice9284.d(12): `__ctor()(string)` fail_compilation/ice9284.d(20): Error: template instance `ice9284.C.__ctor!()` error instantiating --- */ diff --git a/test/fail_compilation/test19107.d b/test/fail_compilation/test19107.d index c748650b2e41..9d7d1a1d8fd8 100644 --- a/test/fail_compilation/test19107.d +++ b/test/fail_compilation/test19107.d @@ -2,8 +2,12 @@ /* TEST_OUTPUT: --- -fail_compilation/test19107.d(20): Error: template `test19107.all` cannot deduce function from argument types `!((c) => c)(string[])`, candidates are: -fail_compilation/test19107.d(14): `test19107.all(alias pred, T)(T t) if (is(typeof(I!pred(t))))` +fail_compilation/test19107.d(24): Error: template `test19107.all` cannot deduce function from argument types `!((c) => c)(string[])`, candidates are: +fail_compilation/test19107.d(18): `all(alias pred, T)(T t)` + with `pred = __lambda2, + T = string[]` + must satisfy the following constraint: +` is(typeof(I!pred(t)))` --- */ diff --git a/test/fail_compilation/test8556.d b/test/fail_compilation/test8556.d index edf303152b12..05f8765538cd 100644 --- a/test/fail_compilation/test8556.d +++ b/test/fail_compilation/test8556.d @@ -1,8 +1,11 @@ /* TEST_OUTPUT: --- -fail_compilation/test8556.d(21): Error: template instance `test8556.Grab!(Circle!(uint[]))` does not match template declaration `Grab(Range) if (!isSliceable!Range)` -fail_compilation/test8556.d(52): Error: template instance `test8556.grab!(Circle!(uint[]))` error instantiating +fail_compilation/test8556.d(24): Error: template instance `test8556.Grab!(Circle!(uint[]))` does not match template declaration `Grab(Range)` + with `Range = Circle!(uint[])` + must satisfy the following constraint: +` !isSliceable!Range` +fail_compilation/test8556.d(55): Error: template instance `test8556.grab!(Circle!(uint[]))` error instantiating --- */ diff --git a/test/fail_compilation/test9176.d b/test/fail_compilation/test9176.d index 72d9786de8b1..62ae5c048d57 100644 --- a/test/fail_compilation/test9176.d +++ b/test/fail_compilation/test9176.d @@ -2,7 +2,7 @@ TEST_OUTPUT: --- fail_compilation/test9176.d(14): Error: forward reference to inferred return type of function call `get()` -fail_compilation/test9176.d(10): while evaluating: `static assert(!false)` +fail_compilation/test9176.d(10): while evaluating: `static assert(!is(typeof(foo(S()))))` --- */