blob: db5913c83899897719a5e124ae2925ae06abb428 [file] [log] [blame]
/*
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 { return this; }
}
void test4()
{
foreach (a; Iter()) { }
}
/**********************************************/
void test5()
{
static struct Double1 {
double val = 1;
alias val this;
}
static Double1 x() { return Double1(); }
x()++;
}
/**********************************************/
// https://issues.dlang.org/show_bug.cgi?id=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));
}
/**********************************************/
// https://issues.dlang.org/show_bug.cgi?id=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);
}
/**********************************************/
// https://issues.dlang.org/show_bug.cgi?id=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: } }));
// https://issues.dlang.org/show_bug.cgi?id=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)));
}
/***************************************************/
// https://issues.dlang.org/show_bug.cgi?id=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));
/***************************************************/
// https://issues.dlang.org/show_bug.cgi?id=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);
}
/***************************************************/
// https://issues.dlang.org/show_bug.cgi?id=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);
}
/**********************************************/
// https://issues.dlang.org/show_bug.cgi?id=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
}
/**********************************************/
// https://issues.dlang.org/show_bug.cgi?id=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)));
}
/**********************************************/
// https://issues.dlang.org/show_bug.cgi?id=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");
}
/****************************************/
// https://issues.dlang.org/show_bug.cgi?id=2787
struct Base2787
{
int x;
void foo() { auto _ = x; }
}
struct Derived2787
{
Base2787 _base;
alias _base this;
int y;
void bar() { auto _ = x; }
}
/***********************************/
// https://issues.dlang.org/show_bug.cgi?id=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[]
}
/***********************************/
// https://issues.dlang.org/show_bug.cgi?id=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);
}
/***********************************/
// https://issues.dlang.org/show_bug.cgi?id=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");
}
/**********************************************/
// https://issues.dlang.org/show_bug.cgi?id=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)'
}
/**************************************/
// https://issues.dlang.org/show_bug.cgi?id=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]);
}
}
}
/***************************************************/
// https://issues.dlang.org/show_bug.cgi?id=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);
}
/**********************************************/
// https://issues.dlang.org/show_bug.cgi?id=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();
}
/**********************************************/
// https://issues.dlang.org/show_bug.cgi?id=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);
}
}
/**********************************************/
// https://issues.dlang.org/show_bug.cgi?id=6479
struct Memory6479
{
mixin Wrapper6479!();
}
struct Image6479
{
Memory6479 sup;
alias sup this;
}
mixin template Wrapper6479()
{
}
/**********************************************/
// https://issues.dlang.org/show_bug.cgi?id=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);
}
/**********************************************/
// https://issues.dlang.org/show_bug.cgi?id=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.
}
/**********************************************/
// https://issues.dlang.org/show_bug.cgi?id=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)));
}
/***************************************************/
// https://issues.dlang.org/show_bug.cgi?id=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
}
/***************************************************/
// https://issues.dlang.org/show_bug.cgi?id=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();
}
/***************************************************/
// https://issues.dlang.org/show_bug.cgi?id=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);
}
/***************************************************/
// https://issues.dlang.org/show_bug.cgi?id=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
}
/***************************************************/
// https://issues.dlang.org/show_bug.cgi?id=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);
}
/***************************************************/
// https://issues.dlang.org/show_bug.cgi?id=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);
}
}
/***************************************************/
// https://issues.dlang.org/show_bug.cgi?id=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);
}
/***************************************************/
// https://issues.dlang.org/show_bug.cgi?id=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
}
/***************************************************/
// https://issues.dlang.org/show_bug.cgi?id=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);
// https://issues.dlang.org/show_bug.cgi?id=11502
static void f(int i);
S8735!f sf;
// https://issues.dlang.org/show_bug.cgi?id=9709
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");
}
/***************************************************/
// https://issues.dlang.org/show_bug.cgi?id=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));
}
/***************************************************/
// https://issues.dlang.org/show_bug.cgi?id=9177
struct S9177
{
int foo(int){ return 0; }
alias foo this;
}
pragma(msg, is(S9177 : int));
/***************************************************/
// https://issues.dlang.org/show_bug.cgi?id=9858
struct S9858()
{
@property int get() const
{
return 42;
}
alias get this;
void opAssign(int) {}
}
void test9858()
{
const S9858!() s;
int i = s;
}
/***************************************************/
// https://issues.dlang.org/show_bug.cgi?id=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])));
}
/***************************************************/
// https://issues.dlang.org/show_bug.cgi?id=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);
}
/***************************************************/
// https://issues.dlang.org/show_bug.cgi?id=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);
}
/***************************************************/
// https://issues.dlang.org/show_bug.cgi?id=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);
}
/***************************************************/
// https://issues.dlang.org/show_bug.cgi?id=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);
}
/***************************************************/
// https://issues.dlang.org/show_bug.cgi?id=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);
}
/***************************************************/
// https://issues.dlang.org/show_bug.cgi?id=10456
void test10456()
{
S10456 s1, s2;
auto x = s1 == s2;
}
struct S10456
{
enum E { e };
alias E this;
int[] x;
}
/***************************************************/
// https://issues.dlang.org/show_bug.cgi?id=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;
}
}
/***************************************************/
// https://issues.dlang.org/show_bug.cgi?id=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
}
/***************************************************/
// https://issues.dlang.org/show_bug.cgi?id=11538
struct NullableRef11538(T)
{
T* _value;
inout(T) get() inout { return *_value; }
alias get this;
}
struct S11538
{
NullableRef11538!S11538 parent;
}
/***************************************************/
// https://issues.dlang.org/show_bug.cgi?id=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);
}
/***************************************************/
// https://issues.dlang.org/show_bug.cgi?id=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;
}
/***************************************************/
// https://issues.dlang.org/show_bug.cgi?id=12038
bool f12038(void* p) { return true; }
struct S12038
{
@property p() { f12038(&this); }
alias p this;
}
/***************************************************/
// https://issues.dlang.org/show_bug.cgi?id=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)]);
}
/***************************************************/
// https://issues.dlang.org/show_bug.cgi?id=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);
}
/***************************************************/
// https://issues.dlang.org/show_bug.cgi?id=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;
}
}
/***************************************************/
// https://issues.dlang.org/show_bug.cgi?id=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()
}
/***************************************************/
// https://issues.dlang.org/show_bug.cgi?id=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;
}
/***************************************************/
// https://issues.dlang.org/show_bug.cgi?id=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.
*/
}
/***************************************************/
struct S19284a { int x; }
struct S19284b
{
S19284a s;
alias s this;
int t;
void f()
{
void wrapped()
{
x = 1;
t = 1;
}
wrapped(); // <-- 'x' not found, whereas 's.x' works fine
}
void f1()
{
x = 2;
}
void f2()
{
int x;
void wrapped()
{
x = 7;
}
wrapped();
assert(x == 7);
}
void f3()
{
void wrapped()
{
void wrapped2()
{
x = 5;
}
wrapped2();
}
wrapped();
}
}
void test19284()
{
S19284b t;
// nested function modifies alias this
t.f();
assert(t.x == 1);
assert(t.t == 1);
// member function modifies alias this
t.f1();
assert(t.x == 2);
// nested function does not modify alias this when it is shadowd by a local variable
t.f2();
assert(t.x == 2);
// multiple levels of nesting
t.f3();
assert(t.x == 5);
}
// 16633
class Item
{
alias children this;
Item[] children;
void populate()
{
children ~= new Item(); // Item is seen as []
assert(children.length == 1);
}
}
void test16633()
{
Item root = new Item();
root.populate;
}
/***************************************************/
// https://issues.dlang.org/show_bug.cgi?id=13009
struct RefCounted13009_2(T)
{
ref T refCountedPayload()
{
assert(false);
}
ref inout(T) refCountedPayload() inout
{
assert(false);
}
alias refCountedPayload this;
}
struct S13009_2
{
struct Payload
{
int[] data;
}
RefCounted13009_2!Payload payload;
alias X = typeof(payload.data[0]);
void foo()
{
payload.data[0] = 0;
}
}
/***************************************************/
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();
test19284();
test16633();
printf("Success\n");
return 0;
}