1 // PERMUTE_ARGS: -inline -O -property
2 // REQUIRED_ARGS: -dip25
3
4 // Test operator overloading
5
6 extern (C) int printf(const(char*) fmt, ...);
7
Seq(T...)8 template Seq(T...){ alias T Seq; }
9
thrown(E,T)10 bool thrown(E, T)(lazy T val)
11 {
12 try { val(); return false; }
13 catch (E e) { return true; }
14 }
15
stompStack()16 void stompStack() { int[256] sa = 0xdeadbeef; }
17
18 /**************************************/
19
20 class A
21 {
opUnary(string s)22 string opUnary(string s)()
23 {
24 printf("A.opUnary!(%.*s)\n", s.length, s.ptr);
25 return s;
26 }
27 }
28
test1()29 void test1()
30 {
31 auto a = new A();
32
33 +a;
34 -a;
35 ~a;
36 *a;
37 ++a;
38 --a;
39
40 auto x = a++;
41 assert(x == a);
42 auto y = a--;
43 assert(y == a);
44 }
45
46 /**************************************/
47
48 class A2
49 {
opCast(T)50 T opCast(T)()
51 {
52 auto s = T.stringof;
53 printf("A.opCast!(%.*s)\n", s.length, s.ptr);
54 return T.init;
55 }
56 }
57
58
test2()59 void test2()
60 {
61 auto a = new A2();
62
63 auto x = cast(int)a;
64 assert(x == 0);
65
66 auto y = cast(char)a;
67 assert(y == char.init);
68 }
69
70 /**************************************/
71
72 struct A3
73 {
opBinaryA374 int opBinary(string s)(int i)
75 {
76 printf("A.opBinary!(%.*s)\n", s.length, s.ptr);
77 return 0;
78 }
79
80 int opBinaryRight(string s)(int i) if (s == "/" || s == "*")
81 {
82 printf("A.opBinaryRight!(%.*s)\n", s.length, s.ptr);
83 return 0;
84 }
85
opCastA386 T opCast(T)()
87 {
88 auto s = T.stringof;
89 printf("A.opCast!(%.*s)\n", s.length, s.ptr);
90 return T.init;
91 }
92 }
93
94
test3()95 void test3()
96 {
97 A3 a;
98
99 a + 3;
100 4 * a;
101 4 / a;
102 a & 5;
103 }
104
105 /**************************************/
106
107 struct A4
108 {
opUnaryA4109 int opUnary(string s)()
110 {
111 printf("A.opUnary!(%.*s)\n", s.length, s.ptr);
112 return 0;
113 }
114
opCastA4115 T opCast(T)()
116 {
117 auto s = T.stringof;
118 printf("A.opCast!(%.*s)\n", s.length, s.ptr);
119 return T.init;
120 }
121 }
122
123
test4()124 void test4()
125 {
126 A4 a;
127
128 if (a)
129 int x = 3;
130 if (!a)
131 int x = 3;
132 if (!!a)
133 int x = 3;
134 }
135
136 /**************************************/
137
138 class A5
139 {
opEquals(Object o)140 override bool opEquals(Object o)
141 {
142 printf("A.opEquals!(%p)\n", o);
143 return 1;
144 }
145
opUnary(string s)146 int opUnary(string s)()
147 {
148 printf("A.opUnary!(%.*s)\n", s.length, s.ptr);
149 return 0;
150 }
151
opCast(T)152 T opCast(T)()
153 {
154 auto s = T.stringof;
155 printf("A.opCast!(%.*s)\n", s.length, s.ptr);
156 return T.init;
157 }
158 }
159
160 class B5 : A5
161 {
opEquals(Object o)162 override bool opEquals(Object o)
163 {
164 printf("B.opEquals!(%p)\n", o);
165 return 1;
166 }
167 }
168
169
test5()170 void test5()
171 {
172 A5 a = new A5();
173 A5 a2 = new A5();
174 B5 b = new B5();
175 A n = null;
176
177 if (a == a)
178 int x = 3;
179 if (a == a2)
180 int x = 3;
181 if (a == b)
182 int x = 3;
183 if (a == n)
184 int x = 3;
185 if (n == a)
186 int x = 3;
187 if (n == n)
188 int x = 3;
189 }
190
191 /**************************************/
192
193 struct S6
194 {
opEqualsS6195 const bool opEquals(ref const S6 b)
196 {
197 printf("S.opEquals(S %p)\n", &b);
198 return true;
199 }
200
opEqualsS6201 const bool opEquals(ref const T6 b)
202 {
203 printf("S.opEquals(T %p)\n", &b);
204 return true;
205 }
206 }
207
208 struct T6
209 {
opEquals(ref const T6 b)210 const bool opEquals(ref const T6 b)
211 {
212 printf("T.opEquals(T %p)\n", &b);
213 return true;
214 }
215 /+
216 const bool opEquals(ref const S6 b)
217 {
218 printf("T.opEquals(S %p)\n", &b);
219 return true;
220 }
221 +/
222 }
223
224
test6()225 void test6()
226 {
227 S6 s1;
228 S6 s2;
229
230 if (s1 == s2)
231 int x = 3;
232
233 T6 t;
234
235 if (s1 == t)
236 int x = 3;
237
238 if (t == s2)
239 int x = 3;
240 }
241
242 /**************************************/
243
244 struct S7
245 {
opCmpS7246 const int opCmp(ref const S7 b)
247 {
248 printf("S.opCmp(S %p)\n", &b);
249 return -1;
250 }
251
opCmpS7252 const int opCmp(ref const T7 b)
253 {
254 printf("S.opCmp(T %p)\n", &b);
255 return -1;
256 }
257 }
258
259 struct T7
260 {
opCmp(ref const T7 b)261 const int opCmp(ref const T7 b)
262 {
263 printf("T.opCmp(T %p)\n", &b);
264 return -1;
265 }
266 /+
267 const int opCmp(ref const S7 b)
268 {
269 printf("T.opCmp(S %p)\n", &b);
270 return -1;
271 }
272 +/
273 }
274
275
test7()276 void test7()
277 {
278 S7 s1;
279 S7 s2;
280
281 if (s1 < s2)
282 int x = 3;
283
284 T7 t;
285
286 if (s1 < t)
287 int x = 3;
288
289 if (t < s2)
290 int x = 3;
291 }
292
293 /**************************************/
294
295 struct A8
296 {
opUnaryA8297 int opUnary(string s)()
298 {
299 printf("A.opUnary!(%.*s)\n", s.length, s.ptr);
300 return 0;
301 }
302
opIndexUnaryA8303 int opIndexUnary(string s, T)(T i)
304 {
305 printf("A.opIndexUnary!(%.*s)(%d)\n", s.length, s.ptr, i);
306 return 0;
307 }
308
opIndexUnaryA8309 int opIndexUnary(string s, T)(T i, T j)
310 {
311 printf("A.opIndexUnary!(%.*s)(%d, %d)\n", s.length, s.ptr, i, j);
312 return 0;
313 }
314
opSliceUnaryA8315 int opSliceUnary(string s)()
316 {
317 printf("A.opSliceUnary!(%.*s)()\n", s.length, s.ptr);
318 return 0;
319 }
320
opSliceUnaryA8321 int opSliceUnary(string s, T)(T i, T j)
322 {
323 printf("A.opSliceUnary!(%.*s)(%d, %d)\n", s.length, s.ptr, i, j);
324 return 0;
325 }
326 }
327
328
test8()329 void test8()
330 {
331 A8 a;
332
333 -a;
334 -a[3];
335 -a[3, 4];
336 -a[];
337 -a[5 .. 6];
338 --a[3];
339 }
340
341 /**************************************/
342
343 struct A9
344 {
opOpAssignA9345 int opOpAssign(string s)(int i)
346 {
347 printf("A.opOpAssign!(%.*s)\n", s.length, s.ptr);
348 return 0;
349 }
350
opIndexOpAssignA9351 int opIndexOpAssign(string s, T)(int v, T i)
352 {
353 printf("A.opIndexOpAssign!(%.*s)(%d, %d)\n", s.length, s.ptr, v, i);
354 return 0;
355 }
356
opIndexOpAssignA9357 int opIndexOpAssign(string s, T)(int v, T i, T j)
358 {
359 printf("A.opIndexOpAssign!(%.*s)(%d, %d, %d)\n", s.length, s.ptr, v, i, j);
360 return 0;
361 }
362
opSliceOpAssignA9363 int opSliceOpAssign(string s)(int v)
364 {
365 printf("A.opSliceOpAssign!(%.*s)(%d)\n", s.length, s.ptr, v);
366 return 0;
367 }
368
opSliceOpAssignA9369 int opSliceOpAssign(string s, T)(int v, T i, T j)
370 {
371 printf("A.opSliceOpAssign!(%.*s)(%d, %d, %d)\n", s.length, s.ptr, v, i, j);
372 return 0;
373 }
374 }
375
376
test9()377 void test9()
378 {
379 A9 a;
380
381 a += 8;
382 a -= 8;
383 a *= 8;
384 a /= 8;
385 a %= 8;
386 a &= 8;
387 a |= 8;
388 a ^= 8;
389 a <<= 8;
390 a >>= 8;
391 a >>>= 8;
392 a ~= 8;
393 a ^^= 8;
394
395 a[3] += 8;
396 a[3] -= 8;
397 a[3] *= 8;
398 a[3] /= 8;
399 a[3] %= 8;
400 a[3] &= 8;
401 a[3] |= 8;
402 a[3] ^= 8;
403 a[3] <<= 8;
404 a[3] >>= 8;
405 a[3] >>>= 8;
406 a[3] ~= 8;
407 a[3] ^^= 8;
408
409 a[3, 4] += 8;
410 a[] += 8;
411 a[5 .. 6] += 8;
412 }
413
414 /**************************************/
415
416 struct BigInt
417 {
opEqualsBigInt418 int opEquals(T)(T n) const
419 {
420 return 1;
421 }
422
423 int opEquals(T:int)(T n) const
424 {
425 return 1;
426 }
427
428 int opEquals(T:const(BigInt))(T n) const
429 {
430 return 1;
431 }
432
433 }
434
decimal(BigInt b,const BigInt c)435 int decimal(BigInt b, const BigInt c)
436 {
437 while (b != c) {
438 }
439 return 1;
440 }
441
442 /**************************************/
443
444 struct Foo10
445 {
opUnaryFoo10446 int opUnary(string op)() { return 1; }
447 }
448
test10()449 void test10()
450 {
451 Foo10 foo;
452 foo++;
453 }
454
455 /**************************************/
456
457 struct S4913
458 {
459 bool opCast(T : bool)() { return true; }
460 }
461
bug4913()462 int bug4913()
463 {
464 if (S4913 s = S4913()) { return 83; }
465 return 9;
466 }
467
468 static assert(bug4913() == 83);
469
470 /**************************************/
471 // 5551
472
473 struct Foo11 {
474 Foo11 opUnary(string op:"++")() {
475 return this;
476 }
opBinaryFoo11477 Foo11 opBinary(string op)(int y) {
478 return this;
479 }
480 }
481
test11()482 void test11()
483 {
484 auto f = Foo11();
485 f++;
486 }
487
488 /**************************************/
489 // 4099
490
491 struct X4099
492 {
493 int x;
494 alias x this;
495
opUnaryX4099496 typeof(this) opUnary (string operator) ()
497 {
498 printf("operator called\n");
499 return this;
500 }
501 }
502
test4099()503 void test4099()
504 {
505 X4099 x;
506 X4099 r1 = ++x; //operator called
507 X4099 r2 = x++; //BUG! (alias this used. returns int)
508 }
509
510 /**************************************/
511
test12()512 void test12()
513 {
514 static int opeq;
515
516 // xopEquals OK
517 static struct S1a { const bool opEquals( const typeof(this) rhs) { ++opeq; return false; } }
518 static struct S1b { const bool opEquals(ref const typeof(this) rhs) { ++opeq; return false; } }
519 static struct S1c { const bool opEquals( typeof(this) rhs) { ++opeq; return false; } }
520
521 // xopEquals NG
522 static struct S2a { bool opEquals( typeof(this) rhs) { ++opeq; return false; } }
523
524 foreach (S; Seq!(S1a, S1b, S1c))
525 {
526 S s;
527 opeq = 0;
528 assert(s != s); // call opEquals directly
529 assert(!typeid(S).equals(&s, &s)); // -> xopEquals (-> __xopEquals) -> opEquals
530 assert(opeq == 2);
531 }
532
533 foreach (S; Seq!(S2a))
534 {
535 S s;
536 opeq = 0;
537 assert(s != s);
538 assert(thrown!Error(!typeid(S).equals(&s, &s)));
539 // Error("notImplemented") thrown
540 assert(opeq == 1);
541 }
542 }
543
544 /**************************************/
545
test13()546 void test13()
547 {
548 static int opeq;
549
550 struct X
551 {
552 const bool opEquals(const X){ ++opeq; return false; }
553 }
554 struct S
555 {
556 X x;
557 }
558
559 S makeS(){ return S(); }
560
561 S s;
562 opeq = 0;
563 assert(s != s);
564 assert(makeS() != s);
565 assert(s != makeS());
566 assert(makeS() != makeS());
567 assert(opeq == 4);
568
569 // built-in opEquals == const bool opEquals(const S rhs);
570 assert(s != s);
571 assert(opeq == 5);
572
573 // xopEquals
574 assert(!typeid(S).equals(&s, &s));
575 assert(opeq == 6);
576 }
577
578 /**************************************/
579
test14()580 void test14()
581 {
582 static int opeq;
583
584 struct S
585 {
586 const bool opEquals(T)(const T rhs) { ++opeq; return false; }
587 }
588
589 S makeS(){ return S(); }
590
591 S s;
592 opeq = 0;
593 assert(s != s);
594 assert(makeS() != s);
595 assert(s != makeS());
596 assert(makeS() != makeS());
597 assert(opeq == 4);
598
599 // xopEquals (-> __xxopEquals) -> template opEquals
600 assert(!typeid(S).equals(&s, &s));
601 assert(opeq == 5);
602 }
603
604 /**************************************/
605
test15()606 void test15()
607 {
608 struct S
609 {
610 const bool opEquals(T)(const(T) rhs)
611 if (!is(T == S))
612 { return false; }
613
614 @disable const bool opEquals(T)(const(T) rhs)
615 if (is(T == S))
616 { return false; }
617 }
618
619 S makeS(){ return S(); }
620
621 S s;
622 static assert(!__traits(compiles, s != s));
623 static assert(!__traits(compiles, makeS() != s));
624 static assert(!__traits(compiles, s != makeS()));
625 static assert(!__traits(compiles, makeS() != makeS()));
626
627 // xopEquals (-> __xxopEquals) -> Error thrown
628 assert(thrown!Error(!typeid(S).equals(&s, &s)));
629 }
630
631 /**************************************/
632
test16()633 void test16()
634 {
635 struct X
636 {
637 int n;
638 const bool opEquals(T)(T t)
639 {
640 return false;
641 }
642 }
643 struct S
644 {
645 X x;
646 }
647
648 S s1, s2;
649 assert(s1 != s2);
650 // field template opEquals should call
651 }
652
653 /**************************************/
654
test17()655 void test17()
656 {
657 static int opeq = 0;
658
659 struct S
660 {
661 bool opEquals(ref S rhs) { ++opeq; return false; }
662 }
663 S[] sa1 = new S[3];
664 S[] sa2 = new S[3];
665 assert(sa1 != sa2); // isn't used TypeInfo.equals
666 assert(opeq == 1);
667
668 const(S)[] csa = new const(S)[3];
669 static assert(!__traits(compiles, csa == sa1));
670 static assert(!__traits(compiles, sa1 == csa));
671 static assert(!__traits(compiles, csa == csa));
672 }
673
674 /**************************************/
675 // 3789
676
test3789()677 bool test3789()
678 {
679 static struct Float
680 {
681 double x;
682 }
683 Float f;
684 assert(f.x != f.x); // NaN != NaN
685 assert(f != f);
686
687 static struct Array
688 {
689 int[] x;
690 }
691 Array a1 = Array([1,2,3].dup);
692 Array a2 = Array([1,2,3].dup);
693 if (!__ctfe)
694 { // Currently doesn't work this in CTFE - may or may not a bug.
695 assert(a1.x !is a2.x);
696 }
697 assert(a1.x == a2.x);
698 assert(a1 == a2);
699
700 static struct AA
701 {
702 int[int] x;
703 }
704 AA aa1 = AA([1:1,2:2,3:3]);
705 AA aa2 = AA([1:1,2:2,3:3]);
706 if (!__ctfe)
707 { // Currently doesn't work this in CTFE - may or may not a bug.
708 assert(aa1.x !is aa2.x);
709 }
710 if (!__ctfe)
711 { // This is definitely a bug. Should work in CTFE.
712 assert(aa1.x == aa2.x);
713 assert(aa1 == aa2);
714 }
715
716 if (!__ctfe)
717 { // Currently union operation is not supported in CTFE.
718 union U1
719 {
720 double x;
721 }
722 static struct UnionA
723 {
724 int[] a;
725 U1 u;
726 }
727 auto ua1 = UnionA([1,2,3]);
728 auto ua2 = UnionA([1,2,3]);
729 assert(ua1.u.x is ua2.u.x);
730 assert(ua1.u.x != ua2.u.x);
731 assert(ua1 == ua2);
732 ua1.u.x = 1.0;
733 ua2.u.x = 1.0;
734 assert(ua1.u.x is ua2.u.x);
735 assert(ua1.u.x == ua2.u.x);
736 assert(ua1 == ua2);
737 ua1.u.x = double.nan;
738 assert(ua1.u.x !is ua2.u.x);
739 assert(ua1.u.x != ua2.u.x);
740 assert(ua1 != ua2);
741
742 union U2
743 {
744 int[] a;
745 }
746 static struct UnionB
747 {
748 double x;
749 U2 u;
750 }
751 auto ub1 = UnionB(1.0);
752 auto ub2 = UnionB(1.0);
753 assert(ub1 == ub2);
754 ub1.u.a = [1,2,3].dup;
755 ub2.u.a = [1,2,3].dup;
756 assert(ub1.u.a !is ub2.u.a);
757 assert(ub1.u.a == ub2.u.a);
758 assert(ub1 != ub2);
759 ub2.u.a = ub1.u.a;
760 assert(ub1.u.a is ub2.u.a);
761 assert(ub1.u.a == ub2.u.a);
762 assert(ub1 == ub2);
763 }
764
765 if (!__ctfe)
766 { // This is definitely a bug. Should work in CTFE.
767 static struct Class
768 {
769 Object x;
770 }
771 static class X
772 {
773 override bool opEquals(Object o){ return true; }
774 }
775
776 Class c1a = Class(new Object());
777 Class c2a = Class(new Object());
778 assert(c1a.x !is c2a.x);
779 assert(c1a.x != c2a.x);
780 assert(c1a != c2a); // Pass, Object.opEquals works like bitwise compare
781
782 Class c1b = Class(new X());
783 Class c2b = Class(new X());
784 assert(c1b.x !is c2b.x);
785 assert(c1b.x == c2b.x);
786 assert(c1b == c2b); // Fails, should pass
787 }
788 return true;
789 }
790 static assert(test3789());
791
792 /**************************************/
793 // 10037
794
795 struct S10037
796 {
opEqualsS10037797 bool opEquals(ref const S10037) { assert(0); }
798 }
799
800 struct T10037
801 {
802 S10037 s;
803 // Compiler should not generate 'opEquals' here implicitly:
804 }
805
Sub10037(TL...)806 struct Sub10037(TL...)
807 {
808 TL data;
809 int value;
810 alias value this;
811 }
812
test10037()813 void test10037()
814 {
815 S10037 s;
816 T10037 t;
817 static assert( __traits(hasMember, S10037, "opEquals"));
818 static assert(!__traits(hasMember, T10037, "opEquals"));
819 assert(thrown!Error(s == s));
820 assert(thrown!Error(t == t));
821
822 Sub10037!(S10037) lhs;
823 Sub10037!(S10037) rhs;
824 static assert(!__traits(hasMember, Sub10037!(S10037), "opEquals"));
825 assert(lhs == rhs); // lowered to: lhs.value == rhs.value
826 }
827
828 /**************************************/
829 // 5810
830
831 struct Bug5810
832 {
opUnaryBug5810833 void opUnary(string op)() {}
834 }
835
836 struct Foo5810
837 {
838 Bug5810 x;
bar()839 void bar() { x++; }
840 }
841
842 /**************************************/
843 // 6798
844
Tuple6798(T...)845 struct Tuple6798(T...)
846 {
847 T field;
848 alias field this;
849
850 bool opEquals(Tuple6798 rhs)
851 {
852 foreach (i, _; T)
853 {
854 if (this[i] != rhs[i])
855 return false;
856 }
857 return true;
858 }
859 }
tuple6798(T...)860 auto tuple6798(T...)(T args)
861 {
862 return Tuple6798!T(args);
863 }
864
test6798a()865 int test6798a()
866 {
867 //import std.typecons;
868 alias tuple6798 tuple;
869
870 static struct S1
871 {
872 auto opDollar(size_t dim)()
873 {
874 return 99;
875 }
876 auto opSlice(int dim)(int lwr, int upr)
877 {
878 return [dim, lwr, upr];
879 }
880
881 auto opIndex(A...)(A indices)
882 {
883 return tuple(" []", indices);
884 }
885 auto opIndexUnary(string op, A...)(A indices)
886 {
887 return tuple(op~"[]", indices);
888 }
889 auto opIndexAssign(A...)(string s, A indices)
890 {
891 return tuple("[] =", s, indices);
892 }
893 auto opIndexOpAssign(string op, A...)(string s, A indices)
894 {
895 return tuple("[]"~op~"=", s, indices);
896 }
897 }
898 S1 s1;
899 assert( s1[] == tuple(" []"));
900 assert( s1[10] == tuple(" []", 10));
901 assert( s1[10, 20] == tuple(" []", 10, 20));
902 assert( s1[10..20] == tuple(" []", [0, 10, 20]));
903 assert(+s1[] == tuple("+[]"));
904 assert(-s1[10] == tuple("-[]", 10));
905 assert(*s1[10, 20] == tuple("*[]", 10, 20));
906 assert(~s1[10..20] == tuple("~[]", [0, 10, 20]));
907 assert((s1[] ="x") == tuple("[] =", "x"));
908 assert((s1[10] ="x") == tuple("[] =", "x", 10));
909 assert((s1[10, 20] ="x") == tuple("[] =", "x", 10, 20));
910 assert((s1[10..20] ="x") == tuple("[] =", "x", [0, 10, 20]));
911 assert((s1[] +="x") == tuple("[]+=", "x"));
912 assert((s1[10] -="x") == tuple("[]-=", "x", 10));
913 assert((s1[10, 20]*="x") == tuple("[]*=", "x", 10, 20));
914 assert((s1[10..20]~="x") == tuple("[]~=", "x", [0, 10, 20]));
915 assert( s1[20..30, 10] == tuple(" []", [0, 20, 30], 10));
916 assert( s1[10, 10..$, $-4, $..2] == tuple(" []", 10, [1,10,99], 99-4, [3,99,2]));
917 assert(+s1[20..30, 10] == tuple("+[]", [0, 20, 30], 10));
918 assert(-s1[10, 10..$, $-4, $..2] == tuple("-[]", 10, [1,10,99], 99-4, [3,99,2]));
919 assert((s1[20..30, 10] ="x") == tuple("[] =", "x", [0, 20, 30], 10));
920 assert((s1[10, 10..$, $-4, $..2] ="x") == tuple("[] =", "x", 10, [1,10,99], 99-4, [3,99,2]));
921 assert((s1[20..30, 10] +="x") == tuple("[]+=", "x", [0, 20, 30], 10));
922 assert((s1[10, 10..$, $-4, $..2]-="x") == tuple("[]-=", "x", 10, [1,10,99], 99-4, [3,99,2]));
923
924 // opIndex exist, but opSlice for multi-dimensional doesn't.
925 static struct S2
926 {
927 auto opSlice(size_t dim)() { return [dim]; }
928 auto opSlice()(size_t lwr, size_t upr) { return [lwr, upr]; }
929
930 auto opIndex(A...)(A indices){ return [[indices]]; }
931 }
932 S2 s2;
933 assert(s2[] == [[]]);
934 assert(s2[1] == [[1]]);
935 assert(s2[1, 2] == [[1, 2]]);
936 assert(s2[1..2] == [1, 2]);
937 static assert(!__traits(compiles, s2[1, 2..3] ));
938 static assert(!__traits(compiles, s2[1..2, 2..3] ));
939
940 // opSlice for multi-dimensional exists, but opIndex for that doesn't.
941 static struct S3
942 {
943 auto opSlice(size_t dim)(size_t lwr, size_t upr) { return [lwr, upr]; }
944
945 auto opIndex(size_t n){ return [[n]]; }
946 auto opIndex(size_t n, size_t m){ return [[n, m]]; }
947 }
948 S3 s3;
949 static assert(!__traits(compiles, s3[] ));
950 assert(s3[1] == [[1]]);
951 assert(s3[1, 2] == [[1, 2]]);
952 static assert(!__traits(compiles, s3[1..2] ));
953 static assert(!__traits(compiles, s3[1, 2..3] ));
954 static assert(!__traits(compiles, s3[1..2, 2..3] ));
955
956 return 0;
957 }
958
test6798b()959 int test6798b()
960 {
961 static struct Typedef(T)
962 {
963 private T Typedef_payload = T.init;
964
965 alias a = Typedef_payload;
966
967 auto ref opIndex(this X, D...)(auto ref D i) { return a[i]; }
968 auto ref opSlice(this X )() { return a[]; }
969 auto ref opSlice(this X, B, E)(auto ref B b, auto ref E e)
970 {
971 assert(b == 0 && e == 3);
972 return a[b..e];
973 }
974
975 template opDispatch(string name)
976 {
977 // field or property function
978 @property auto ref opDispatch(this X)() { return mixin("a."~name); }
979 @property auto ref opDispatch(this X, V)(auto ref V v) { return mixin("a."~name~" = v"); }
980 }
981
982 static if (is(typeof(a) : E[], E))
983 {
984 auto opDollar() const { return a.length; }
985 }
986 }
987
988 Typedef!(int[]) dollar2;
989 dollar2.length = 3;
990 assert(dollar2.Typedef_payload.length == 3);
991 assert(dollar2[0 .. $] is dollar2[0 .. 3]);
992
993 return 0;
994 }
995
test6798c()996 int test6798c()
997 {
998 alias T = Tuple6798!(int, int);
999 auto n = T[].init;
1000 static assert(is(typeof(n[0]) == Tuple6798!(int, int)));
1001
1002 return 0;
1003 }
1004
test6798()1005 void test6798()
1006 {
1007 static assert(test6798a() == 0); // CTFE check
1008 test6798a();
1009 static assert(test6798b() == 0);
1010 test6798b();
1011 static assert(test6798c() == 0);
1012 test6798c();
1013 }
1014
1015 /**************************************/
1016 // 12382
1017
1018 struct S12382
1019 {
opDollarS123821020 size_t opDollar() { return 0; }
opIndexS123821021 size_t opIndex(size_t) { return 0; }
1022 }
1023
func12382()1024 S12382 func12382() { return S12382(); }
1025
1026 static assert(S12382.init[$] == 0);
1027 static assert(func12382()[$] == 0);
1028 enum e12382a = S12382.init[$];
1029 enum e12382b = func12382()[$];
1030 static v12382a = S12382.init[$];
1031 static v12382b = func12382()[$];
1032
test12382()1033 void test12382()
1034 {
1035 static assert(S12382.init[$] == 0);
1036 static assert(func12382()[$] == 0);
1037 enum e12382a = S12382.init[$];
1038 enum e12382b = func12382()[$];
1039 static v12382a = S12382.init[$];
1040 static v12382b = func12382()[$];
1041 }
1042
1043 /**************************************/
1044 // 12904
1045
1046 struct S12904
1047 {
opIndexAssignS129041048 void opIndexAssign(U, A...)(U value, A args)
1049 {
1050 static assert(0);
1051 }
opSliceAssignS129041052 void opSliceAssign(int n)
1053 {
1054 assert(n == 10);
1055 }
1056
opDollarS129041057 size_t opDollar(size_t dim)()
1058 {
1059 return 7;
1060 }
1061
opSliceS129041062 int opSlice(size_t dim)(size_t, size_t to)
1063 {
1064 assert(to == 7);
1065 return 1;
1066 }
1067
opIndexS129041068 int opIndex(int i1, int i2)
1069 {
1070 assert(i1 == 1 && i2 == 1);
1071 return 10;
1072 }
1073 }
1074
test12904()1075 void test12904()
1076 {
1077 S12904 s;
1078 s[] = s[0..$, 1];
1079 s[] = s[0..$, 0..$];
1080 }
1081
1082 /**************************************/
1083 // 7641
1084
Proxy7641(alias a)1085 mixin template Proxy7641(alias a)
1086 {
1087 auto ref opBinaryRight(string op, B)(auto ref B b)
1088 {
1089 return mixin("b "~op~" a");
1090 }
1091 }
Typedef7641(T)1092 struct Typedef7641(T)
1093 {
1094 private T Typedef_payload;
1095
1096 this(T init)
1097 {
1098 Typedef_payload = init;
1099 }
1100
1101 mixin Proxy7641!Typedef_payload;
1102 }
1103
test7641()1104 void test7641()
1105 {
1106 class C {}
1107 C c1 = new C();
1108 auto a = Typedef7641!C(c1);
1109 static assert(!__traits(compiles, { C c2 = a; }));
1110 }
1111
1112 /**************************************/
1113 // 8434
1114
test8434()1115 void test8434()
1116 {
1117 static class Vector2D(T)
1118 {
1119 T x, y;
1120
1121 this(T x, T y) {
1122 this.x = x;
1123 this.y = y;
1124 }
1125
1126 U opCast(U)() const { assert(0); }
1127 }
1128
1129 alias Vector2D!(short) Vector2s;
1130 alias Vector2D!(float) Vector2f;
1131
1132 Vector2s vs1 = new Vector2s(42, 23);
1133 Vector2s vs2 = new Vector2s(42, 23);
1134
1135 assert(vs1 != vs2);
1136 }
1137
1138 /**************************************/
1139
test18()1140 void test18()
1141 {
1142 // one dimensional indexing
1143 static struct IndexExp
1144 {
1145 int[] opIndex(int a)
1146 {
1147 return [a];
1148 }
1149
1150 int[] opIndexUnary(string op)(int a)
1151 {
1152 return [a];
1153 }
1154
1155 int[] opIndexAssign(int val, int a)
1156 {
1157 return [val, a];
1158 }
1159
1160 int[] opIndexOpAssign(string op)(int val, int a)
1161 {
1162 return [val, a];
1163 }
1164
1165 int opDollar()
1166 {
1167 return 8;
1168 }
1169 }
1170
1171 IndexExp index;
1172 // opIndex
1173 assert(index[8] == [8]);
1174 assert(index[$] == [8]);
1175 assert(index[$-1] == [7]);
1176 assert(index[$-$/2] == [4]);
1177 // opIndexUnary
1178 assert(-index[8] == [8]);
1179 assert(-index[$] == [8]);
1180 assert(-index[$-1] == [7]);
1181 assert(-index[$-$/2] == [4]);
1182 // opIndexAssign
1183 assert((index[8] = 2) == [2, 8]);
1184 assert((index[$] = 2) == [2, 8]);
1185 assert((index[$-1] = 2) == [2, 7]);
1186 assert((index[$-$/2] = 2) == [2, 4]);
1187 // opIndexOpAssign
1188 assert((index[8] += 2) == [2, 8]);
1189 assert((index[$] += 2) == [2, 8]);
1190 assert((index[$-1] += 2) == [2, 7]);
1191 assert((index[$-$/2] += 2) == [2, 4]);
1192
1193 // opDollar is only one-dimensional
1194 static assert(!is(typeof(index[$, $])));
1195 static assert(!is(typeof(-index[$, $])));
1196 static assert(!is(typeof(index[$, $] = 2)));
1197 static assert(!is(typeof(index[$, $] += 2)));
1198
1199 // multi dimensional indexing
1200 static struct ArrayExp
1201 {
1202 int[] opIndex(int a, int b)
1203 {
1204 return [a, b];
1205 }
1206
1207 int[] opIndexUnary(string op)(int a, int b)
1208 {
1209 return [a, b];
1210 }
1211
1212 int[] opIndexAssign(int val, int a, int b)
1213 {
1214 return [val, a, b];
1215 }
1216
1217 int[] opIndexOpAssign(string op)(int val, int a, int b)
1218 {
1219 return [val, a, b];
1220 }
1221
1222 int opDollar(int dim)()
1223 {
1224 return dim;
1225 }
1226 }
1227
1228 ArrayExp array;
1229 // opIndex
1230 assert(array[8, 8] == [8, 8]);
1231 assert(array[$, $] == [0, 1]);
1232 assert(array[$, $-1] == [0, 0]);
1233 assert(array[2, $-$/2] == [2, 1]);
1234 // opIndexUnary
1235 assert(-array[8, 8] == [8, 8]);
1236 assert(-array[$, $] == [0, 1]);
1237 assert(-array[$, $-1] == [0, 0]);
1238 assert(-array[2, $-$/2] == [2, 1]);
1239 // opIndexAssign
1240 assert((array[8, 8] = 2) == [2, 8, 8]);
1241 assert((array[$, $] = 2) == [2, 0, 1]);
1242 assert((array[$, $-1] = 2) == [2, 0, 0]);
1243 assert((array[2, $-$/2] = 2) == [2, 2, 1]);
1244 // opIndexOpAssign
1245 assert((array[8, 8] += 2) == [2, 8, 8]);
1246 assert((array[$, $] += 2) == [2, 0, 1]);
1247 assert((array[$, $-1] += 2) == [2, 0, 0]);
1248 assert((array[2, $-$/2] += 2) == [2, 2, 1]);
1249
1250 // one dimensional slicing
1251 static struct SliceExp
1252 {
1253 int[] opSlice(int a, int b)
1254 {
1255 return [a, b];
1256 }
1257
1258 int[] opSliceUnary(string op)(int a, int b)
1259 {
1260 return [a, b];
1261 }
1262
1263 int[] opSliceAssign(int val, int a, int b)
1264 {
1265 return [val, a, b];
1266 }
1267
1268 int[] opSliceOpAssign(string op)(int val, int a, int b)
1269 {
1270 return [val, a, b];
1271 }
1272
1273 int opDollar()
1274 {
1275 return 8;
1276 }
1277 }
1278
1279 SliceExp slice;
1280 // opSlice
1281 assert(slice[0 .. 8] == [0, 8]);
1282 assert(slice[0 .. $] == [0, 8]);
1283 assert(slice[0 .. $-1] == [0, 7]);
1284 assert(slice[$-3 .. $-1] == [5, 7]);
1285 // opSliceUnary
1286 assert(-slice[0 .. 8] == [0, 8]);
1287 assert(-slice[0 .. $] == [0, 8]);
1288 assert(-slice[0 .. $-1] == [0, 7]);
1289 assert(-slice[$-3 .. $-1] == [5, 7]);
1290 // opSliceAssign
1291 assert((slice[0 .. 8] = 2) == [2, 0, 8]);
1292 assert((slice[0 .. $] = 2) == [2, 0, 8]);
1293 assert((slice[0 .. $-1] = 2) == [2, 0, 7]);
1294 assert((slice[$-3 .. $-1] = 2) == [2, 5, 7]);
1295 // opSliceOpAssign
1296 assert((slice[0 .. 8] += 2) == [2, 0, 8]);
1297 assert((slice[0 .. $] += 2) == [2, 0, 8]);
1298 assert((slice[0 .. $-1] += 2) == [2, 0, 7]);
1299 assert((slice[$-3 .. $-1] += 2) == [2, 5, 7]);
1300
1301 // test different kinds of opDollar
1302 auto dollar(string opDollar)()
1303 {
1304 static struct Dollar
1305 {
1306 size_t opIndex(size_t a) { return a; }
1307 mixin(opDollar);
1308 }
1309 Dollar d;
1310 return d[$];
1311 }
1312 assert(dollar!q{@property size_t opDollar() { return 8; }}() == 8);
1313 assert(dollar!q{template opDollar(size_t dim) { enum opDollar = dim; }}() == 0);
1314 assert(dollar!q{static const size_t opDollar = 8;}() == 8);
1315 assert(dollar!q{enum opDollar = 8;}() == 8);
1316 assert(dollar!q{size_t length() { return 8; } alias length opDollar;}() == 8);
1317 }
1318
1319 /**************************************/
1320
test19()1321 void test19()
1322 {
1323 static struct Foo
1324 {
1325 int[] opSlice(int a, int b)
1326 {
1327 return [a, b];
1328 }
1329
1330 int opDollar(int dim)()
1331 {
1332 return dim;
1333 }
1334 }
1335
1336 Foo foo;
1337 assert(foo[0 .. $] == [0, 0]);
1338 }
1339
1340 /**************************************/
1341 // 9453
1342
1343 struct Foo9453
1344 {
1345 static int ctor = 0;
1346
thisFoo94531347 this(string bar) { ++ctor; }
1348
opIndexFoo94531349 void opIndex(size_t i) const {}
opSliceFoo94531350 void opSlice(size_t s, size_t e) const {}
1351
1352 size_t opDollar(int dim)() const if (dim == 0) { return 1; }
1353 }
1354
test9453()1355 void test9453()
1356 {
1357 assert(Foo9453.ctor == 0); Foo9453("bar")[$-1];
1358 assert(Foo9453.ctor == 1); Foo9453("bar")[0..$];
1359 assert(Foo9453.ctor == 2);
1360 }
1361
1362 /**************************************/
1363 // 9496
1364
1365 struct S9496
1366 {
1367 static S9496* ptr;
1368
opDollarS94961369 size_t opDollar()
1370 {
1371 assert(ptr is &this);
1372 return 10;
1373 }
opSliceS94961374 void opSlice(size_t , size_t)
1375 {
1376 assert(ptr is &this);
1377 }
getSliceS94961378 void getSlice()
1379 {
1380 assert(ptr is &this);
1381 this[1 .. opDollar()];
1382 this[1 .. $];
1383 }
1384 }
1385
test9496()1386 void test9496()
1387 {
1388 S9496 s;
1389 S9496.ptr = &s;
1390 s.getSlice();
1391 s[1 .. $];
1392 }
1393
1394 /**************************************/
1395 // 9689
1396
B9689(T)1397 struct B9689(T)
1398 {
1399 T val;
1400 @disable this(this);
1401
1402 bool opEquals(this X, B)(auto ref B b)
1403 {
1404 //pragma(msg, "+", X, ", B = ", B, ", ref = ", __traits(isRef, b));
1405 return this.val == b.val;
1406 //pragma(msg, "-", X, ", B = ", B, ", ref = ", __traits(isRef, b));
1407 }
1408 }
1409
1410 struct S9689
1411 {
1412 B9689!int num;
1413 }
1414
test9689()1415 void test9689()
1416 {
1417 B9689!S9689 b;
1418 }
1419
1420 /**************************************/
1421 // 9694
1422
1423 struct S9694
1424 {
opEqualsS96941425 bool opEquals(ref S9694 rhs)
1426 {
1427 assert(0);
1428 }
1429 }
1430 struct T9694
1431 {
1432 S9694 s;
1433 }
test9694()1434 void test9694()
1435 {
1436 T9694 t;
1437 assert(thrown!Error(typeid(T9694).equals(&t, &t)));
1438 }
1439
1440 /**************************************/
1441 // 10064
1442
test10064()1443 void test10064()
1444 {
1445 static struct S
1446 {
1447 int x = 3;
1448
1449 @disable this();
1450
1451 this(int)
1452 { x = 7; }
1453
1454 int opSlice(size_t, size_t)
1455 { return 0; }
1456
1457 @property size_t opDollar()
1458 {
1459 assert(x == 7 || x == 3); // fails
1460 assert(x == 7);
1461 return 0;
1462 }
1463 }
1464 auto x = S(0)[0 .. $];
1465 }
1466
1467 /**************************************/
1468 // 12585
1469
test12585()1470 void test12585()
1471 {
1472 struct Bar
1473 {
1474 int opIndex(size_t index)
1475 {
1476 return 0;
1477 }
1478 }
1479
1480 struct Foo
1481 {
1482 Bar opIndex(size_t index)
1483 {
1484 throw new Exception("Fail");
1485 }
1486 }
1487
1488 Foo foo()
1489 {
1490 return Foo();
1491 }
1492
1493 void catchStuff(E)(lazy E expression)
1494 {
1495 try
1496 expression();
1497 catch (Exception e) {}
1498 }
1499
1500 catchStuff(foo()[0][0]); // OK <- NG
1501 catchStuff(foo().opIndex(0)[0]); // OK
1502 catchStuff(foo()[0].opIndex(0)); // OK
1503 Foo f; catchStuff(f[0][0]); // OK
1504 }
1505
1506 /**************************************/
1507 // 10394
1508
test10394()1509 void test10394()
1510 {
1511 alias Seq!(int, int) Pair;
1512 Pair pair;
1513
1514 struct S1
1515 {
1516 int opBinary(string op)(Pair) { return 1; }
1517 bool opEquals(Pair) { return true; }
1518 int opOpAssign(string op)(Pair) { return 1; }
1519 }
1520 S1 s1;
1521 assert((s1 + pair) == 1);
1522 assert((s1 == pair) == true);
1523 assert((s1 *= pair) == 1);
1524
1525 struct S2
1526 {
1527 int opBinaryRight(string op)(Pair lhs) { return 1; }
1528 int opCmp(Pair) { return -1; }
1529 }
1530 S2 s2;
1531 assert((pair in s2) == 1);
1532 assert(s2 < pair);
1533 }
1534
1535 /**************************************/
1536 // 10597
1537
1538 struct R10597
1539 {
opIndexR105971540 void opIndex(int) {}
opSliceR105971541 void opSlice(int, int) {}
1542 int opDollar();
1543 }
1544 R10597 r;
1545
1546 struct S10597
1547 {
1548 static assert(is(typeof(r[0]))); //ok
1549 static assert(is(typeof(r[$]))); //fails
1550
1551 static assert(is(typeof(r[0..0]))); //ok
1552 static assert(is(typeof(r[$..$]))); //fails
1553
fooS105971554 void foo()
1555 {
1556 static assert(is(typeof(r[0]))); //ok
1557 static assert(is(typeof(r[$]))); //ok
1558
1559 static assert(is(typeof(r[0..0]))); //ok
1560 static assert(is(typeof(r[$..$]))); //ok
1561 }
1562 }
1563
1564 static assert(is(typeof(r[0]))); //ok
1565 static assert(is(typeof(r[$]))); //fails
1566
1567 static assert(is(typeof(r[0..0]))); //ok
1568 static assert(is(typeof(r[$..$]))); //fails
1569
test10597()1570 void test10597()
1571 {
1572 static assert(is(typeof(r[0]))); //ok
1573 static assert(is(typeof(r[$]))); //ok
1574
1575 static assert(is(typeof(r[0..0]))); //ok
1576 static assert(is(typeof(r[$..$]))); //ok
1577 }
1578
1579 /**************************************/
1580 // 10567
1581
1582 // doesn't require thunk
opCmpS10567x1n1583 struct S10567x1n { int value; int opCmp(ref const S10567x1n rhs) const { return 0; } }
1584
1585 // requires thunk
opCmp(const S10567y1n rhs)1586 struct S10567y1n { int value; int opCmp(const S10567y1n rhs) const { return 0; } }
opCmpS10567y1t1587 struct S10567y1t { int value; int opCmp(S)(const S rhs) const { return 0; } }
1588
1589 // doesn't support const comparison
opCmp(const S10567z1n rhs)1590 struct S10567z1n { int value; int opCmp(const S10567z1n rhs) { return 0; } }
opCmpS10567z1t1591 struct S10567z1t { int value; int opCmp(S)(const S rhs) { return 0; } }
1592
1593 /+
1594 struct S10567x2n { S10567x1n s; this(int n) { s = typeof(s)(n); } alias s this; }
1595
1596 struct S10567y2n { S10567y1n s; this(int n) { s = typeof(s)(n); } alias s this; }
1597 struct S10567y2t { S10567y1t s; this(int n) { s = typeof(s)(n); } alias s this; }
1598
1599 struct S10567z2n { S10567z1n s; this(int n) { s = typeof(s)(n); } alias s this; }
1600 struct S10567z2t { S10567z1t s; this(int n) { s = typeof(s)(n); } alias s this; }
1601
1602 struct S10567d1
1603 {
1604 int value;
1605 int opDispatch(string name, S)(const S rhs) const if (name == "opCmp")
1606 { assert(0); }
1607 }
1608 struct S10567d2
1609 {
1610 int value;
1611 template opDispatch(string name) if (name == "opCmp")
1612 {
1613 int opDispatch(const S rhs) const
1614 { assert(0); }
1615 }
1616 }
1617
1618 // recursive alias this + opCmp searching
1619 struct S10567r1
1620 {
1621 static S10567r2 t;
1622 ref S10567r2 payload() { return t; }
1623 alias payload this;
1624
1625 int opCmp(const S10567r1 s) const { return 0; }
1626 }
1627 struct S10567r2
1628 {
1629 static S10567r1 s;
1630 ref S10567r1 payload() { return s; }
1631 alias payload this;
1632 }
1633 +/
1634
test10567()1635 void test10567()
1636 {
1637 foreach (S; Seq!(S10567x1n/+, S10567x2n+/))
1638 {
1639 S sx = S(1);
1640 S sy = S(2);
1641 assert(!(sx < sy) && !(sx > sy));
1642 assert(sx.opCmp(sy) == 0);
1643
1644 assert(typeid(S).compare(&sx, &sy) == 0);
1645 static if (is(S == S10567x1n))
1646 assert(cast(void*)typeid(S).xopCmp == cast(void*)&S.opCmp, S.stringof);
1647 }
1648
1649 foreach (S; Seq!(S10567y1n, S10567y1t/+, S10567y2n, S10567y2t+/))
1650 {
1651 S sx = S(1);
1652 S sy = S(2);
1653 assert(!(sx < sy) && !(sx > sy));
1654 assert(sx.opCmp(sy) == 0);
1655
1656 assert(typeid(S).compare(&sx, &sy) == 0);
1657 }
1658
1659 foreach (S; Seq!(S10567z1n, S10567z1t/+, S10567z2n, S10567z2t+/))
1660 {
1661 S sx = S(1);
1662 S sy = S(2);
1663 assert(!(sx < sy) && !(sx > sy));
1664 assert(sx.opCmp(sy) == 0);
1665
1666 try
1667 {
1668 auto x = typeid(S).compare(&sx, &sy);
1669 assert(0);
1670 }
1671 catch (Error e) { assert(e.msg[$-15 .. $] == "not implemented"); }
1672 }
1673 /+
1674 foreach (S; Seq!(S10567d1, S10567d2))
1675 {
1676 int[S] aa;
1677 aa[S(1)] = 10; aa[S(1)] = 1;
1678 aa[S(2)] = 20; aa[S(2)] = 2;
1679 assert(aa.length == 2);
1680 foreach (k, v; aa)
1681 assert(k.value == v);
1682
1683 S sx = S(1);
1684 S sy = S(2);
1685
1686 // Don't invoke opDispatch!"opCmp"
1687 assert(typeid(S).compare(&sx, &sy) != 0);
1688 }
1689 +/
1690 }
1691
1692 /**************************************/
1693 // 11062
1694
1695 struct S11062ia
1696 {
1697 struct S1
1698 {
opIndexAssignS11062ia::S11699 void opIndexAssign(int val, int key) {}
1700 }
1701 struct S2
1702 {
1703 S1 headers;
1704 }
1705
1706 private S2 m_obj;
getS11062ia1707 @property S2 get() { return m_obj; }
1708 alias get this;
1709 }
1710
1711 struct S11062sa
1712 {
1713 struct S1
1714 {
opSliceAssignS11715 void opSliceAssign(int val, int lwr, int upr) {}
1716 }
1717 struct S2
1718 {
1719 S1 headers;
1720 }
1721
1722 private S2 m_obj;
get()1723 @property S2 get() { return m_obj; }
1724 alias get this;
1725 }
1726
test11062()1727 void test11062()
1728 {
1729 auto sia = S11062ia();
1730 sia.headers[1] = 1; // bug
1731
1732 auto ssa = S11062sa();
1733 ssa.headers[1..2] = 1; // bug
1734 }
1735
1736 /**************************************/
1737 // 11311
1738
test11311()1739 void test11311()
1740 {
1741 static int ctor, cpctor, dtor;
1742
1743 static struct S
1744 {
1745 this(int) { ++ctor; }
1746 this(this) { ++cpctor; }
1747 ~this() { ++dtor; }
1748 }
1749 static struct Arr
1750 {
1751 S data;
1752 ref S opIndex(int) return { return data; }
1753 ref S opSlice(int, int) return { return data; }
1754 }
1755
1756 {
1757 Arr a = Arr(S(1));
1758 assert(ctor == 1);
1759 assert(cpctor == 0);
1760 assert(dtor == 0);
1761
1762 auto getA1() { return a; }
1763 //getA1().opIndex(1); // OK
1764 getA1()[1]; // NG
1765
1766 assert(ctor == 1);
1767 assert(cpctor == 1); // getA() returns a copy of a
1768 assert(dtor == 1); // temporary returned by getA() should be destroyed
1769 }
1770 assert(dtor == 2);
1771 assert(ctor + cpctor == dtor);
1772
1773 ctor = cpctor = dtor = 0;
1774
1775 {
1776 Arr a = Arr(S(1));
1777 assert(ctor == 1);
1778 assert(cpctor == 0);
1779 assert(dtor == 0);
1780
1781 auto getA2() { return a; }
1782 //getA2().opSlice(1, 2); // OK
1783 getA2()[1..2]; // NG
1784
1785 assert(ctor == 1);
1786 assert(cpctor == 1); // getA() returns a copy of a
1787 assert(dtor == 1); // temporary returned by getA() should be destroyed
1788 }
1789 assert(dtor == 2);
1790 assert(ctor + cpctor == dtor);
1791 }
1792
1793 /**************************************/
1794 // 12193
1795
1796 void test12193()
1797 {
1798 struct Foo
1799 {
1800 bool bar;
1801 alias bar this;
1802 void opOpAssign(string op)(size_t x)
1803 {
1804 bar = false;
1805 }
1806 }
1807
1808 Foo foo;
1809 foo <<= 1;
1810 }
1811
1812 /**************************************/
1813 // 14057
1814
1815 struct W14057
1816 {
1817 int[] subType;
1818 alias subType this;
1819
1820 W14057 opSlice(size_t, size_t)
1821 {
1822 return this;
1823 }
1824 }
1825
1826 void test14057()
1827 {
1828 auto w = W14057();
1829 W14057 w2 = w[0 .. 1337];
1830 }
1831
1832 /**************************************/
1833
1834 struct Tuple20(T...) { T field; alias field this; }
1835
1836 void test20a()
1837 {
1838 // ae1save in in AssignExp::semantic
1839 int a, b;
1840
1841 struct A1
1842 {
1843 void opIndexAssign(int v, Tuple20!(int, int) ) { a = v; }
1844 Tuple20!(int, int) opSlice(size_t dim)(int, int) { return typeof(return).init; }
1845 }
1846 struct A2
1847 {
1848 A1 a1;
1849 alias a1 this;
1850 int opIndexAssign(int) { return b; }
1851 }
1852
1853 stompStack();
1854 A2 foo() { return A2(); }
1855 foo()[1..2] = 1;
1856 // ref A1 __tmp = foo().a1; __tmp.opIndexAssign(1, __tmp.opSlice!0(1, 2));
1857 assert(a == 1); // should work
1858 assert(b == 0);
1859 }
1860
1861 void test20b()
1862 {
1863 // ae1save in UnaExp::op_overload()
1864 int a, b;
1865
1866 struct A1
1867 {
1868 void opIndexUnary(string op)(Tuple20!(int, int) ) { a = 1; }
1869 Tuple20!(int, int) opSlice(size_t dim)(int, int) { return typeof(return).init; }
1870 void dummy() {} // nessary to make A1 nested struct
1871 }
1872 struct A2
1873 {
1874 A1 a1;
1875 alias a1 this;
1876 int opIndexUnary(string op)(int) { return 0; }
1877 }
1878
1879 stompStack();
1880 A2 foo() { return A2(); }
1881 +foo()[1..2];
1882 // ref A1 __tmp = foo().a1; __tmp.opIndexUnary!"+"(__tmp.opSlice!0(1, 2));
1883 assert(a == 1); // should pass
1884 assert(b == 0);
1885 }
1886
1887 void test20c()
1888 {
1889 // ae1save in ArrayExp::op_overload()
1890 int a, b;
1891
1892 struct A1
1893 {
1894 void opIndex(Tuple20!(int, int) ) { a = 1; }
1895 Tuple20!(int, int) opSlice(size_t dim)(int, int) { return typeof(return).init; }
1896 }
1897 struct A2
1898 {
1899 A1 a1;
1900 alias a1 this;
1901 int opIndex(int) { return 0; }
1902 }
1903
1904 stompStack();
1905 A2 foo() { return A2(); }
1906 foo()[1..2];
1907 // ref A1 __tmp = foo().a1; __tmp.opIndex(__tmp.opSlice!0(1, 2));
1908 assert(a == 1); // should pass
1909 assert(b == 0);
1910 }
1911
1912 void test20d()
1913 {
1914 // ae1save in BinAssignExp::op_overload()
1915 int a, b;
1916
1917 struct A1
1918 {
1919 void opIndexOpAssign(string op)(int v, Tuple20!(int, int) ) { a = v; }
1920 Tuple20!(int, int) opSlice(size_t dim)(int, int) { return typeof(return).init; }
1921 void dummy() {} // nessary to make A1 nested struct
1922 }
1923 struct A2
1924 {
1925 A1 a1;
1926 alias a1 this;
1927 ref int opIndexOpAssign(alias op)(int) { return b; }
1928 }
1929
1930 stompStack();
1931 A2 foo() { return A2(); }
1932 foo()[1..2] += 1;
1933 // ref A1 __tmp = foo().a1; __tmp.opIndexOpAssign!"+"(1, __tmp.opSlice!0(1, 2));
1934 assert(a == 1); // should pass
1935 assert(b == 0);
1936 }
1937
1938 /**************************************/
1939 // 14624
1940
1941 void test14624()
1942 {
1943 struct A1
1944 {
1945 int x;
1946 ref int opIndex() return { return x; }
1947 ref int opSlice() { assert(0); }
1948 }
1949 {
1950 A1 a = A1(1);
1951 auto x = a[]; // a.opIndex()
1952 assert(x == a.x);
1953 auto y = -a[]; // -a.opIndex() <-- not found: a.opIndexUnary!"-"
1954 assert(y == -a.x);
1955 a[] = 1; // a.opIndex() = 1; <-- not found: a.opIndexAssign(int)
1956 assert(a.x == 1);
1957 a[] += 1; // a.opIndex() += 1; <-- not found: a.opIndexOpAssign!"+"(int)
1958 assert(a.x == 2);
1959 }
1960
1961 struct A2
1962 {
1963 int x;
1964 ref int opIndex() return { x = 10; return x; }
1965 ref int opSlice() { assert(0); }
1966 ref int opSliceUnary(alias op)() { x = 11; return x; }
1967 ref int opSliceAssign(int) return { x = 12; return x; }
1968 ref int opSliceOpAssign(alias op)(int) { x = 13; return x; }
1969 }
1970 {
1971 A2 a = A2(1);
1972 auto x = a[]; // a.opIndex()
1973 assert(a.x == 10);
1974 auto y = -a[]; // a.opSliceUnary!"-"() is preferred than: -a.opIndex()
1975 assert(a.x == 11);
1976 a[] = 1; // a.opSliceAssign(1) is preferred than: a.opIndex() = 1;
1977 assert(a.x == 12);
1978 a[] += 1; // a.opSliceOpAssign!"+"(1) is preferred than: a.opIndex() += 1;
1979 assert(a.x == 13);
1980 }
1981 }
1982
1983 /**************************************/
1984 // 14625
1985
1986 void test14625()
1987 {
1988 struct R
1989 {
1990 @property bool empty() { return true; }
1991 @property int front() { return 0; }
1992 void popFront() {}
1993 }
1994
1995 struct C1
1996 {
1997 R opIndex() { return R(); }
1998 R opSlice() { assert(0); }
1999 }
2000 C1 c1;
2001 foreach (e; c1) {} // OK <- asserts in opSlice()
2002 foreach (e; c1[]) {} // OK, opIndex()
2003
2004 struct C2
2005 {
2006 R opIndex() { return R(); }
2007 }
2008 C2 c2;
2009 foreach (e; c2) {} // OK <- rejected
2010 foreach (e; c2[]) {} // OK, opIndex()
2011 }
2012
2013 /**************************************/
2014
2015 int main()
2016 {
2017 test1();
2018 test2();
2019 test3();
2020 test4();
2021 test5();
2022 test6();
2023 test7();
2024 test8();
2025 test9();
2026 test10();
2027 test11();
2028 test4099();
2029 test12();
2030 test13();
2031 test14();
2032 test15();
2033 test16();
2034 test17();
2035 test3789();
2036 test10037();
2037 test6798();
2038 test12904();
2039 test7641();
2040 test8434();
2041 test18();
2042 test19();
2043 test9453();
2044 test9496();
2045 test9689();
2046 test9694();
2047 test10064();
2048 test12585();
2049 test10394();
2050 test10567();
2051 test11062();
2052 test11311();
2053 test14057();
2054 test20a();
2055 test20b();
2056 test20c();
2057 test20d();
2058 test14624();
2059 test14625();
2060
2061 printf("Success\n");
2062 return 0;
2063 }
2064
2065