19
19
*/
20
20
module core.internal.dassert ;
21
21
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
-
34
22
/**
35
23
* Generates rich assert error messages for unary expressions
36
24
*
@@ -49,25 +37,42 @@ string _d_assert_fail(string comp, A, B)(auto ref const scope A a, auto ref cons
49
37
*/
50
38
string _d_assert_fail (A)(const scope string op, auto ref const scope A a)
51
39
{
52
- string val = miniFormatFakeAttributes(a);
40
+ string [ 2 ] vals = [ miniFormatFakeAttributes(a), " true " ] ;
53
41
immutable token = op == " !" ? " ==" : " !=" ;
54
- return combine (val , token, " true " );
42
+ return combine (vals[ 0 .. 1 ] , token, vals[ 1 .. $] );
55
43
}
56
44
57
45
/**
58
46
* Generates rich assert error messages for binary expressions
59
47
*
60
48
* 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))`.
62
50
*
63
51
* Params:
64
52
* 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) .
67
55
*
68
56
* Returns:
69
57
* A string such as "$a $comp $b".
70
58
*/
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
71
76
string _d_assert_fail (A, B)(const scope string comp, auto ref const scope A a, auto ref const scope B b)
72
77
{
73
78
/*
@@ -80,23 +85,48 @@ string _d_assert_fail(A, B)(const scope string comp, auto ref const scope A a, a
80
85
string valA = miniFormatFakeAttributes(a);
81
86
string valB = miniFormatFakeAttributes(b);
82
87
immutable token = invertCompToken(comp);
83
- return combine (valA, token, valB);
88
+ return combine ([ valA] , token, [ valB] );
84
89
}
85
90
86
91
// / 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
89
94
{
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
+
91
105
char [] buffer = cast (char []) pureAlloc(totalLen)[0 .. totalLen];
92
106
// @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);
95
125
buffer[n++ ] = ' ' ;
96
126
buffer[n .. n + token.length] = token;
97
127
n += token.length;
98
128
buffer[n++ ] = ' ' ;
99
- buffer[n .. n + valB.length] = valB ;
129
+ formatTuple( buffer, n, valB, printBraces) ;
100
130
return (() @trusted => cast (string ) buffer)();
101
131
}
102
132
@@ -165,7 +195,8 @@ private string miniFormat(V)(const scope ref V v)
165
195
166
196
// Format invalid enum values as their base type
167
197
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 ]);
169
200
}
170
201
else static if (is (V == bool ))
171
202
{
@@ -371,7 +402,7 @@ private string invertCompToken(string comp) pure nothrow @nogc @safe
371
402
case " !in" :
372
403
return " in" ;
373
404
default :
374
- assert (0 , combine(" Invalid comparison operator" , " -" , comp));
405
+ assert (0 , combine([ " Invalid comparison operator" ] , " -" , [ comp] ));
375
406
}
376
407
}
377
408
0 commit comments