/* TEST_OUTPUT: --- false [] = int [] = string [0] = int [1] = string [] = string [] = int [1] = string [0] = int --- RUN_OUTPUT: --- 1 1.1 ctor cpctor dtor cpctor dtor dtor Success --- */ extern (C) int printf(const(char*) fmt, ...); import core.vararg; struct Tup(T...) { T field; alias field this; bool opEquals(const Tup rhs) const { foreach (i, _; T) if (field[i] != rhs.field[i]) return false; return true; } } Tup!T tup(T...)(T fields) { return typeof(return)(fields); } template Seq(T...) { alias T Seq; } /**********************************************/ struct S { int x; alias x this; } int foo(int i) { return i * 2; } void test1() { S s; s.x = 7; int i = -s; assert(i == -7); i = s + 8; assert(i == 15); i = s + s; assert(i == 14); i = 9 + s; assert(i == 16); i = foo(s); assert(i == 14); } /**********************************************/ class C { int x; alias x this; } void test2() { C s = new C(); s.x = 7; int i = -s; assert(i == -7); i = s + 8; assert(i == 15); i = s + s; assert(i == 14); i = 9 + s; assert(i == 16); i = foo(s); assert(i == 14); } /**********************************************/ void test3() { Tup!(int, double) t; t[0] = 1; t[1] = 1.1; assert(t[0] == 1); assert(t[1] == 1.1); printf("%d %g\n", t[0], t[1]); } /**********************************************/ struct Iter { bool empty() { return true; } void popFront() { } ref Tup!(int, int) front() { return *new Tup!(int, int); } ref Iter opSlice() { return this; } } void test4() { foreach (a; Iter()) { } } /**********************************************/ void test5() { static struct Double1 { double val = 1; alias val this; } static Double1 x() { return Double1(); } x()++; } /**********************************************/ // 4617 struct S4617 { struct F { int square(int n) { return n*n; } real square(real n) { return n*n; } } F forward; alias forward this; alias forward.square sqr; // okay int field; void mfunc(); template Templ(){} void tfunc()(){} } template Id4617(alias k) { alias k Id4617; } void test4617a() { alias Id4617!(S4617.square) test1; //NG alias Id4617!(S4617.forward.square) test2; //OK alias Id4617!(S4617.sqr) test3; //okay static assert(__traits(isSame, S4617.square, S4617.forward.square)); } void test4617b() { static struct Sub(T) { T value; @property ref inout(T) payload() inout { return value; } alias payload this; } alias Id4617!(S4617.field) S_field; alias Id4617!(S4617.mfunc) S_mfunc; alias Id4617!(S4617.Templ) S_Templ; alias Id4617!(S4617.tfunc) S_tfunc; alias Sub!S4617 T4617; alias Id4617!(T4617.field) R_field; alias Id4617!(T4617.mfunc) R_mfunc; alias Id4617!(T4617.Templ) R_Templ; alias Id4617!(T4617.tfunc) R_tfunc; static assert(__traits(isSame, R_field, S_field)); static assert(__traits(isSame, R_mfunc, S_mfunc)); static assert(__traits(isSame, R_Templ, S_Templ)); static assert(__traits(isSame, R_tfunc, S_tfunc)); alias Id4617!(T4617.square) R_sqr; static assert(__traits(isSame, R_sqr, S4617.forward.square)); } /**********************************************/ // 4773 void test4773() { struct Rebindable { Object obj; @property const(Object) get(){ return obj; } alias get this; } Rebindable r; if (r) assert(0); r.obj = new Object; if (!r) assert(0); } /**********************************************/ // 5188 void test5188() { struct S { int v = 10; alias v this; } S s; assert(s <= 20); assert(s != 14); } /***********************************************/ struct Foo { void opIndexAssign(int x, size_t i) { val = x; } void opSliceAssign(int x, size_t a, size_t b) { val = x; } int val; } struct Bar { Foo foo; alias foo this; } void test6() { Bar b; b[0] = 1; assert(b.val == 1); b[0 .. 1] = 2; assert(b.val == 2); } /**********************************************/ // recursive alias this detection class C0 {} class C1 { C2 c; alias c this; } class C2 { C1 c; alias c this; } class C3 { C2 c; alias c this; } struct S0 {} struct S1 { S2* ps; @property ref get(){return *ps;} alias get this; } struct S2 { S1* ps; @property ref get(){return *ps;} alias get this; } struct S3 { S2* ps; @property ref get(){return *ps;} alias get this; } struct S4 { S5* ps; @property ref get(){return *ps;} alias get this; } struct S5 { S4* ps; @property ref get(){return *ps;} alias get this; } struct S6 { S5* ps; @property ref get(){return *ps;} alias get this; } void test7() { // Able to check a type is implicitly convertible within a finite time. static assert(!is(C1 : C0)); static assert( is(C2 : C1)); static assert( is(C1 : C2)); static assert(!is(C3 : C0)); static assert( is(C3 : C1)); static assert( is(C3 : C2)); static assert(!is(S1 : S0)); static assert( is(S2 : S1)); static assert( is(S1 : S2)); static assert(!is(S3 : S0)); static assert( is(S3 : S1)); static assert( is(S3 : S2)); C0 c0; C1 c1; C3 c3; S0 s0; S1 s1; S3 s3; S4 s4; S6 s6; // Allow merging types that contains alias this recursion. static assert( __traits(compiles, c0 is c1)); // typeMerge(c || c) e2->implicitConvTo(t1); static assert( __traits(compiles, c0 is c3)); // typeMerge(c || c) e2->implicitConvTo(t1); static assert( __traits(compiles, c1 is c0)); // typeMerge(c || c) e1->implicitConvTo(t2); static assert( __traits(compiles, c3 is c0)); // typeMerge(c || c) e1->implicitConvTo(t2); static assert(!__traits(compiles, s1 is c0)); // typeMerge(c || c) e1 static assert(!__traits(compiles, s3 is c0)); // typeMerge(c || c) e1 static assert(!__traits(compiles, c0 is s1)); // typeMerge(c || c) e2 static assert(!__traits(compiles, c0 is s3)); // typeMerge(c || c) e2 static assert(!__traits(compiles, s1 is s0)); // typeMerge(s && s) e1 static assert(!__traits(compiles, s3 is s0)); // typeMerge(s && s) e1 static assert(!__traits(compiles, s0 is s1)); // typeMerge(s && s) e2 static assert(!__traits(compiles, s0 is s3)); // typeMerge(s && s) e2 static assert(!__traits(compiles, s1 is s4)); // typeMerge(s && s) e1 + e2 static assert(!__traits(compiles, s3 is s6)); // typeMerge(s && s) e1 + e2 static assert(!__traits(compiles, s1 is 10)); // typeMerge(s || s) e1 static assert(!__traits(compiles, s3 is 10)); // typeMerge(s || s) e1 static assert(!__traits(compiles, 10 is s1)); // typeMerge(s || s) e2 static assert(!__traits(compiles, 10 is s3)); // typeMerge(s || s) e2 // SliceExp::semantic static assert(!__traits(compiles, c1[])); static assert(!__traits(compiles, c3[])); static assert(!__traits(compiles, s1[])); static assert(!__traits(compiles, s3[])); // CallExp::semantic // static assert(!__traits(compiles, c1())); // static assert(!__traits(compiles, c3())); static assert(!__traits(compiles, s1())); static assert(!__traits(compiles, s3())); // AssignExp::semantic static assert(!__traits(compiles, { c1[1] = 0; })); static assert(!__traits(compiles, { c3[1] = 0; })); static assert(!__traits(compiles, { s1[1] = 0; })); static assert(!__traits(compiles, { s3[1] = 0; })); static assert(!__traits(compiles, { c1[ ] = 0; })); static assert(!__traits(compiles, { c3[ ] = 0; })); static assert(!__traits(compiles, { s1[ ] = 0; })); static assert(!__traits(compiles, { s3[ ] = 0; })); // UnaExp::op_overload static assert(!__traits(compiles, +c1[1])); static assert(!__traits(compiles, +c3[1])); static assert(!__traits(compiles, +s1[1])); static assert(!__traits(compiles, +s3[1])); static assert(!__traits(compiles, +c1[ ])); static assert(!__traits(compiles, +c3[ ])); static assert(!__traits(compiles, +s1[ ])); static assert(!__traits(compiles, +s3[ ])); static assert(!__traits(compiles, +c1)); static assert(!__traits(compiles, +c3)); static assert(!__traits(compiles, +s1)); static assert(!__traits(compiles, +s3)); // ArrayExp::op_overload static assert(!__traits(compiles, c1[1])); static assert(!__traits(compiles, c3[1])); static assert(!__traits(compiles, s1[1])); static assert(!__traits(compiles, s3[1])); // BinExp::op_overload static assert(!__traits(compiles, c1 + 10)); // e1 static assert(!__traits(compiles, c3 + 10)); // e1 static assert(!__traits(compiles, 10 + c1)); // e2 static assert(!__traits(compiles, 10 + c3)); // e2 static assert(!__traits(compiles, s1 + 10)); // e1 static assert(!__traits(compiles, s3 + 10)); // e1 static assert(!__traits(compiles, 10 + s1)); // e2 static assert(!__traits(compiles, 10 + s3)); // e2 // BinExp::compare_overload static assert(!__traits(compiles, c1 < 10)); // (Object.opCmp(int) is invalid) static assert(!__traits(compiles, c3 < 10)); // (Object.opCmp(int) is invalid) static assert(!__traits(compiles, 10 < c1)); // (Object.opCmp(int) is invalid) static assert(!__traits(compiles, 10 < c3)); // (Object.opCmp(int) is invalid) static assert(!__traits(compiles, s1 < 10)); // e1 static assert(!__traits(compiles, s3 < 10)); // e1 static assert(!__traits(compiles, 10 < s1)); // e2 static assert(!__traits(compiles, 10 < s3)); // e2 // BinAssignExp::op_overload static assert(!__traits(compiles, c1[1] += 1)); static assert(!__traits(compiles, c3[1] += 1)); static assert(!__traits(compiles, s1[1] += 1)); static assert(!__traits(compiles, s3[1] += 1)); static assert(!__traits(compiles, c1[ ] += 1)); static assert(!__traits(compiles, c3[ ] += 1)); static assert(!__traits(compiles, s1[ ] += 1)); static assert(!__traits(compiles, s3[ ] += 1)); static assert(!__traits(compiles, c1 += c0)); // e1 static assert(!__traits(compiles, c3 += c0)); // e1 static assert(!__traits(compiles, s1 += s0)); // e1 static assert(!__traits(compiles, s3 += s0)); // e1 static assert(!__traits(compiles, c0 += c1)); // e2 static assert(!__traits(compiles, c0 += c3)); // e2 static assert(!__traits(compiles, s0 += s1)); // e2 static assert(!__traits(compiles, s0 += s3)); // e2 static assert(!__traits(compiles, c1 += s1)); // e1 + e2 static assert(!__traits(compiles, c3 += s3)); // e1 + e2 // ForeachStatement::inferAggregate static assert(!__traits(compiles, { foreach (e; s1){} })); static assert(!__traits(compiles, { foreach (e; s3){} })); static assert(!__traits(compiles, { foreach (e; c1){} })); static assert(!__traits(compiles, { foreach (e; c3){} })); // Expression::checkToBoolean static assert(!__traits(compiles, { if (s1){} })); static assert(!__traits(compiles, { if (s3){} })); // SwitchStatement::semantic static assert(!__traits(compiles, { switch (c0) { default: } })); static assert(!__traits(compiles, { switch (c1) { default: } })); static assert(!__traits(compiles, { switch (c3) { default: } })); // Bugzilla 12537: function arguments with IFTI void eq12537()(Object lhs) {} const C0 cc0; const C1 cc1; const C3 cc3; static assert(!__traits(compiles, eq12537(cc0))); static assert(!__traits(compiles, eq12537(cc1))); static assert(!__traits(compiles, eq12537(cc3))); } /***************************************************/ // 11875 - endless recursion in Type::deduceType struct T11875x(C) { C c; } class D11875a { D11875b c; alias c this; } class D11875b { D11875a c; alias c this; } static assert(!is(D11875a == D11875b)); static assert( is(T11875x!D11875a == T11875x!D, D) && is(D == D11875a)); static assert(!is(D11875a == T11875x!D, D)); // this used to freeze dmd // test that types in recursion are still detected struct T11875y(C) { C c; alias c this; } class D11875c { T11875y!D11875b c; alias c this; } static assert(is(D11875c : T11875y!D, D) && is(D == D11875b)); /***************************************************/ // 11930 class BarObj11930 {} struct Bar11930 { BarObj11930 _obj; alias _obj this; } BarObj11930 getBarObj11930(T)(T t) { static if (is(T unused : BarObj11930)) return t; else static assert(false, "Can not get BarObj from " ~ T.stringof); } void test11930() { Bar11930 b; getBarObj11930(b); } /***************************************************/ // 2781 struct Tuple2781a(T...) { T data; alias data this; } struct Tuple2781b(T) { T data; alias data this; } void test2781() { Tuple2781a!(uint, float) foo; foreach(elem; foo) {} { Tuple2781b!(int[]) bar1; foreach(elem; bar1) {} Tuple2781b!(int[int]) bar2; foreach(key, elem; bar2) {} Tuple2781b!(string) bar3; foreach(dchar elem; bar3) {} } { Tuple2781b!(int[]) bar1; foreach(elem; bar1) goto L1; L1: ; Tuple2781b!(int[int]) bar2; foreach(key, elem; bar2) goto L2; L2: ; Tuple2781b!(string) bar3; foreach(dchar elem; bar3) goto L3; L3: ; } int eval; auto t1 = tup(10, "str"); auto i1 = 0; foreach (e; t1) { pragma(msg, "[] = ", typeof(e)); static if (is(typeof(e) == int )) assert(i1 == 0 && e == 10); static if (is(typeof(e) == string)) assert(i1 == 1 && e == "str"); ++i1; } auto t2 = tup(10, "str"); foreach (i2, e; t2) { pragma(msg, "[", cast(int)i2, "] = ", typeof(e)); static if (is(typeof(e) == int )) { static assert(i2 == 0); assert(e == 10); } static if (is(typeof(e) == string)) { static assert(i2 == 1); assert(e == "str"); } } auto t3 = tup(10, "str"); auto i3 = 2; foreach_reverse (e; t3) { --i3; pragma(msg, "[] = ", typeof(e)); static if (is(typeof(e) == int )) assert(i3 == 0 && e == 10); static if (is(typeof(e) == string)) assert(i3 == 1 && e == "str"); } auto t4 = tup(10, "str"); foreach_reverse (i4, e; t4) { pragma(msg, "[", cast(int)i4, "] = ", typeof(e)); static if (is(typeof(e) == int )) { static assert(i4 == 0); assert(e == 10); } static if (is(typeof(e) == string)) { static assert(i4 == 1); assert(e == "str"); } } eval = 0; foreach (i, e; tup(tup((){eval++; return 10;}(), 3.14), tup("str", [1,2]))) { static if (i == 0) assert(e == tup(10, 3.14)); static if (i == 1) assert(e == tup("str", [1,2])); } assert(eval == 1); eval = 0; foreach (i, e; tup((){eval++; return 10;}(), tup(3.14, tup("str", tup([1,2]))))) { static if (i == 0) assert(e == 10); static if (i == 1) assert(e == tup(3.14, tup("str", tup([1,2])))); } assert(eval == 1); } /**********************************************/ // 6546 void test6546() { class C {} class D : C {} struct S { C c; alias c this; } // S : C struct T { S s; alias s this; } // T : S struct U { T t; alias t this; } // U : T C c; D d; S s; T t; U u; assert(c is c); // OK assert(c is d); // OK assert(c is s); // OK assert(c is t); // OK assert(c is u); // OK assert(d is c); // OK assert(d is d); // OK assert(d is s); // doesn't work assert(d is t); // doesn't work assert(d is u); // doesn't work assert(s is c); // OK assert(s is d); // doesn't work assert(s is s); // OK assert(s is t); // doesn't work assert(s is u); // doesn't work assert(t is c); // OK assert(t is d); // doesn't work assert(t is s); // doesn't work assert(t is t); // OK assert(t is u); // doesn't work assert(u is c); // OK assert(u is d); // doesn't work assert(u is s); // doesn't work assert(u is t); // doesn't work assert(u is u); // OK } /**********************************************/ // 6736 void test6736() { static struct S1 { struct S2 // must be 8 bytes in size { uint a, b; } S2 s2; alias s2 this; } S1 c; static assert(!is(typeof(c + c))); } /**********************************************/ // 2777 struct ArrayWrapper(T) { T[] array; alias array this; } // alias array this void test2777a() { ArrayWrapper!(uint) foo; foo.length = 5; // Works foo[0] = 1; // Works auto e0 = foo[0]; // Works auto e4 = foo[$ - 1]; // Error: undefined identifier __dollar auto s01 = foo[0..2]; // Error: ArrayWrapper!(uint) cannot be sliced with[] } // alias tuple this void test2777b() { auto t = tup(10, 3.14, "str", [1,2]); assert(t[$ - 1] == [1,2]); auto f1 = t[]; assert(f1[0] == 10); assert(f1[1] == 3.14); assert(f1[2] == "str"); assert(f1[3] == [1,2]); auto f2 = t[1..3]; assert(f2[0] == 3.14); assert(f2[1] == "str"); } /****************************************/ // 2787 struct Base2787 { int x; void foo() { auto _ = x; } } struct Derived2787 { Base2787 _base; alias _base this; int y; void bar() { auto _ = x; } } /***********************************/ // 5679 void test5679() { class Foo {} class Base { @property Foo getFoo() { return null; } } class Derived : Base { alias getFoo this; } Derived[] dl; Derived d = new Derived(); dl ~= d; // Error: cannot append type alias_test.Base to type Derived[] } /***********************************/ // 6508 void test6508() { int x, y; Seq!(x, y) = tup(10, 20); assert(x == 10); assert(y == 20); } void test6508x() { static int ctor, cpctor, dtor; static struct Tuple(T...) { T field; alias field this; this(int) { ++ctor; printf("ctor\n"); } this(this) { ++cpctor; printf("cpctor\n"); } ~this() { ++dtor; printf("dtor\n"); } } { alias Tup = Tuple!(int, string); auto tup = Tup(1); assert(ctor==1 && cpctor==0 && dtor==0); auto getVal() { return tup; } ref getRef(ref Tup s = tup) { return s; } { auto n1 = tup[0]; assert(ctor==1 && cpctor==0 && dtor==0); auto n2 = getRef()[0]; assert(ctor==1 && cpctor==0 && dtor==0); auto n3 = getVal()[0]; assert(ctor==1 && cpctor==1 && dtor==1); } // bug in DotVarExp::semantic { typeof(tup.field) vars; vars = getVal(); assert(ctor==1 && cpctor==2 && dtor==2); } } assert(ctor==1 && cpctor==2 && dtor==3); assert(ctor + cpctor == dtor); } /***********************************/ // 6369 void test6369a() { alias Seq!(int, string) Field; auto t1 = Tup!(int, string)(10, "str"); Field field1 = t1; // NG -> OK assert(field1[0] == 10); assert(field1[1] == "str"); auto t2 = Tup!(int, string)(10, "str"); Field field2 = t2.field; // NG -> OK assert(field2[0] == 10); assert(field2[1] == "str"); auto t3 = Tup!(int, string)(10, "str"); Field field3; field3 = t3.field; assert(field3[0] == 10); assert(field3[1] == "str"); } void test6369b() { auto t = Tup!(Tup!(int, double), string)(tup(10, 3.14), "str"); Seq!(int, double, string) fs1 = t; assert(fs1[0] == 10); assert(fs1[1] == 3.14); assert(fs1[2] == "str"); Seq!(Tup!(int, double), string) fs2 = t; assert(fs2[0][0] == 10); assert(fs2[0][1] == 3.14); assert(fs2[0] == tup(10, 3.14)); assert(fs2[1] == "str"); Tup!(Tup!(int, double), string) fs3 = t; assert(fs3[0][0] == 10); assert(fs3[0][1] == 3.14); assert(fs3[0] == tup(10, 3.14)); assert(fs3[1] == "str"); } void test6369c() { auto t = Tup!(Tup!(int, double), Tup!(string, int[]))(tup(10, 3.14), tup("str", [1,2])); Seq!(int, double, string, int[]) fs1 = t; assert(fs1[0] == 10); assert(fs1[1] == 3.14); assert(fs1[2] == "str"); assert(fs1[3] == [1,2]); Seq!(int, double, Tup!(string, int[])) fs2 = t; assert(fs2[0] == 10); assert(fs2[1] == 3.14); assert(fs2[2] == tup("str", [1,2])); Seq!(Tup!(int, double), string, int[]) fs3 = t; assert(fs3[0] == tup(10, 3.14)); assert(fs3[0][0] == 10); assert(fs3[0][1] == 3.14); assert(fs3[1] == "str"); assert(fs3[2] == [1,2]); } void test6369d() { int eval = 0; Seq!(int, string) t = tup((){++eval; return 10;}(), "str"); assert(eval == 1); assert(t[0] == 10); assert(t[1] == "str"); } /**********************************************/ // 6434 struct Variant6434{} struct A6434 { Variant6434 i; alias i this; void opDispatch(string name)() { } } void test6434() { A6434 a; a.weird; // no property 'weird' for type 'VariantN!(maxSize)' } /**************************************/ // 6366 void test6366() { struct Zip { string str; size_t i; this(string s) { str = s; } @property const bool empty() { return i == str.length; } @property Tup!(size_t, char) front() { return typeof(return)(i, str[i]); } void popFront() { ++i; } } foreach (i, c; Zip("hello")) { switch (i) { case 0: assert(c == 'h'); break; case 1: assert(c == 'e'); break; case 2: assert(c == 'l'); break; case 3: assert(c == 'l'); break; case 4: assert(c == 'o'); break; default:assert(0); } } auto range(F...)(F field) { static struct Range { F field; bool empty = false; Tup!F front() { return typeof(return)(field); } void popFront(){ empty = true; } } return Range(field); } foreach (i, t; range(10, tup("str", [1,2]))){ static assert(is(typeof(i) == int)); static assert(is(typeof(t) == Tup!(string, int[]))); assert(i == 10); assert(t == tup("str", [1,2])); } auto r1 = range(10, "str", [1,2]); auto r2 = range(tup(10, "str"), [1,2]); auto r3 = range(10, tup("str", [1,2])); auto r4 = range(tup(10, "str", [1,2])); alias Seq!(r1, r2, r3, r4) ranges; foreach (n, _; ranges) { foreach (i, s, a; ranges[n]){ static assert(is(typeof(i) == int)); static assert(is(typeof(s) == string)); static assert(is(typeof(a) == int[])); assert(i == 10); assert(s == "str"); assert(a == [1,2]); } } } /***************************************************/ // 6711 void test6711() { struct A { int i; } struct B { A a; alias a this; } struct C { B b; alias b this; } B b; with (b) { i = 42; } assert(b.i == 42); C c; with (c) { i = 42; } assert(c.i == 42); } /**********************************************/ // 12161 class A12161 { void m() {} } class B12161 { A12161 a; alias a this; } void test12161() { B12161 b = new B12161(); b.a = new A12161(); with (b) m(); } /**********************************************/ // 6759 struct Range { size_t front() { return 0; } void popFront() { empty = true; } bool empty; } struct ARange { Range range; alias range this; } void test6759() { ARange arange; assert(arange.front == 0); foreach(e; arange) { assert(e == 0); } } /**********************************************/ // 6479 struct Memory6479 { mixin Wrapper6479!(); } struct Image6479 { Memory6479 sup; alias sup this; } mixin template Wrapper6479() { } /**********************************************/ // 6832 void test6832() { static class Foo { } static struct Bar { Foo foo; alias foo this; } Bar bar; bar = new Foo; // ok assert(bar !is null); // ng struct Int { int n; alias n this; } Int a; int b; auto c = (true ? a : b); // TODO assert(c == a); } /**********************************************/ // 6928 void test6928() { struct T { int* p; } // p is necessary. T tx; struct S { T get() const { return tx; } alias get this; } immutable(S) s; immutable(T) t; static assert(is(typeof(1? s:t))); // ok. static assert(is(typeof(1? t:s))); // ok. static assert(is(typeof(1? s:t)==typeof(1? t:s))); // fail. auto x = 1? t:s; // ok. auto y = 1? s:t; // compile error. } /**********************************************/ // 6929 struct S6929 { T6929 get() const { return T6929.init; } alias get this; } struct T6929 { S6929 get() const { return S6929.init; } alias get this; } void test6929() { T6929 t; S6929 s; static assert(!is(typeof(1? t:s))); } /***************************************************/ // 7136 void test7136() { struct X { Object get() immutable { return null; } alias get this; } immutable(X) x; Object y; static assert( is(typeof(1?x:y) == Object)); // fails static assert(!is(typeof(1?x:y) == const(Object))); // fails struct A { int[] get() immutable { return null; } alias get this; } immutable(A) a; int[] b; static assert( is(typeof(1?a:b) == int[])); // fails static assert(!is(typeof(1?a:b) == const(int[]))); // fails } /***************************************************/ // 7731 struct A7731 { int a; } template Inherit7731(alias X) { X __super; alias __super this; } struct B7731 { mixin Inherit7731!A7731; int b; } struct PolyPtr7731(X) { X* _payload; static if (is(typeof(X.init.__super))) { alias typeof(X.init.__super) Super; @property auto getSuper(){ return PolyPtr7731!Super(&_payload.__super); } alias getSuper this; } } template create7731(X) { PolyPtr7731!X create7731(T...)(T args){ return PolyPtr7731!X(args); } } void f7731a(PolyPtr7731!A7731 a) {/*...*/} void f7731b(PolyPtr7731!B7731 b) {f7731a(b);/*...*/} void test7731() { auto b = create7731!B7731(); } /***************************************************/ // 7808 struct Nullable7808(T) { private T _value; this()(T value) { _value = value; } @property ref inout(T) get() inout pure @safe { return _value; } alias get this; } class C7808 {} struct S7808 { C7808 c; } void func7808(S7808 s) {} void test7808() { auto s = Nullable7808!S7808(S7808(new C7808)); func7808(s); } /***************************************************/ // 7945 struct S7945 { int v; alias v this; } void foo7945(ref int n){} void test7945() { auto s = S7945(1); foo7945(s); // 1.NG -> OK s.foo7945(); // 2.OK, ufcs foo7945(s.v); // 3.OK s.v.foo7945(); // 4.OK, ufcs } /***************************************************/ // 15674 - alias this on out parameter, consistent with 7945 case struct S15674 { int v; alias v this; } void foo15674(out int i){ i = 42; } void test15674() { S15674 s; s.v = 1; foo15674(s); assert(s.v == 42); s.v = 1; foo15674(s.v); assert(s.v == 42); s.v = 1; s.foo15674(); assert(s.v == 42); s.v = 1; s.v.foo15674(); assert(s.v == 42); } /***************************************************/ // 7979 void test7979() { static struct N { int val; alias val this; } N n = N(1); switch (n) { case 0: assert(0); case 1: break; default: assert(0); } static struct S { string val; alias val this; } S s = S("b"); switch (s) { case "a": assert(0); case "b": break; default: assert(0); } } /***************************************************/ // 7992 struct S7992 { int[] arr; alias arr this; } S7992 func7992(...) { S7992 ret; ret.arr.length = _arguments.length; return ret; } void test7992() { int[] arr; assert(arr.length == 0); arr ~= func7992(1, 2); //NG //arr = func7992(1, 2); //OK assert(arr.length == 2); } /***************************************************/ // 8169 void test8169() { static struct ValueImpl { static immutable(int) getValue() { return 42; } } static struct ValueUser { ValueImpl m_valueImpl; alias m_valueImpl this; } static assert(ValueImpl.getValue() == 42); // #0, OK static assert(ValueUser.getValue() == 42); // #1, NG -> OK static assert( ValueUser.m_valueImpl .getValue() == 42); // #2, NG -> OK static assert(typeof(ValueUser.m_valueImpl).getValue() == 42); // #3, OK } /***************************************************/ // 8735 struct S8735(alias Arg) { alias Arg Val; alias Val this; } struct Tuple9709(T...) { alias T expand; alias expand this; } void test8735() { alias S8735!1 S; S s; int n = s; assert(n == 1); // 11502 case static void f(int i); S8735!f sf; // 9709 case alias A = Tuple9709!(1,int,"foo"); A a; //static assert(A[0] == 1); static assert(a[0] == 1); //static assert(is(A[1] == int)); //static assert(is(a[1] == int)); //static assert(A[2] == "foo"); static assert(a[2] == "foo"); } /***************************************************/ // 9174 void test9174() { static struct Foo { char x; alias x this; } static assert(is(typeof(true ? 'A' : Foo()) == char)); static assert(is(typeof(true ? Foo() : 100) == int)); } /***************************************************/ // 9177 struct S9177 { int foo(int){ return 0; } alias foo this; } pragma(msg, is(S9177 : int)); /***************************************************/ // 9858 struct S9858() { @property int get() const { return 42; } alias get this; void opAssign(int) {} } void test9858() { const S9858!() s; int i = s; } /***************************************************/ // 9873 void test9873() { struct Tup(T...) { T field; alias field this; } auto seq1 = Seq!(1, "hi"); assert(Seq!(1, "hi") == Seq!(1, "hi")); assert(seq1 == Seq!(1, "hi")); assert(Seq!(1, "hi") == seq1); assert(seq1 == seq1); auto seq2 = Seq!(2, "hi"); assert(Seq!(1, "hi") != Seq!(2, "hi")); assert(seq2 != Seq!(1, "hi")); assert(Seq!(1, "hi") != seq2); assert(seq2 != seq1); auto tup1 = Tup!(int, string)(1, "hi"); assert(Seq!(1, "hi") == tup1); assert(seq1 == tup1); assert(tup1 == Seq!(1, "hi")); assert(tup1 == seq1); auto tup2 = Tup!(int, string)(2, "hi"); assert(Seq!(1, "hi") != tup2); assert(seq1 != tup2); assert(tup2 != Seq!(1, "hi")); assert(tup2 != seq1); static assert(!__traits(compiles, seq1 == Seq!(1, "hi", [1,2]))); static assert(!__traits(compiles, tup1 == Seq!(1, "hi", [1,2]))); } /***************************************************/ // 10178 void test10178() { struct S { static int count; } S s; assert((s.tupleof == s.tupleof) == true); assert((s.tupleof != s.tupleof) == false); S getS() { S s; ++S.count; return s; } assert(getS().tupleof == getS().tupleof); assert(S.count == 2); } /***************************************************/ // 10179 void test10179() { struct S { static int count; } S s; static assert(s.tupleof.length == 0); s.tupleof = s.tupleof; // error -> OK S getS() { S s; ++S.count; return s; } getS().tupleof = getS().tupleof; assert(S.count == 2); } /***************************************************/ // 9890 void test9890() { struct RefCounted(T) { T _payload; ref T refCountedPayload() { return _payload; } alias refCountedPayload this; } struct S(int x_) { alias x_ x; } alias RefCounted!(S!1) Rs; static assert(Rs.x == 1); } /***************************************************/ // 10004 void test10004() { static int count = 0; static S make(S)() { ++count; // necessary to make this function impure S s; return s; } struct SX(T...) { T field; alias field this; } alias S = SX!(int, long); assert(make!S.field == make!S.field); assert(count == 2); } /***************************************************/ // 10180 template TypeTuple10180(TL...) { alias TypeTuple10180 = TL; } template Identity10180(alias T) { alias Identity10180 = T; } struct Tuple10180(Specs...) { static if (is(Specs)) { alias Types = Specs; Types expand; alias expand this; } else { alias Types = TypeTuple10180!(Specs[0]); Types expand; mixin("alias Identity10180!(expand[0]) "~Specs[1]~";"); @property ref Tuple10180!(Specs[0]) _Tuple_super() { return *cast(typeof(return)*) (&expand[0]); } alias _Tuple_super this; } } void test10180() { Tuple10180!(int, "a") x; auto o1 = x.a.offsetof; // OK auto o2 = x[0].offsetof; // NG: no property 'offsetof' for type 'int' auto o3 = x._Tuple_super[0].offsetof; // same as above assert(o2 == o3); } /***************************************************/ // 10456 void test10456() { S10456 s1, s2; auto x = s1 == s2; } struct S10456 { enum E { e }; alias E this; int[] x; } /***************************************************/ // 11261 template Tuple11261(Specs...) { struct Tuple11261 { static if (Specs.length != 4) // anonymous field version { alias Specs Types; Types expand; alias expand this; } else { alias Seq!(Specs[0], Specs[2]) Types; Types expand; ref inout(Tuple11261!Types) _Tuple_super() inout @trusted { return *cast(typeof(return)*) &(expand[0]); } // This is mostly to make t[n] work. alias _Tuple_super this; } this()(Types values) { expand[] = values[]; } } } interface InputRange11261(E) { @property bool empty(); @property E front(); void popFront(); int opApply(int delegate(E)); int opApply(int delegate(size_t, E)); } template InputRangeObject11261(R) { alias typeof(R.init.front()) E; class InputRangeObject11261 : InputRange11261!E { private R _range; this(R range) { this._range = range; } @property bool empty() { return _range.empty; } @property E front() { return _range.front; } void popFront() { _range.popFront(); } int opApply(int delegate(E) dg) { return 0; } int opApply(int delegate(size_t, E) dg) { return 0; } } } // ------ class Container11261 { alias Tuple11261!(string, "key", string, "value") Key; InputRange11261!Key opSlice() { Range r; return new InputRangeObject11261!Range(r); } private struct Range { enum empty = false; auto popFront() {} auto front() { return Key("myKey", "myValue"); } } } void test11261() { auto container = new Container11261(); foreach (k, v; container) // map the tuple of container[].front to (k, v) { static assert(is(typeof(k) == string) && is(typeof(v) == string)); break; } } /***************************************************/ // 11333 alias id11333(a...) = a; struct Unit11333 { enum value = Unit11333.init.tupleof; alias value this; } void test11333() { void foo() {} id11333!() unit; unit = unit; // ok foo(unit); // ok unit = Unit11333.value; // ok foo(Unit11333.value); // ok Unit11333 unit2; unit = unit2; // ok <- segfault } /***************************************************/ // 11800 struct A11800 { B11800 b; alias b this; } struct B11800 { static struct Value {} Value value; alias value this; void foo(ref const B11800 rhs) { } } void test11800() { A11800 a; B11800 b; b.foo(a); } /***************************************************/ // 12008 struct RefCounted12008(T) { struct RefCountedStore { private struct Impl { T _payload; } private void initialize(A...)(auto ref A args) { import core.memory; } void ensureInitialized() { initialize(); } } RefCountedStore _refCounted; void opAssign(T rhs) { } int refCountedPayload() { _refCounted.ensureInitialized(); return 0; } int refCountedPayload() inout { return 0; } alias refCountedPayload this; } struct SharedInput12008 { Group12008 unused; } struct Group12008 { RefCounted12008!SharedInput12008 _allGroups; } /***************************************************/ // 12038 bool f12038(void* p) { return true; } struct S12038 { @property p() { f12038(&this); } alias p this; } /***************************************************/ // 13490 struct S13490 { int i; alias i this; } struct T13490 { S13490[] a1, a2; } void test13490() { T13490 t; (true ? t.a1 : t.a2) ~= S13490(1); assert(t.a1 == [S13490(1)]); assert(t.a2 == []); (false ? t.a1 : t.a2) ~= S13490(2); assert(t.a1 == [S13490(1)]); assert(t.a2 == [S13490(2)]); } /***************************************************/ // 11355 struct A11355 { static int postblit; this(this) { ++postblit; } } struct B11355 { A11355 a; alias a this; } B11355 make11355() { return B11355(); } void test11355() { A11355 a1 = make11355(); assert(A11355.postblit == 1); } /***************************************************/ // 13009 struct T13009 { void put(char c) {} } struct S13009(bool rev) { T13009 t; static if (!rev) { @property T13009 getT() { return t; } @property inout(T13009) getT() inout { return t; } } else { @property inout(T13009) getT() inout { return t; } @property T13009 getT() { return t; } } alias getT this; } void test13009() { foreach (bool rev; Seq!(false, true)) { alias S = S13009!rev; alias MS = S; alias CS = const(S); alias WS = inout( S); alias WCS = inout(const S); alias SMS = shared( S); alias SCS = shared( const S); alias SWS = shared(inout S); alias SWCS = shared(inout const S); alias IS = immutable(S); alias MSput = MS .put; alias CSput = CS .put; alias WSput = WS .put; alias WCSput = WCS.put; static assert(!__traits(compiles, { alias SMSput = SMS .put; })); static assert(!__traits(compiles, { alias SCSput = SCS .put; })); static assert(!__traits(compiles, { alias SWSput = SWS .put; })); static assert(!__traits(compiles, { alias SWCSput = SWCS.put; })); alias ISput = IS .put; } } /***************************************************/ // 14806 struct Nullable14806 { float get() { return float.nan; } alias get this; } struct Foo14806(T) { T bar; Nullable14806 baz; } void test14806() { Foo14806!int a, b; assert(a != b); // ==> a.tupleof != b.tupleof // ==> a.bar != b.bar || a.baz.get() != b.baz.get() Foo14806!string c, d; assert(c != d); // ==> c.tupleof != d.tupleof // ==> c.bar != d.bar || c.baz.get() != d.baz.get() } /***************************************************/ // 14948 struct RefCounted14948(T) { struct Impl { T data; } Impl* impl; @property ref T payload() { return impl.data; } alias payload this; } struct HTTP14948 { struct Impl { } RefCounted14948!Impl p; } void test14948() { int[HTTP14948] aa; } /***************************************************/ // 15292 struct NullableRef15292(T) { inout(T) get() inout { assert(false); } alias get this; } struct S15292 { NullableRef15292!S15292 n; // -> no segfault /* The field 'n' contains alias this, so to use it for the equality, * following helper function is automatically generated in buildXopEquals(). * * static bool __xopEquals(ref const S15292 p, ref const S15292 q) * { * return p == q; * } * * In its definition, const(S15292) equality is analyzed. It fails, then * the error is gagged. */ } /***************************************************/ int main() { test1(); test2(); test3(); test4(); test5(); test4617a(); test4617b(); test4773(); test5188(); test6(); test7(); test2781(); test6546(); test6736(); test2777a(); test2777b(); test5679(); test6508(); test6508x(); test6369a(); test6369b(); test6369c(); test6369d(); test6434(); test6366(); test6711(); test12161(); test6759(); test6832(); test6928(); test6929(); test7136(); test7731(); test7808(); test7945(); test15674(); test7979(); test7992(); test8169(); test8735(); test9174(); test9858(); test9873(); test10178(); test10179(); test9890(); test10004(); test10180(); test10456(); test11333(); test11800(); test13490(); test11355(); test14806(); printf("Success\n"); return 0; }