| // PERMUTE_ARGS: -inline -O -property |
| // REQUIRED_ARGS: -dip25 |
| |
| // Test operator overloading |
| |
| extern (C) int printf(const(char*) fmt, ...); |
| |
| template Seq(T...){ alias T Seq; } |
| |
| bool thrown(E, T)(lazy T val) |
| { |
| try { val(); return false; } |
| catch (E e) { return true; } |
| } |
| |
| void stompStack() { int[256] sa = 0xdeadbeef; } |
| |
| /**************************************/ |
| |
| class A |
| { |
| string opUnary(string s)() |
| { |
| printf("A.opUnary!(%.*s)\n", s.length, s.ptr); |
| return s; |
| } |
| } |
| |
| void test1() |
| { |
| auto a = new A(); |
| |
| +a; |
| -a; |
| ~a; |
| *a; |
| ++a; |
| --a; |
| |
| auto x = a++; |
| assert(x == a); |
| auto y = a--; |
| assert(y == a); |
| } |
| |
| /**************************************/ |
| |
| class A2 |
| { |
| T opCast(T)() |
| { |
| auto s = T.stringof; |
| printf("A.opCast!(%.*s)\n", s.length, s.ptr); |
| return T.init; |
| } |
| } |
| |
| |
| void test2() |
| { |
| auto a = new A2(); |
| |
| auto x = cast(int)a; |
| assert(x == 0); |
| |
| auto y = cast(char)a; |
| assert(y == char.init); |
| } |
| |
| /**************************************/ |
| |
| struct A3 |
| { |
| int opBinary(string s)(int i) |
| { |
| printf("A.opBinary!(%.*s)\n", s.length, s.ptr); |
| return 0; |
| } |
| |
| int opBinaryRight(string s)(int i) if (s == "/" || s == "*") |
| { |
| printf("A.opBinaryRight!(%.*s)\n", s.length, s.ptr); |
| return 0; |
| } |
| |
| T opCast(T)() |
| { |
| auto s = T.stringof; |
| printf("A.opCast!(%.*s)\n", s.length, s.ptr); |
| return T.init; |
| } |
| } |
| |
| |
| void test3() |
| { |
| A3 a; |
| |
| a + 3; |
| 4 * a; |
| 4 / a; |
| a & 5; |
| } |
| |
| /**************************************/ |
| |
| struct A4 |
| { |
| int opUnary(string s)() |
| { |
| printf("A.opUnary!(%.*s)\n", s.length, s.ptr); |
| return 0; |
| } |
| |
| T opCast(T)() |
| { |
| auto s = T.stringof; |
| printf("A.opCast!(%.*s)\n", s.length, s.ptr); |
| return T.init; |
| } |
| } |
| |
| |
| void test4() |
| { |
| A4 a; |
| |
| if (a) |
| int x = 3; |
| if (!a) |
| int x = 3; |
| if (!!a) |
| int x = 3; |
| } |
| |
| /**************************************/ |
| |
| class A5 |
| { |
| override bool opEquals(Object o) |
| { |
| printf("A.opEquals!(%p)\n", o); |
| return 1; |
| } |
| |
| int opUnary(string s)() |
| { |
| printf("A.opUnary!(%.*s)\n", s.length, s.ptr); |
| return 0; |
| } |
| |
| T opCast(T)() |
| { |
| auto s = T.stringof; |
| printf("A.opCast!(%.*s)\n", s.length, s.ptr); |
| return T.init; |
| } |
| } |
| |
| class B5 : A5 |
| { |
| override bool opEquals(Object o) |
| { |
| printf("B.opEquals!(%p)\n", o); |
| return 1; |
| } |
| } |
| |
| |
| void test5() |
| { |
| A5 a = new A5(); |
| A5 a2 = new A5(); |
| B5 b = new B5(); |
| A n = null; |
| |
| if (a == a) |
| int x = 3; |
| if (a == a2) |
| int x = 3; |
| if (a == b) |
| int x = 3; |
| if (a == n) |
| int x = 3; |
| if (n == a) |
| int x = 3; |
| if (n == n) |
| int x = 3; |
| } |
| |
| /**************************************/ |
| |
| struct S6 |
| { |
| const bool opEquals(ref const S6 b) |
| { |
| printf("S.opEquals(S %p)\n", &b); |
| return true; |
| } |
| |
| const bool opEquals(ref const T6 b) |
| { |
| printf("S.opEquals(T %p)\n", &b); |
| return true; |
| } |
| } |
| |
| struct T6 |
| { |
| const bool opEquals(ref const T6 b) |
| { |
| printf("T.opEquals(T %p)\n", &b); |
| return true; |
| } |
| /+ |
| const bool opEquals(ref const S6 b) |
| { |
| printf("T.opEquals(S %p)\n", &b); |
| return true; |
| } |
| +/ |
| } |
| |
| |
| void test6() |
| { |
| S6 s1; |
| S6 s2; |
| |
| if (s1 == s2) |
| int x = 3; |
| |
| T6 t; |
| |
| if (s1 == t) |
| int x = 3; |
| |
| if (t == s2) |
| int x = 3; |
| } |
| |
| /**************************************/ |
| |
| struct S7 |
| { |
| const int opCmp(ref const S7 b) |
| { |
| printf("S.opCmp(S %p)\n", &b); |
| return -1; |
| } |
| |
| const int opCmp(ref const T7 b) |
| { |
| printf("S.opCmp(T %p)\n", &b); |
| return -1; |
| } |
| } |
| |
| struct T7 |
| { |
| const int opCmp(ref const T7 b) |
| { |
| printf("T.opCmp(T %p)\n", &b); |
| return -1; |
| } |
| /+ |
| const int opCmp(ref const S7 b) |
| { |
| printf("T.opCmp(S %p)\n", &b); |
| return -1; |
| } |
| +/ |
| } |
| |
| |
| void test7() |
| { |
| S7 s1; |
| S7 s2; |
| |
| if (s1 < s2) |
| int x = 3; |
| |
| T7 t; |
| |
| if (s1 < t) |
| int x = 3; |
| |
| if (t < s2) |
| int x = 3; |
| } |
| |
| /**************************************/ |
| |
| struct A8 |
| { |
| int opUnary(string s)() |
| { |
| printf("A.opUnary!(%.*s)\n", s.length, s.ptr); |
| return 0; |
| } |
| |
| int opIndexUnary(string s, T)(T i) |
| { |
| printf("A.opIndexUnary!(%.*s)(%d)\n", s.length, s.ptr, i); |
| return 0; |
| } |
| |
| int opIndexUnary(string s, T)(T i, T j) |
| { |
| printf("A.opIndexUnary!(%.*s)(%d, %d)\n", s.length, s.ptr, i, j); |
| return 0; |
| } |
| |
| int opSliceUnary(string s)() |
| { |
| printf("A.opSliceUnary!(%.*s)()\n", s.length, s.ptr); |
| return 0; |
| } |
| |
| int opSliceUnary(string s, T)(T i, T j) |
| { |
| printf("A.opSliceUnary!(%.*s)(%d, %d)\n", s.length, s.ptr, i, j); |
| return 0; |
| } |
| } |
| |
| |
| void test8() |
| { |
| A8 a; |
| |
| -a; |
| -a[3]; |
| -a[3, 4]; |
| -a[]; |
| -a[5 .. 6]; |
| --a[3]; |
| } |
| |
| /**************************************/ |
| |
| struct A9 |
| { |
| int opOpAssign(string s)(int i) |
| { |
| printf("A.opOpAssign!(%.*s)\n", s.length, s.ptr); |
| return 0; |
| } |
| |
| int opIndexOpAssign(string s, T)(int v, T i) |
| { |
| printf("A.opIndexOpAssign!(%.*s)(%d, %d)\n", s.length, s.ptr, v, i); |
| return 0; |
| } |
| |
| int opIndexOpAssign(string s, T)(int v, T i, T j) |
| { |
| printf("A.opIndexOpAssign!(%.*s)(%d, %d, %d)\n", s.length, s.ptr, v, i, j); |
| return 0; |
| } |
| |
| int opSliceOpAssign(string s)(int v) |
| { |
| printf("A.opSliceOpAssign!(%.*s)(%d)\n", s.length, s.ptr, v); |
| return 0; |
| } |
| |
| int opSliceOpAssign(string s, T)(int v, T i, T j) |
| { |
| printf("A.opSliceOpAssign!(%.*s)(%d, %d, %d)\n", s.length, s.ptr, v, i, j); |
| return 0; |
| } |
| } |
| |
| |
| void test9() |
| { |
| A9 a; |
| |
| a += 8; |
| a -= 8; |
| a *= 8; |
| a /= 8; |
| a %= 8; |
| a &= 8; |
| a |= 8; |
| a ^= 8; |
| a <<= 8; |
| a >>= 8; |
| a >>>= 8; |
| a ~= 8; |
| a ^^= 8; |
| |
| a[3] += 8; |
| a[3] -= 8; |
| a[3] *= 8; |
| a[3] /= 8; |
| a[3] %= 8; |
| a[3] &= 8; |
| a[3] |= 8; |
| a[3] ^= 8; |
| a[3] <<= 8; |
| a[3] >>= 8; |
| a[3] >>>= 8; |
| a[3] ~= 8; |
| a[3] ^^= 8; |
| |
| a[3, 4] += 8; |
| a[] += 8; |
| a[5 .. 6] += 8; |
| } |
| |
| /**************************************/ |
| |
| struct BigInt |
| { |
| int opEquals(T)(T n) const |
| { |
| return 1; |
| } |
| |
| int opEquals(T:int)(T n) const |
| { |
| return 1; |
| } |
| |
| int opEquals(T:const(BigInt))(T n) const |
| { |
| return 1; |
| } |
| |
| } |
| |
| int decimal(BigInt b, const BigInt c) |
| { |
| while (b != c) { |
| } |
| return 1; |
| } |
| |
| /**************************************/ |
| |
| struct Foo10 |
| { |
| int opUnary(string op)() { return 1; } |
| } |
| |
| void test10() |
| { |
| Foo10 foo; |
| foo++; |
| } |
| |
| /**************************************/ |
| |
| struct S4913 |
| { |
| bool opCast(T : bool)() { return true; } |
| } |
| |
| int bug4913() |
| { |
| if (S4913 s = S4913()) { return 83; } |
| return 9; |
| } |
| |
| static assert(bug4913() == 83); |
| |
| /**************************************/ |
| // 5551 |
| |
| struct Foo11 { |
| Foo11 opUnary(string op:"++")() { |
| return this; |
| } |
| Foo11 opBinary(string op)(int y) { |
| return this; |
| } |
| } |
| |
| void test11() |
| { |
| auto f = Foo11(); |
| f++; |
| } |
| |
| /**************************************/ |
| // 4099 |
| |
| struct X4099 |
| { |
| int x; |
| alias x this; |
| |
| typeof(this) opUnary (string operator) () |
| { |
| printf("operator called\n"); |
| return this; |
| } |
| } |
| |
| void test4099() |
| { |
| X4099 x; |
| X4099 r1 = ++x; //operator called |
| X4099 r2 = x++; //BUG! (alias this used. returns int) |
| } |
| |
| /**************************************/ |
| |
| void test12() |
| { |
| static int opeq; |
| |
| // xopEquals OK |
| static struct S1a { const bool opEquals( const typeof(this) rhs) { ++opeq; return false; } } |
| static struct S1b { const bool opEquals(ref const typeof(this) rhs) { ++opeq; return false; } } |
| static struct S1c { const bool opEquals( typeof(this) rhs) { ++opeq; return false; } } |
| |
| // xopEquals NG |
| static struct S2a { bool opEquals( typeof(this) rhs) { ++opeq; return false; } } |
| |
| foreach (S; Seq!(S1a, S1b, S1c)) |
| { |
| S s; |
| opeq = 0; |
| assert(s != s); // call opEquals directly |
| assert(!typeid(S).equals(&s, &s)); // -> xopEquals (-> __xopEquals) -> opEquals |
| assert(opeq == 2); |
| } |
| |
| foreach (S; Seq!(S2a)) |
| { |
| S s; |
| opeq = 0; |
| assert(s != s); |
| assert(thrown!Error(!typeid(S).equals(&s, &s))); |
| // Error("notImplemented") thrown |
| assert(opeq == 1); |
| } |
| } |
| |
| /**************************************/ |
| |
| void test13() |
| { |
| static int opeq; |
| |
| struct X |
| { |
| const bool opEquals(const X){ ++opeq; return false; } |
| } |
| struct S |
| { |
| X x; |
| } |
| |
| S makeS(){ return S(); } |
| |
| S s; |
| opeq = 0; |
| assert(s != s); |
| assert(makeS() != s); |
| assert(s != makeS()); |
| assert(makeS() != makeS()); |
| assert(opeq == 4); |
| |
| // built-in opEquals == const bool opEquals(const S rhs); |
| assert(s != s); |
| assert(opeq == 5); |
| |
| // xopEquals |
| assert(!typeid(S).equals(&s, &s)); |
| assert(opeq == 6); |
| } |
| |
| /**************************************/ |
| |
| void test14() |
| { |
| static int opeq; |
| |
| struct S |
| { |
| const bool opEquals(T)(const T rhs) { ++opeq; return false; } |
| } |
| |
| S makeS(){ return S(); } |
| |
| S s; |
| opeq = 0; |
| assert(s != s); |
| assert(makeS() != s); |
| assert(s != makeS()); |
| assert(makeS() != makeS()); |
| assert(opeq == 4); |
| |
| // xopEquals (-> __xxopEquals) -> template opEquals |
| assert(!typeid(S).equals(&s, &s)); |
| assert(opeq == 5); |
| } |
| |
| /**************************************/ |
| |
| void test15() |
| { |
| struct S |
| { |
| const bool opEquals(T)(const(T) rhs) |
| if (!is(T == S)) |
| { return false; } |
| |
| @disable const bool opEquals(T)(const(T) rhs) |
| if (is(T == S)) |
| { return false; } |
| } |
| |
| S makeS(){ return S(); } |
| |
| S s; |
| static assert(!__traits(compiles, s != s)); |
| static assert(!__traits(compiles, makeS() != s)); |
| static assert(!__traits(compiles, s != makeS())); |
| static assert(!__traits(compiles, makeS() != makeS())); |
| |
| // xopEquals (-> __xxopEquals) -> Error thrown |
| assert(thrown!Error(!typeid(S).equals(&s, &s))); |
| } |
| |
| /**************************************/ |
| |
| void test16() |
| { |
| struct X |
| { |
| int n; |
| const bool opEquals(T)(T t) |
| { |
| return false; |
| } |
| } |
| struct S |
| { |
| X x; |
| } |
| |
| S s1, s2; |
| assert(s1 != s2); |
| // field template opEquals should call |
| } |
| |
| /**************************************/ |
| |
| void test17() |
| { |
| static int opeq = 0; |
| |
| struct S |
| { |
| bool opEquals(ref S rhs) { ++opeq; return false; } |
| } |
| S[] sa1 = new S[3]; |
| S[] sa2 = new S[3]; |
| assert(sa1 != sa2); // isn't used TypeInfo.equals |
| assert(opeq == 1); |
| |
| const(S)[] csa = new const(S)[3]; |
| static assert(!__traits(compiles, csa == sa1)); |
| static assert(!__traits(compiles, sa1 == csa)); |
| static assert(!__traits(compiles, csa == csa)); |
| } |
| |
| /**************************************/ |
| // 3789 |
| |
| bool test3789() |
| { |
| static struct Float |
| { |
| double x; |
| } |
| Float f; |
| assert(f.x != f.x); // NaN != NaN |
| assert(f != f); |
| |
| static struct Array |
| { |
| int[] x; |
| } |
| Array a1 = Array([1,2,3].dup); |
| Array a2 = Array([1,2,3].dup); |
| if (!__ctfe) |
| { // Currently doesn't work this in CTFE - may or may not a bug. |
| assert(a1.x !is a2.x); |
| } |
| assert(a1.x == a2.x); |
| assert(a1 == a2); |
| |
| static struct AA |
| { |
| int[int] x; |
| } |
| AA aa1 = AA([1:1,2:2,3:3]); |
| AA aa2 = AA([1:1,2:2,3:3]); |
| if (!__ctfe) |
| { // Currently doesn't work this in CTFE - may or may not a bug. |
| assert(aa1.x !is aa2.x); |
| } |
| if (!__ctfe) |
| { // This is definitely a bug. Should work in CTFE. |
| assert(aa1.x == aa2.x); |
| assert(aa1 == aa2); |
| } |
| |
| if (!__ctfe) |
| { // Currently union operation is not supported in CTFE. |
| union U1 |
| { |
| double x; |
| } |
| static struct UnionA |
| { |
| int[] a; |
| U1 u; |
| } |
| auto ua1 = UnionA([1,2,3]); |
| auto ua2 = UnionA([1,2,3]); |
| assert(ua1.u.x is ua2.u.x); |
| assert(ua1.u.x != ua2.u.x); |
| assert(ua1 == ua2); |
| ua1.u.x = 1.0; |
| ua2.u.x = 1.0; |
| assert(ua1.u.x is ua2.u.x); |
| assert(ua1.u.x == ua2.u.x); |
| assert(ua1 == ua2); |
| ua1.u.x = double.nan; |
| assert(ua1.u.x !is ua2.u.x); |
| assert(ua1.u.x != ua2.u.x); |
| assert(ua1 != ua2); |
| |
| union U2 |
| { |
| int[] a; |
| } |
| static struct UnionB |
| { |
| double x; |
| U2 u; |
| } |
| auto ub1 = UnionB(1.0); |
| auto ub2 = UnionB(1.0); |
| assert(ub1 == ub2); |
| ub1.u.a = [1,2,3].dup; |
| ub2.u.a = [1,2,3].dup; |
| assert(ub1.u.a !is ub2.u.a); |
| assert(ub1.u.a == ub2.u.a); |
| assert(ub1 != ub2); |
| ub2.u.a = ub1.u.a; |
| assert(ub1.u.a is ub2.u.a); |
| assert(ub1.u.a == ub2.u.a); |
| assert(ub1 == ub2); |
| } |
| |
| if (!__ctfe) |
| { // This is definitely a bug. Should work in CTFE. |
| static struct Class |
| { |
| Object x; |
| } |
| static class X |
| { |
| override bool opEquals(Object o){ return true; } |
| } |
| |
| Class c1a = Class(new Object()); |
| Class c2a = Class(new Object()); |
| assert(c1a.x !is c2a.x); |
| assert(c1a.x != c2a.x); |
| assert(c1a != c2a); // Pass, Object.opEquals works like bitwise compare |
| |
| Class c1b = Class(new X()); |
| Class c2b = Class(new X()); |
| assert(c1b.x !is c2b.x); |
| assert(c1b.x == c2b.x); |
| assert(c1b == c2b); // Fails, should pass |
| } |
| return true; |
| } |
| static assert(test3789()); |
| |
| /**************************************/ |
| // 10037 |
| |
| struct S10037 |
| { |
| bool opEquals(ref const S10037) { assert(0); } |
| } |
| |
| struct T10037 |
| { |
| S10037 s; |
| // Compiler should not generate 'opEquals' here implicitly: |
| } |
| |
| struct Sub10037(TL...) |
| { |
| TL data; |
| int value; |
| alias value this; |
| } |
| |
| void test10037() |
| { |
| S10037 s; |
| T10037 t; |
| static assert( __traits(hasMember, S10037, "opEquals")); |
| static assert(!__traits(hasMember, T10037, "opEquals")); |
| assert(thrown!Error(s == s)); |
| assert(thrown!Error(t == t)); |
| |
| Sub10037!(S10037) lhs; |
| Sub10037!(S10037) rhs; |
| static assert(!__traits(hasMember, Sub10037!(S10037), "opEquals")); |
| assert(lhs == rhs); // lowered to: lhs.value == rhs.value |
| } |
| |
| /**************************************/ |
| // 5810 |
| |
| struct Bug5810 |
| { |
| void opUnary(string op)() {} |
| } |
| |
| struct Foo5810 |
| { |
| Bug5810 x; |
| void bar() { x++; } |
| } |
| |
| /**************************************/ |
| // 6798 |
| |
| struct Tuple6798(T...) |
| { |
| T field; |
| alias field this; |
| |
| bool opEquals(Tuple6798 rhs) |
| { |
| foreach (i, _; T) |
| { |
| if (this[i] != rhs[i]) |
| return false; |
| } |
| return true; |
| } |
| } |
| auto tuple6798(T...)(T args) |
| { |
| return Tuple6798!T(args); |
| } |
| |
| int test6798a() |
| { |
| //import std.typecons; |
| alias tuple6798 tuple; |
| |
| static struct S1 |
| { |
| auto opDollar(size_t dim)() |
| { |
| return 99; |
| } |
| auto opSlice(int dim)(int lwr, int upr) |
| { |
| return [dim, lwr, upr]; |
| } |
| |
| auto opIndex(A...)(A indices) |
| { |
| return tuple(" []", indices); |
| } |
| auto opIndexUnary(string op, A...)(A indices) |
| { |
| return tuple(op~"[]", indices); |
| } |
| auto opIndexAssign(A...)(string s, A indices) |
| { |
| return tuple("[] =", s, indices); |
| } |
| auto opIndexOpAssign(string op, A...)(string s, A indices) |
| { |
| return tuple("[]"~op~"=", s, indices); |
| } |
| } |
| S1 s1; |
| assert( s1[] == tuple(" []")); |
| assert( s1[10] == tuple(" []", 10)); |
| assert( s1[10, 20] == tuple(" []", 10, 20)); |
| assert( s1[10..20] == tuple(" []", [0, 10, 20])); |
| assert(+s1[] == tuple("+[]")); |
| assert(-s1[10] == tuple("-[]", 10)); |
| assert(*s1[10, 20] == tuple("*[]", 10, 20)); |
| assert(~s1[10..20] == tuple("~[]", [0, 10, 20])); |
| assert((s1[] ="x") == tuple("[] =", "x")); |
| assert((s1[10] ="x") == tuple("[] =", "x", 10)); |
| assert((s1[10, 20] ="x") == tuple("[] =", "x", 10, 20)); |
| assert((s1[10..20] ="x") == tuple("[] =", "x", [0, 10, 20])); |
| assert((s1[] +="x") == tuple("[]+=", "x")); |
| assert((s1[10] -="x") == tuple("[]-=", "x", 10)); |
| assert((s1[10, 20]*="x") == tuple("[]*=", "x", 10, 20)); |
| assert((s1[10..20]~="x") == tuple("[]~=", "x", [0, 10, 20])); |
| assert( s1[20..30, 10] == tuple(" []", [0, 20, 30], 10)); |
| assert( s1[10, 10..$, $-4, $..2] == tuple(" []", 10, [1,10,99], 99-4, [3,99,2])); |
| assert(+s1[20..30, 10] == tuple("+[]", [0, 20, 30], 10)); |
| assert(-s1[10, 10..$, $-4, $..2] == tuple("-[]", 10, [1,10,99], 99-4, [3,99,2])); |
| assert((s1[20..30, 10] ="x") == tuple("[] =", "x", [0, 20, 30], 10)); |
| assert((s1[10, 10..$, $-4, $..2] ="x") == tuple("[] =", "x", 10, [1,10,99], 99-4, [3,99,2])); |
| assert((s1[20..30, 10] +="x") == tuple("[]+=", "x", [0, 20, 30], 10)); |
| assert((s1[10, 10..$, $-4, $..2]-="x") == tuple("[]-=", "x", 10, [1,10,99], 99-4, [3,99,2])); |
| |
| // opIndex exist, but opSlice for multi-dimensional doesn't. |
| static struct S2 |
| { |
| auto opSlice(size_t dim)() { return [dim]; } |
| auto opSlice()(size_t lwr, size_t upr) { return [lwr, upr]; } |
| |
| auto opIndex(A...)(A indices){ return [[indices]]; } |
| } |
| S2 s2; |
| assert(s2[] == [[]]); |
| assert(s2[1] == [[1]]); |
| assert(s2[1, 2] == [[1, 2]]); |
| assert(s2[1..2] == [1, 2]); |
| static assert(!__traits(compiles, s2[1, 2..3] )); |
| static assert(!__traits(compiles, s2[1..2, 2..3] )); |
| |
| // opSlice for multi-dimensional exists, but opIndex for that doesn't. |
| static struct S3 |
| { |
| auto opSlice(size_t dim)(size_t lwr, size_t upr) { return [lwr, upr]; } |
| |
| auto opIndex(size_t n){ return [[n]]; } |
| auto opIndex(size_t n, size_t m){ return [[n, m]]; } |
| } |
| S3 s3; |
| static assert(!__traits(compiles, s3[] )); |
| assert(s3[1] == [[1]]); |
| assert(s3[1, 2] == [[1, 2]]); |
| static assert(!__traits(compiles, s3[1..2] )); |
| static assert(!__traits(compiles, s3[1, 2..3] )); |
| static assert(!__traits(compiles, s3[1..2, 2..3] )); |
| |
| return 0; |
| } |
| |
| int test6798b() |
| { |
| static struct Typedef(T) |
| { |
| private T Typedef_payload = T.init; |
| |
| alias a = Typedef_payload; |
| |
| auto ref opIndex(this X, D...)(auto ref D i) { return a[i]; } |
| auto ref opSlice(this X )() { return a[]; } |
| auto ref opSlice(this X, B, E)(auto ref B b, auto ref E e) |
| { |
| assert(b == 0 && e == 3); |
| return a[b..e]; |
| } |
| |
| template opDispatch(string name) |
| { |
| // field or property function |
| @property auto ref opDispatch(this X)() { return mixin("a."~name); } |
| @property auto ref opDispatch(this X, V)(auto ref V v) { return mixin("a."~name~" = v"); } |
| } |
| |
| static if (is(typeof(a) : E[], E)) |
| { |
| auto opDollar() const { return a.length; } |
| } |
| } |
| |
| Typedef!(int[]) dollar2; |
| dollar2.length = 3; |
| assert(dollar2.Typedef_payload.length == 3); |
| assert(dollar2[0 .. $] is dollar2[0 .. 3]); |
| |
| return 0; |
| } |
| |
| int test6798c() |
| { |
| alias T = Tuple6798!(int, int); |
| auto n = T[].init; |
| static assert(is(typeof(n[0]) == Tuple6798!(int, int))); |
| |
| return 0; |
| } |
| |
| void test6798() |
| { |
| static assert(test6798a() == 0); // CTFE check |
| test6798a(); |
| static assert(test6798b() == 0); |
| test6798b(); |
| static assert(test6798c() == 0); |
| test6798c(); |
| } |
| |
| /**************************************/ |
| // 12382 |
| |
| struct S12382 |
| { |
| size_t opDollar() { return 0; } |
| size_t opIndex(size_t) { return 0; } |
| } |
| |
| S12382 func12382() { return S12382(); } |
| |
| static assert(S12382.init[$] == 0); |
| static assert(func12382()[$] == 0); |
| enum e12382a = S12382.init[$]; |
| enum e12382b = func12382()[$]; |
| static v12382a = S12382.init[$]; |
| static v12382b = func12382()[$]; |
| |
| void test12382() |
| { |
| static assert(S12382.init[$] == 0); |
| static assert(func12382()[$] == 0); |
| enum e12382a = S12382.init[$]; |
| enum e12382b = func12382()[$]; |
| static v12382a = S12382.init[$]; |
| static v12382b = func12382()[$]; |
| } |
| |
| /**************************************/ |
| // 12904 |
| |
| struct S12904 |
| { |
| void opIndexAssign(U, A...)(U value, A args) |
| { |
| static assert(0); |
| } |
| void opSliceAssign(int n) |
| { |
| assert(n == 10); |
| } |
| |
| size_t opDollar(size_t dim)() |
| { |
| return 7; |
| } |
| |
| int opSlice(size_t dim)(size_t, size_t to) |
| { |
| assert(to == 7); |
| return 1; |
| } |
| |
| int opIndex(int i1, int i2) |
| { |
| assert(i1 == 1 && i2 == 1); |
| return 10; |
| } |
| } |
| |
| void test12904() |
| { |
| S12904 s; |
| s[] = s[0..$, 1]; |
| s[] = s[0..$, 0..$]; |
| } |
| |
| /**************************************/ |
| // 7641 |
| |
| mixin template Proxy7641(alias a) |
| { |
| auto ref opBinaryRight(string op, B)(auto ref B b) |
| { |
| return mixin("b "~op~" a"); |
| } |
| } |
| struct Typedef7641(T) |
| { |
| private T Typedef_payload; |
| |
| this(T init) |
| { |
| Typedef_payload = init; |
| } |
| |
| mixin Proxy7641!Typedef_payload; |
| } |
| |
| void test7641() |
| { |
| class C {} |
| C c1 = new C(); |
| auto a = Typedef7641!C(c1); |
| static assert(!__traits(compiles, { C c2 = a; })); |
| } |
| |
| /**************************************/ |
| // 8434 |
| |
| void test8434() |
| { |
| static class Vector2D(T) |
| { |
| T x, y; |
| |
| this(T x, T y) { |
| this.x = x; |
| this.y = y; |
| } |
| |
| U opCast(U)() const { assert(0); } |
| } |
| |
| alias Vector2D!(short) Vector2s; |
| alias Vector2D!(float) Vector2f; |
| |
| Vector2s vs1 = new Vector2s(42, 23); |
| Vector2s vs2 = new Vector2s(42, 23); |
| |
| assert(vs1 != vs2); |
| } |
| |
| /**************************************/ |
| |
| void test18() |
| { |
| // one dimensional indexing |
| static struct IndexExp |
| { |
| int[] opIndex(int a) |
| { |
| return [a]; |
| } |
| |
| int[] opIndexUnary(string op)(int a) |
| { |
| return [a]; |
| } |
| |
| int[] opIndexAssign(int val, int a) |
| { |
| return [val, a]; |
| } |
| |
| int[] opIndexOpAssign(string op)(int val, int a) |
| { |
| return [val, a]; |
| } |
| |
| int opDollar() |
| { |
| return 8; |
| } |
| } |
| |
| IndexExp index; |
| // opIndex |
| assert(index[8] == [8]); |
| assert(index[$] == [8]); |
| assert(index[$-1] == [7]); |
| assert(index[$-$/2] == [4]); |
| // opIndexUnary |
| assert(-index[8] == [8]); |
| assert(-index[$] == [8]); |
| assert(-index[$-1] == [7]); |
| assert(-index[$-$/2] == [4]); |
| // opIndexAssign |
| assert((index[8] = 2) == [2, 8]); |
| assert((index[$] = 2) == [2, 8]); |
| assert((index[$-1] = 2) == [2, 7]); |
| assert((index[$-$/2] = 2) == [2, 4]); |
| // opIndexOpAssign |
| assert((index[8] += 2) == [2, 8]); |
| assert((index[$] += 2) == [2, 8]); |
| assert((index[$-1] += 2) == [2, 7]); |
| assert((index[$-$/2] += 2) == [2, 4]); |
| |
| // opDollar is only one-dimensional |
| static assert(!is(typeof(index[$, $]))); |
| static assert(!is(typeof(-index[$, $]))); |
| static assert(!is(typeof(index[$, $] = 2))); |
| static assert(!is(typeof(index[$, $] += 2))); |
| |
| // multi dimensional indexing |
| static struct ArrayExp |
| { |
| int[] opIndex(int a, int b) |
| { |
| return [a, b]; |
| } |
| |
| int[] opIndexUnary(string op)(int a, int b) |
| { |
| return [a, b]; |
| } |
| |
| int[] opIndexAssign(int val, int a, int b) |
| { |
| return [val, a, b]; |
| } |
| |
| int[] opIndexOpAssign(string op)(int val, int a, int b) |
| { |
| return [val, a, b]; |
| } |
| |
| int opDollar(int dim)() |
| { |
| return dim; |
| } |
| } |
| |
| ArrayExp array; |
| // opIndex |
| assert(array[8, 8] == [8, 8]); |
| assert(array[$, $] == [0, 1]); |
| assert(array[$, $-1] == [0, 0]); |
| assert(array[2, $-$/2] == [2, 1]); |
| // opIndexUnary |
| assert(-array[8, 8] == [8, 8]); |
| assert(-array[$, $] == [0, 1]); |
| assert(-array[$, $-1] == [0, 0]); |
| assert(-array[2, $-$/2] == [2, 1]); |
| // opIndexAssign |
| assert((array[8, 8] = 2) == [2, 8, 8]); |
| assert((array[$, $] = 2) == [2, 0, 1]); |
| assert((array[$, $-1] = 2) == [2, 0, 0]); |
| assert((array[2, $-$/2] = 2) == [2, 2, 1]); |
| // opIndexOpAssign |
| assert((array[8, 8] += 2) == [2, 8, 8]); |
| assert((array[$, $] += 2) == [2, 0, 1]); |
| assert((array[$, $-1] += 2) == [2, 0, 0]); |
| assert((array[2, $-$/2] += 2) == [2, 2, 1]); |
| |
| // one dimensional slicing |
| static struct SliceExp |
| { |
| int[] opSlice(int a, int b) |
| { |
| return [a, b]; |
| } |
| |
| int[] opSliceUnary(string op)(int a, int b) |
| { |
| return [a, b]; |
| } |
| |
| int[] opSliceAssign(int val, int a, int b) |
| { |
| return [val, a, b]; |
| } |
| |
| int[] opSliceOpAssign(string op)(int val, int a, int b) |
| { |
| return [val, a, b]; |
| } |
| |
| int opDollar() |
| { |
| return 8; |
| } |
| } |
| |
| SliceExp slice; |
| // opSlice |
| assert(slice[0 .. 8] == [0, 8]); |
| assert(slice[0 .. $] == [0, 8]); |
| assert(slice[0 .. $-1] == [0, 7]); |
| assert(slice[$-3 .. $-1] == [5, 7]); |
| // opSliceUnary |
| assert(-slice[0 .. 8] == [0, 8]); |
| assert(-slice[0 .. $] == [0, 8]); |
| assert(-slice[0 .. $-1] == [0, 7]); |
| assert(-slice[$-3 .. $-1] == [5, 7]); |
| // opSliceAssign |
| assert((slice[0 .. 8] = 2) == [2, 0, 8]); |
| assert((slice[0 .. $] = 2) == [2, 0, 8]); |
| assert((slice[0 .. $-1] = 2) == [2, 0, 7]); |
| assert((slice[$-3 .. $-1] = 2) == [2, 5, 7]); |
| // opSliceOpAssign |
| assert((slice[0 .. 8] += 2) == [2, 0, 8]); |
| assert((slice[0 .. $] += 2) == [2, 0, 8]); |
| assert((slice[0 .. $-1] += 2) == [2, 0, 7]); |
| assert((slice[$-3 .. $-1] += 2) == [2, 5, 7]); |
| |
| // test different kinds of opDollar |
| auto dollar(string opDollar)() |
| { |
| static struct Dollar |
| { |
| size_t opIndex(size_t a) { return a; } |
| mixin(opDollar); |
| } |
| Dollar d; |
| return d[$]; |
| } |
| assert(dollar!q{@property size_t opDollar() { return 8; }}() == 8); |
| assert(dollar!q{template opDollar(size_t dim) { enum opDollar = dim; }}() == 0); |
| assert(dollar!q{static const size_t opDollar = 8;}() == 8); |
| assert(dollar!q{enum opDollar = 8;}() == 8); |
| assert(dollar!q{size_t length() { return 8; } alias length opDollar;}() == 8); |
| } |
| |
| /**************************************/ |
| |
| void test19() |
| { |
| static struct Foo |
| { |
| int[] opSlice(int a, int b) |
| { |
| return [a, b]; |
| } |
| |
| int opDollar(int dim)() |
| { |
| return dim; |
| } |
| } |
| |
| Foo foo; |
| assert(foo[0 .. $] == [0, 0]); |
| } |
| |
| /**************************************/ |
| // 9453 |
| |
| struct Foo9453 |
| { |
| static int ctor = 0; |
| |
| this(string bar) { ++ctor; } |
| |
| void opIndex(size_t i) const {} |
| void opSlice(size_t s, size_t e) const {} |
| |
| size_t opDollar(int dim)() const if (dim == 0) { return 1; } |
| } |
| |
| void test9453() |
| { |
| assert(Foo9453.ctor == 0); Foo9453("bar")[$-1]; |
| assert(Foo9453.ctor == 1); Foo9453("bar")[0..$]; |
| assert(Foo9453.ctor == 2); |
| } |
| |
| /**************************************/ |
| // 9496 |
| |
| struct S9496 |
| { |
| static S9496* ptr; |
| |
| size_t opDollar() |
| { |
| assert(ptr is &this); |
| return 10; |
| } |
| void opSlice(size_t , size_t) |
| { |
| assert(ptr is &this); |
| } |
| void getSlice() |
| { |
| assert(ptr is &this); |
| this[1 .. opDollar()]; |
| this[1 .. $]; |
| } |
| } |
| |
| void test9496() |
| { |
| S9496 s; |
| S9496.ptr = &s; |
| s.getSlice(); |
| s[1 .. $]; |
| } |
| |
| /**************************************/ |
| // 9689 |
| |
| struct B9689(T) |
| { |
| T val; |
| @disable this(this); |
| |
| bool opEquals(this X, B)(auto ref B b) |
| { |
| //pragma(msg, "+", X, ", B = ", B, ", ref = ", __traits(isRef, b)); |
| return this.val == b.val; |
| //pragma(msg, "-", X, ", B = ", B, ", ref = ", __traits(isRef, b)); |
| } |
| } |
| |
| struct S9689 |
| { |
| B9689!int num; |
| } |
| |
| void test9689() |
| { |
| B9689!S9689 b; |
| } |
| |
| /**************************************/ |
| // 9694 |
| |
| struct S9694 |
| { |
| bool opEquals(ref S9694 rhs) |
| { |
| assert(0); |
| } |
| } |
| struct T9694 |
| { |
| S9694 s; |
| } |
| void test9694() |
| { |
| T9694 t; |
| assert(thrown!Error(typeid(T9694).equals(&t, &t))); |
| } |
| |
| /**************************************/ |
| // 10064 |
| |
| void test10064() |
| { |
| static struct S |
| { |
| int x = 3; |
| |
| @disable this(); |
| |
| this(int) |
| { x = 7; } |
| |
| int opSlice(size_t, size_t) |
| { return 0; } |
| |
| @property size_t opDollar() |
| { |
| assert(x == 7 || x == 3); // fails |
| assert(x == 7); |
| return 0; |
| } |
| } |
| auto x = S(0)[0 .. $]; |
| } |
| |
| /**************************************/ |
| // 12585 |
| |
| void test12585() |
| { |
| struct Bar |
| { |
| int opIndex(size_t index) |
| { |
| return 0; |
| } |
| } |
| |
| struct Foo |
| { |
| Bar opIndex(size_t index) |
| { |
| throw new Exception("Fail"); |
| } |
| } |
| |
| Foo foo() |
| { |
| return Foo(); |
| } |
| |
| void catchStuff(E)(lazy E expression) |
| { |
| try |
| expression(); |
| catch (Exception e) {} |
| } |
| |
| catchStuff(foo()[0][0]); // OK <- NG |
| catchStuff(foo().opIndex(0)[0]); // OK |
| catchStuff(foo()[0].opIndex(0)); // OK |
| Foo f; catchStuff(f[0][0]); // OK |
| } |
| |
| /**************************************/ |
| // 10394 |
| |
| void test10394() |
| { |
| alias Seq!(int, int) Pair; |
| Pair pair; |
| |
| struct S1 |
| { |
| int opBinary(string op)(Pair) { return 1; } |
| bool opEquals(Pair) { return true; } |
| int opOpAssign(string op)(Pair) { return 1; } |
| } |
| S1 s1; |
| assert((s1 + pair) == 1); |
| assert((s1 == pair) == true); |
| assert((s1 *= pair) == 1); |
| |
| struct S2 |
| { |
| int opBinaryRight(string op)(Pair lhs) { return 1; } |
| int opCmp(Pair) { return -1; } |
| } |
| S2 s2; |
| assert((pair in s2) == 1); |
| assert(s2 < pair); |
| } |
| |
| /**************************************/ |
| // 10597 |
| |
| struct R10597 |
| { |
| void opIndex(int) {} |
| void opSlice(int, int) {} |
| int opDollar(); |
| } |
| R10597 r; |
| |
| struct S10597 |
| { |
| static assert(is(typeof(r[0]))); //ok |
| static assert(is(typeof(r[$]))); //fails |
| |
| static assert(is(typeof(r[0..0]))); //ok |
| static assert(is(typeof(r[$..$]))); //fails |
| |
| void foo() |
| { |
| static assert(is(typeof(r[0]))); //ok |
| static assert(is(typeof(r[$]))); //ok |
| |
| static assert(is(typeof(r[0..0]))); //ok |
| static assert(is(typeof(r[$..$]))); //ok |
| } |
| } |
| |
| static assert(is(typeof(r[0]))); //ok |
| static assert(is(typeof(r[$]))); //fails |
| |
| static assert(is(typeof(r[0..0]))); //ok |
| static assert(is(typeof(r[$..$]))); //fails |
| |
| void test10597() |
| { |
| static assert(is(typeof(r[0]))); //ok |
| static assert(is(typeof(r[$]))); //ok |
| |
| static assert(is(typeof(r[0..0]))); //ok |
| static assert(is(typeof(r[$..$]))); //ok |
| } |
| |
| /**************************************/ |
| // 10567 |
| |
| // doesn't require thunk |
| struct S10567x1n { int value; int opCmp(ref const S10567x1n rhs) const { return 0; } } |
| |
| // requires thunk |
| struct S10567y1n { int value; int opCmp(const S10567y1n rhs) const { return 0; } } |
| struct S10567y1t { int value; int opCmp(S)(const S rhs) const { return 0; } } |
| |
| // doesn't support const comparison |
| struct S10567z1n { int value; int opCmp(const S10567z1n rhs) { return 0; } } |
| struct S10567z1t { int value; int opCmp(S)(const S rhs) { return 0; } } |
| |
| /+ |
| struct S10567x2n { S10567x1n s; this(int n) { s = typeof(s)(n); } alias s this; } |
| |
| struct S10567y2n { S10567y1n s; this(int n) { s = typeof(s)(n); } alias s this; } |
| struct S10567y2t { S10567y1t s; this(int n) { s = typeof(s)(n); } alias s this; } |
| |
| struct S10567z2n { S10567z1n s; this(int n) { s = typeof(s)(n); } alias s this; } |
| struct S10567z2t { S10567z1t s; this(int n) { s = typeof(s)(n); } alias s this; } |
| |
| struct S10567d1 |
| { |
| int value; |
| int opDispatch(string name, S)(const S rhs) const if (name == "opCmp") |
| { assert(0); } |
| } |
| struct S10567d2 |
| { |
| int value; |
| template opDispatch(string name) if (name == "opCmp") |
| { |
| int opDispatch(const S rhs) const |
| { assert(0); } |
| } |
| } |
| |
| // recursive alias this + opCmp searching |
| struct S10567r1 |
| { |
| static S10567r2 t; |
| ref S10567r2 payload() { return t; } |
| alias payload this; |
| |
| int opCmp(const S10567r1 s) const { return 0; } |
| } |
| struct S10567r2 |
| { |
| static S10567r1 s; |
| ref S10567r1 payload() { return s; } |
| alias payload this; |
| } |
| +/ |
| |
| void test10567() |
| { |
| foreach (S; Seq!(S10567x1n/+, S10567x2n+/)) |
| { |
| S sx = S(1); |
| S sy = S(2); |
| assert(!(sx < sy) && !(sx > sy)); |
| assert(sx.opCmp(sy) == 0); |
| |
| assert(typeid(S).compare(&sx, &sy) == 0); |
| static if (is(S == S10567x1n)) |
| assert(cast(void*)typeid(S).xopCmp == cast(void*)&S.opCmp, S.stringof); |
| } |
| |
| foreach (S; Seq!(S10567y1n, S10567y1t/+, S10567y2n, S10567y2t+/)) |
| { |
| S sx = S(1); |
| S sy = S(2); |
| assert(!(sx < sy) && !(sx > sy)); |
| assert(sx.opCmp(sy) == 0); |
| |
| assert(typeid(S).compare(&sx, &sy) == 0); |
| } |
| |
| foreach (S; Seq!(S10567z1n, S10567z1t/+, S10567z2n, S10567z2t+/)) |
| { |
| S sx = S(1); |
| S sy = S(2); |
| assert(!(sx < sy) && !(sx > sy)); |
| assert(sx.opCmp(sy) == 0); |
| |
| try |
| { |
| auto x = typeid(S).compare(&sx, &sy); |
| assert(0); |
| } |
| catch (Error e) { assert(e.msg[$-15 .. $] == "not implemented"); } |
| } |
| /+ |
| foreach (S; Seq!(S10567d1, S10567d2)) |
| { |
| int[S] aa; |
| aa[S(1)] = 10; aa[S(1)] = 1; |
| aa[S(2)] = 20; aa[S(2)] = 2; |
| assert(aa.length == 2); |
| foreach (k, v; aa) |
| assert(k.value == v); |
| |
| S sx = S(1); |
| S sy = S(2); |
| |
| // Don't invoke opDispatch!"opCmp" |
| assert(typeid(S).compare(&sx, &sy) != 0); |
| } |
| +/ |
| } |
| |
| /**************************************/ |
| // 11062 |
| |
| struct S11062ia |
| { |
| struct S1 |
| { |
| void opIndexAssign(int val, int key) {} |
| } |
| struct S2 |
| { |
| S1 headers; |
| } |
| |
| private S2 m_obj; |
| @property S2 get() { return m_obj; } |
| alias get this; |
| } |
| |
| struct S11062sa |
| { |
| struct S1 |
| { |
| void opSliceAssign(int val, int lwr, int upr) {} |
| } |
| struct S2 |
| { |
| S1 headers; |
| } |
| |
| private S2 m_obj; |
| @property S2 get() { return m_obj; } |
| alias get this; |
| } |
| |
| void test11062() |
| { |
| auto sia = S11062ia(); |
| sia.headers[1] = 1; // bug |
| |
| auto ssa = S11062sa(); |
| ssa.headers[1..2] = 1; // bug |
| } |
| |
| /**************************************/ |
| // 11311 |
| |
| void test11311() |
| { |
| static int ctor, cpctor, dtor; |
| |
| static struct S |
| { |
| this(int) { ++ctor; } |
| this(this) { ++cpctor; } |
| ~this() { ++dtor; } |
| } |
| static struct Arr |
| { |
| S data; |
| ref S opIndex(int) return { return data; } |
| ref S opSlice(int, int) return { return data; } |
| } |
| |
| { |
| Arr a = Arr(S(1)); |
| assert(ctor == 1); |
| assert(cpctor == 0); |
| assert(dtor == 0); |
| |
| auto getA1() { return a; } |
| //getA1().opIndex(1); // OK |
| getA1()[1]; // NG |
| |
| assert(ctor == 1); |
| assert(cpctor == 1); // getA() returns a copy of a |
| assert(dtor == 1); // temporary returned by getA() should be destroyed |
| } |
| assert(dtor == 2); |
| assert(ctor + cpctor == dtor); |
| |
| ctor = cpctor = dtor = 0; |
| |
| { |
| Arr a = Arr(S(1)); |
| assert(ctor == 1); |
| assert(cpctor == 0); |
| assert(dtor == 0); |
| |
| auto getA2() { return a; } |
| //getA2().opSlice(1, 2); // OK |
| getA2()[1..2]; // NG |
| |
| assert(ctor == 1); |
| assert(cpctor == 1); // getA() returns a copy of a |
| assert(dtor == 1); // temporary returned by getA() should be destroyed |
| } |
| assert(dtor == 2); |
| assert(ctor + cpctor == dtor); |
| } |
| |
| /**************************************/ |
| // 12193 |
| |
| void test12193() |
| { |
| struct Foo |
| { |
| bool bar; |
| alias bar this; |
| void opOpAssign(string op)(size_t x) |
| { |
| bar = false; |
| } |
| } |
| |
| Foo foo; |
| foo <<= 1; |
| } |
| |
| /**************************************/ |
| // 14057 |
| |
| struct W14057 |
| { |
| int[] subType; |
| alias subType this; |
| |
| W14057 opSlice(size_t, size_t) |
| { |
| return this; |
| } |
| } |
| |
| void test14057() |
| { |
| auto w = W14057(); |
| W14057 w2 = w[0 .. 1337]; |
| } |
| |
| /**************************************/ |
| |
| struct Tuple20(T...) { T field; alias field this; } |
| |
| void test20a() |
| { |
| // ae1save in in AssignExp::semantic |
| int a, b; |
| |
| struct A1 |
| { |
| void opIndexAssign(int v, Tuple20!(int, int) ) { a = v; } |
| Tuple20!(int, int) opSlice(size_t dim)(int, int) { return typeof(return).init; } |
| } |
| struct A2 |
| { |
| A1 a1; |
| alias a1 this; |
| int opIndexAssign(int) { return b; } |
| } |
| |
| stompStack(); |
| A2 foo() { return A2(); } |
| foo()[1..2] = 1; |
| // ref A1 __tmp = foo().a1; __tmp.opIndexAssign(1, __tmp.opSlice!0(1, 2)); |
| assert(a == 1); // should work |
| assert(b == 0); |
| } |
| |
| void test20b() |
| { |
| // ae1save in UnaExp::op_overload() |
| int a, b; |
| |
| struct A1 |
| { |
| void opIndexUnary(string op)(Tuple20!(int, int) ) { a = 1; } |
| Tuple20!(int, int) opSlice(size_t dim)(int, int) { return typeof(return).init; } |
| void dummy() {} // nessary to make A1 nested struct |
| } |
| struct A2 |
| { |
| A1 a1; |
| alias a1 this; |
| int opIndexUnary(string op)(int) { return 0; } |
| } |
| |
| stompStack(); |
| A2 foo() { return A2(); } |
| +foo()[1..2]; |
| // ref A1 __tmp = foo().a1; __tmp.opIndexUnary!"+"(__tmp.opSlice!0(1, 2)); |
| assert(a == 1); // should pass |
| assert(b == 0); |
| } |
| |
| void test20c() |
| { |
| // ae1save in ArrayExp::op_overload() |
| int a, b; |
| |
| struct A1 |
| { |
| void opIndex(Tuple20!(int, int) ) { a = 1; } |
| Tuple20!(int, int) opSlice(size_t dim)(int, int) { return typeof(return).init; } |
| } |
| struct A2 |
| { |
| A1 a1; |
| alias a1 this; |
| int opIndex(int) { return 0; } |
| } |
| |
| stompStack(); |
| A2 foo() { return A2(); } |
| foo()[1..2]; |
| // ref A1 __tmp = foo().a1; __tmp.opIndex(__tmp.opSlice!0(1, 2)); |
| assert(a == 1); // should pass |
| assert(b == 0); |
| } |
| |
| void test20d() |
| { |
| // ae1save in BinAssignExp::op_overload() |
| int a, b; |
| |
| struct A1 |
| { |
| void opIndexOpAssign(string op)(int v, Tuple20!(int, int) ) { a = v; } |
| Tuple20!(int, int) opSlice(size_t dim)(int, int) { return typeof(return).init; } |
| void dummy() {} // nessary to make A1 nested struct |
| } |
| struct A2 |
| { |
| A1 a1; |
| alias a1 this; |
| ref int opIndexOpAssign(alias op)(int) { return b; } |
| } |
| |
| stompStack(); |
| A2 foo() { return A2(); } |
| foo()[1..2] += 1; |
| // ref A1 __tmp = foo().a1; __tmp.opIndexOpAssign!"+"(1, __tmp.opSlice!0(1, 2)); |
| assert(a == 1); // should pass |
| assert(b == 0); |
| } |
| |
| /**************************************/ |
| // 14624 |
| |
| void test14624() |
| { |
| struct A1 |
| { |
| int x; |
| ref int opIndex() return { return x; } |
| ref int opSlice() { assert(0); } |
| } |
| { |
| A1 a = A1(1); |
| auto x = a[]; // a.opIndex() |
| assert(x == a.x); |
| auto y = -a[]; // -a.opIndex() <-- not found: a.opIndexUnary!"-" |
| assert(y == -a.x); |
| a[] = 1; // a.opIndex() = 1; <-- not found: a.opIndexAssign(int) |
| assert(a.x == 1); |
| a[] += 1; // a.opIndex() += 1; <-- not found: a.opIndexOpAssign!"+"(int) |
| assert(a.x == 2); |
| } |
| |
| struct A2 |
| { |
| int x; |
| ref int opIndex() return { x = 10; return x; } |
| ref int opSlice() { assert(0); } |
| ref int opSliceUnary(alias op)() { x = 11; return x; } |
| ref int opSliceAssign(int) return { x = 12; return x; } |
| ref int opSliceOpAssign(alias op)(int) { x = 13; return x; } |
| } |
| { |
| A2 a = A2(1); |
| auto x = a[]; // a.opIndex() |
| assert(a.x == 10); |
| auto y = -a[]; // a.opSliceUnary!"-"() is preferred than: -a.opIndex() |
| assert(a.x == 11); |
| a[] = 1; // a.opSliceAssign(1) is preferred than: a.opIndex() = 1; |
| assert(a.x == 12); |
| a[] += 1; // a.opSliceOpAssign!"+"(1) is preferred than: a.opIndex() += 1; |
| assert(a.x == 13); |
| } |
| } |
| |
| /**************************************/ |
| // 14625 |
| |
| void test14625() |
| { |
| struct R |
| { |
| @property bool empty() { return true; } |
| @property int front() { return 0; } |
| void popFront() {} |
| } |
| |
| struct C1 |
| { |
| R opIndex() { return R(); } |
| R opSlice() { assert(0); } |
| } |
| C1 c1; |
| foreach (e; c1) {} // OK <- asserts in opSlice() |
| foreach (e; c1[]) {} // OK, opIndex() |
| |
| struct C2 |
| { |
| R opIndex() { return R(); } |
| } |
| C2 c2; |
| foreach (e; c2) {} // OK <- rejected |
| foreach (e; c2[]) {} // OK, opIndex() |
| } |
| |
| /**************************************/ |
| |
| int main() |
| { |
| test1(); |
| test2(); |
| test3(); |
| test4(); |
| test5(); |
| test6(); |
| test7(); |
| test8(); |
| test9(); |
| test10(); |
| test11(); |
| test4099(); |
| test12(); |
| test13(); |
| test14(); |
| test15(); |
| test16(); |
| test17(); |
| test3789(); |
| test10037(); |
| test6798(); |
| test12904(); |
| test7641(); |
| test8434(); |
| test18(); |
| test19(); |
| test9453(); |
| test9496(); |
| test9689(); |
| test9694(); |
| test10064(); |
| test12585(); |
| test10394(); |
| test10567(); |
| test11062(); |
| test11311(); |
| test14057(); |
| test20a(); |
| test20b(); |
| test20c(); |
| test20d(); |
| test14624(); |
| test14625(); |
| |
| printf("Success\n"); |
| return 0; |
| } |
| |