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