Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.

Commit 728f1d9

Browse files
authored
Merge pull request #3318 from MoonlightSentinel/checkaction-tuples
Fix 21472 (1/2) - Add tuple formatting to _d_assert_fail` merged-on-behalf-of: Mathias LANG <pro.mathias.lang@gmail.com>
2 parents 09ddfff + 1456451 commit 728f1d9

File tree

2 files changed

+70
-37
lines changed

2 files changed

+70
-37
lines changed

src/core/internal/dassert.d

Lines changed: 57 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,6 @@
1919
*/
2020
module core.internal.dassert;
2121

22-
// Legacy hooks currently used by dmd, remove once dmd uses
23-
// the new runtime versions defined below
24-
string _d_assert_fail(string op, A)(auto ref const scope A a)
25-
{
26-
return _d_assert_fail!(A)(op, a);
27-
}
28-
29-
string _d_assert_fail(string comp, A, B)(auto ref const scope A a, auto ref const scope B b)
30-
{
31-
return _d_assert_fail!(A, B)(comp, a, b);
32-
}
33-
3422
/**
3523
* Generates rich assert error messages for unary expressions
3624
*
@@ -49,25 +37,42 @@ string _d_assert_fail(string comp, A, B)(auto ref const scope A a, auto ref cons
4937
*/
5038
string _d_assert_fail(A)(const scope string op, auto ref const scope A a)
5139
{
52-
string val = miniFormatFakeAttributes(a);
40+
string[2] vals = [ miniFormatFakeAttributes(a), "true" ];
5341
immutable token = op == "!" ? "==" : "!=";
54-
return combine(val, token, "true");
42+
return combine(vals[0 .. 1], token, vals[1 .. $]);
5543
}
5644

5745
/**
5846
* Generates rich assert error messages for binary expressions
5947
*
6048
* The binary expression `assert(x == y)` will be turned into
61-
* `assert(x == y, _d_assert_fail("==", x, y))`.
49+
* `assert(x == y, _d_assert_fail!(typeof(x))("==", x, y))`.
6250
*
6351
* Params:
6452
* comp = Comparison operator that was used in the expression.
65-
* a = Left hand side operand.
66-
* b = Right hand side operand.
53+
* a = Left hand side operand (can be a tuple).
54+
* b = Right hand side operand (can be a tuple).
6755
*
6856
* Returns:
6957
* A string such as "$a $comp $b".
7058
*/
59+
template _d_assert_fail(A...)
60+
{
61+
string _d_assert_fail(B...)(
62+
const scope string comp, auto ref const scope A a, auto ref const scope B b)
63+
if (B.length > 0)
64+
{
65+
string[A.length + B.length] vals;
66+
static foreach (idx; 0 .. A.length)
67+
vals[idx] = miniFormatFakeAttributes(a[idx]);
68+
static foreach (idx; 0 .. B.length)
69+
vals[A.length + idx] = miniFormatFakeAttributes(b[idx]);
70+
immutable token = invertCompToken(comp);
71+
return combine(vals[0 .. A.length], token, vals[A.length .. $]);
72+
}
73+
}
74+
75+
// Legacy definition
7176
string _d_assert_fail(A, B)(const scope string comp, auto ref const scope A a, auto ref const scope B b)
7277
{
7378
/*
@@ -80,23 +85,48 @@ string _d_assert_fail(A, B)(const scope string comp, auto ref const scope A a, a
8085
string valA = miniFormatFakeAttributes(a);
8186
string valB = miniFormatFakeAttributes(b);
8287
immutable token = invertCompToken(comp);
83-
return combine(valA, token, valB);
88+
return combine([valA], token, [valB]);
8489
}
8590

8691
/// Combines the supplied arguments into one string "valA token valB"
87-
private string combine(const scope string valA, const scope string token,
88-
const scope string valB) pure nothrow @nogc @safe
92+
private string combine(const scope string[] valA, const scope string token,
93+
const scope string[] valB) pure nothrow @nogc @safe
8994
{
90-
const totalLen = valA.length + token.length + valB.length + 2;
95+
// Each separator is 2 chars (", "), plus the two spaces around the token.
96+
size_t totalLen = (valA.length - 1) * 2 +
97+
(valB.length - 1) * 2 + 2 + token.length;
98+
foreach (v; valA) totalLen += v.length;
99+
foreach (v; valB) totalLen += v.length;
100+
101+
// Include braces when printing tuples
102+
const printBraces = (valA.length + valB.length) > 2;
103+
if (printBraces) totalLen += 4; // '(', ')' for both tuples
104+
91105
char[] buffer = cast(char[]) pureAlloc(totalLen)[0 .. totalLen];
92106
// @nogc-concat of "<valA> <comp> <valB>"
93-
auto n = valA.length;
94-
buffer[0 .. n] = valA;
107+
static void formatTuple (scope char[] buffer, ref size_t n, in string[] vals, in bool printBraces)
108+
{
109+
if (printBraces) buffer[n++] = '(';
110+
foreach (idx, v; vals)
111+
{
112+
if (idx)
113+
{
114+
buffer[n++] = ',';
115+
buffer[n++] = ' ';
116+
}
117+
buffer[n .. n + v.length] = v;
118+
n += v.length;
119+
}
120+
if (printBraces) buffer[n++] = ')';
121+
}
122+
123+
size_t n;
124+
formatTuple(buffer, n, valA, printBraces);
95125
buffer[n++] = ' ';
96126
buffer[n .. n + token.length] = token;
97127
n += token.length;
98128
buffer[n++] = ' ';
99-
buffer[n .. n + valB.length] = valB;
129+
formatTuple(buffer, n, valB, printBraces);
100130
return (() @trusted => cast(string) buffer)();
101131
}
102132

@@ -165,7 +195,8 @@ private string miniFormat(V)(const scope ref V v)
165195

166196
// Format invalid enum values as their base type
167197
enum cast_ = "cast(" ~ V.stringof ~ ")";
168-
return combine(cast_, "", miniFormat(*(cast(BaseType*) &v)));
198+
const val = miniFormat(*(cast(BaseType*) &v));
199+
return combine([ cast_ ], "", [ val ]);
169200
}
170201
else static if (is(V == bool))
171202
{
@@ -371,7 +402,7 @@ private string invertCompToken(string comp) pure nothrow @nogc @safe
371402
case "!in":
372403
return "in";
373404
default:
374-
assert(0, combine("Invalid comparison operator", "-", comp));
405+
assert(0, combine(["Invalid comparison operator"], "-", [comp]));
375406
}
376407
}
377408

test/exceptions/src/assert_fail.d

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import core.internal.dassert : _d_assert_fail;
33

44
void test(string comp = "==", A, B)(A a, B b, string msg, size_t line = __LINE__)
55
{
6-
test(_d_assert_fail!(A, B)(comp, a, b), msg, line);
6+
test(_d_assert_fail!(A)(comp, a, b), msg, line);
77
}
88

99
void test(const string actual, const string expected, size_t line = __LINE__)
@@ -167,10 +167,10 @@ void testStruct()()
167167
}
168168

169169
NoCopy n;
170-
test(_d_assert_fail("!=", n, n), "NoCopy() == NoCopy()");
170+
test(_d_assert_fail!(typeof(n))("!=", n, n), "NoCopy() == NoCopy()");
171171

172172
shared NoCopy sn;
173-
test(_d_assert_fail("!=", sn, sn), "NoCopy() == NoCopy()");
173+
test(_d_assert_fail!(typeof(sn))("!=", sn, sn), "NoCopy() == NoCopy()");
174174
}
175175

176176
void testAA()()
@@ -180,16 +180,18 @@ void testAA()()
180180
test!"in"("foo", ["bar": true], `"foo" !in ["bar": true]`);
181181
}
182182

183-
184183
void testAttributes() @safe pure @nogc nothrow
185184
{
186185
int a;
187-
string s = _d_assert_fail("==", a, 0);
188-
string s2 = _d_assert_fail("!", a);
186+
string s = _d_assert_fail!(int, char)("==", a, 'c', 1, 'd');
187+
assert(s == `(0, 'c') != (1, 'd')`);
188+
189+
string s2 = _d_assert_fail!int("", a);
190+
assert(s2 == `0 != true`);
189191

190192
// Test instatiation of legacy hooks
191-
s = _d_assert_fail!"=="(a, 0);
192-
s2 = _d_assert_fail!"!"(a);
193+
s2 = _d_assert_fail("==", a, 1);
194+
assert(s2 == `0 != 1`);
193195
}
194196

195197
// https://issues.dlang.org/show_bug.cgi?id=20066
@@ -227,13 +229,13 @@ void testEnum()
227229

228230
ubyte[] data;
229231
enum ctfe = UUID();
230-
test(_d_assert_fail("==", ctfe.data, data), "[1] != []");
232+
test(_d_assert_fail!(ubyte[])("==", ctfe.data, data), "[1] != []");
231233
}
232234

233235
void testUnary()
234236
{
235-
test(_d_assert_fail("", 9), "9 != true");
236-
test(_d_assert_fail("!", [1, 2, 3]), "[1, 2, 3] == true");
237+
test(_d_assert_fail!int("", 9), "9 != true");
238+
test(_d_assert_fail!(int[])("!", [1, 2, 3]), "[1, 2, 3] == true");
237239
}
238240

239241
void main()

0 commit comments

Comments
 (0)