// REQUIRED_ARGS:

module template1;

import core.stdc.stdio : printf;
import core.vararg;

/******************************************/

template TFoo1(T,U)
{
    int foo(T t, U u)
    {
        return 3;
    }
}


alias TFoo1!(int, char) Foo1;


void test1()
{
    int i = Foo1.foo(1, 2);
    assert(i == 3);
}

/******************************************/

template TFoo2(T,U)
{
    T x = 4;
    U y;
}


alias TFoo2!(int, char) Foo2;


void test2()
{
    assert(Foo2.x + Foo2.y == 0x103);
    Foo2.x = 3;
    Foo2.y = 7;
    assert(Foo2.x + Foo2.y == 10);
}

/******************************************/

template TFoo3(T,U)
{
    class Bar
    {
        T x = 4;
        U y;
    }
}


alias TFoo3!(int, char) Foo3;


void test3()
{
    Foo3.Bar b = new Foo3.Bar();

    assert(b.x == 4);
    assert(b.y == 0xFF);
}

/******************************************/

template TFoo4(T,U)
{
    T x;
    U y;
}

template TFoo4(T:T,U:T)
{
    T a;
    U b;
}

template TFoo4(T:uint, U:uint)
{
    T c;
    U d;
}

alias TFoo4!(int, char) Foo4x;

void test4()
{
    alias TFoo4!(int, char) Foo4;
    int* x = &Foo4.c;
    char* y = &Foo4.d;

    alias TFoo4!(uint, char**) Foo4_2;
    uint* x2 = &Foo4_2.x;
    char*** y2 = &Foo4_2.y;

    alias TFoo4!(int, int) Foo4_3;
    int* x3 = &Foo4_3.a;
    int* y3 = &Foo4_3.b;

    alias TFoo4!(uint, uint) Foo4_4;
    uint* x4 = &Foo4_4.c;
    uint* y4 = &Foo4_4.d;
}


/******************************************/

template TtoUx(T, U)
{
    T toUx(U[] s)
    {
        uint v = 0;

        if (v != cast(T)v)
            return 3;

        return cast(T)v;
    }

}

alias TtoUx!(ubyte, char).toUx toUbyte;
alias TtoUx!(ushort, char).toUx toUshort;

void test5()
{
}


/******************************************/

template TtoUx6(T, U)
{
    T toUx(U[] s)
    {
        uint v = 0;

        if (v != cast(T)v)
            return 3;

        return cast(T)v;
    }

}

alias TtoUx6!(ubyte, char) t6;

void test6()
{
}

/******************************************/

template A7(T) {
    T id(T t) {
        return t;
    }
}

alias A7!(int) a;

void test7()
{
    printf("%d\r\n", a.id(3));
    assert(a.id(3) == 3);
}

/******************************************/

template Swapper(T)
{
    void Swap(ref T a, ref T b)
    {
        T temp = a; a = b; b = temp;
    }
}

void test8()
{
    alias Swapper!(int) IntSwap;
    int a=1,b=2;
    IntSwap.Swap(a,b);
    printf("a=%d,b=%d\n",a,b); // prints 2,1
    assert(a == 2);
    assert(b == 1);
}


/******************************************/

template Foo9(T)
{
    class B
    {
        T data;
    }
}

void test9()
{
    (new Foo9!(int).B).data += 4;
}


/******************************************/

template A10(T) {
}

template B10(T) {
    alias A10!(int) a;
}

void test10()
{
    alias B10!(int) b;
}

/******************************************/

template A11(T) {
    T idf(T t) {
        return t;
    }
}

template B11(T) {
    private alias A11!(T) a;
    T same(T t) {
        return a.idf(t);
    }
}

void test11()
{
    alias B11!(int) b;
    //printf("%d\r\n", b.same(10));
    assert(b.same(10) == 10);
}


/******************************************/

template A12(T) {
    class B {
        invariant() {
            assert(1);
        }
    T ide(T t) {
        return t;
    }
    }
}

void test12()
{
    alias A12!(int) a;
    a.B b = new a.B();
    printf("%d\r\n", b.ide(10));
    assert(b.ide(10) == 10);
}


/******************************************/

template A13(T) {
    public interface I {
        public T i();
    }
}

class B13 : A13!(int).I {
    public int i() {
        return 42;
    }
}

void test13()
{
    B13 b = new B13();
    A13!(int).I i = b;
    assert(b.i() == 42);
    assert(i.i() == 42);
}


/******************************************/

class B14
{
}

template A14(T, U) {

    private U u;

    static this()
    {
        u = new U();
    }
}

alias A14!(int, B14) t14;

void test14()
{
}


/******************************************/

template A15(T) {
    public interface Init {
        public T init();
    }
}
template A15(T : int) {
    public class Init {
        public T init() {
            return 42;
        };
    }
}
template A15(T : float) {
    public class Init {
        public T init() {
            return 3.25;
        };
    }
}

template TB15(T, U) {
    private U initializer;
    private void setInitializer(U init) {
        initializer = init;
    }
    public class B {
        private T _value;
        public this() {
            this._value = initializer.init();
        }
        public T value() {
            return this._value;
        }
    }
}
template TB15(T) {
    private alias TB15!(T, A15!(T).Init) tb;
    private void setInitializer(A15!(T).Init init) {
        tb.setInitializer(init);
    }
    public class B : tb.B {
    }
}

void test15()
{
    alias TB15!(int, A15!(int).Init) tb;
    tb.setInitializer(new A15!(int).Init());
    tb.B b = new tb.B();
    int i;
    i = b.value();
    assert(i == 42);

    alias TB15!(float) tb2;
    tb2.setInitializer(new A15!(float).Init());
    tb2.B b2 = new tb2.B();
    assert(b2.value() == 3.25);
}

/******************************************/

template foo16(U : int, int T : 9+1)
{
    U x = T;
}

alias foo16!(int, 10) bar16;

void test16()
{
    int i;

    i = bar16.x;
    assert(i == 10);
    assert(foo16!(int, 10).x == 10);
}

/******************************************/

template VecTemplate(tfloat)
{
    struct Vector
    {
        tfloat d;
    }
}

void test17()
{
    with (VecTemplate!(int)) // crash DMD
    {
    }
}

/******************************************/

template Bomb (T)
{
   void foo (T *parm)
   {
   }
}

template Name (T)
{
   T y;

   void test ()
   {
      Bomb!(T).foo (&y);
   }
}

alias Name!(int) a18;
alias Name!(ubyte) b18;

void test18()
{
}

/******************************************/

template one20( T )
{
  alias T function () safeptr;
}

template one20( T1, T2 )
{
  alias int function(int) safeptr;
}

alias one20!( int ) A;
A.safeptr foo20;

alias one20!( int, int ) B;
B.safeptr bar20;


int func_bar(int i) { return 2; }

void test20()
{
    bar20 = &func_bar;
}

/******************************************/

class A21 { int x; }
class B21 : A21 { int y; }

void abc21(B21* b) { }

template TFoo21(T : A21, U : T*)
{
    void test()
    {
        assert(T.sizeof == B21.sizeof);
        U u;
        abc21(u);
    }
}

alias TFoo21!(B21, B21*) bar21;

void test21()
{
    bar21.test();
}

/******************************************/

template Bug22(T : Object) {
    int print() {
        printf("Bug22(T : Object).print()\r\n");
        return 1;
    }
}
template Bug22(T) {
    int print() {
        printf("Bug22(T).print()\r\n");
        return 2;
    }
}
template TTest22(T) {
    private alias Bug22!(T) bug;
    class Test {
        int test() {
            return bug.print();
        }
    }
}

void test22()
{
    alias TTest22!(int).Test Test1;
    alias TTest22!(Test1).Test Test2;
    alias TTest22!(Object).Test Test3;
    Test1 test1 = new Test1();
    Test2 test2 = new Test2();
    Test3 test3 = new Test3();
    int i;

    i = test1.test();
    assert(i == 2);
    i = test2.test();
    assert(i == 1);
    i = test3.test();
    assert(i == 1);
}


/******************************************/

template T23()
{
     struct Rank
     {
     }
}

template A23()
{
    struct Array
    {
        alias T23!().Rank Rank1;

        Rank1 data;
    }
}

alias A23!().Array Array_int23;

void test23()
{
}


/******************************************/

template TList24(T)
{
    class Node
    {
    }
    class List
    {
        Node m_first = null;
    }
}

void test24()
{
  alias TList24!(uint).List UIntList;
}


/******************************************/

template TList25(T)
{
    class Node
    {
        Node prev;
        Node next;
        T Value;
    }
    class List
    {
        Node m_first = null;
        Node m_last = null;
        void AddFront(T _Value)
        {
            Node cur = new Node;
            with (cur)
            {
                next = m_first;
                prev = null;
                Value = _Value;
                if (next !is null)
                    next.prev = cur;
            }
            m_first = null;
            if (m_last is null)
                m_last = cur;
        }
    }
}

void test25()
{
  alias TList25!(uint).List UIntList;
  alias TList25!(uint).Node UIntNode;
  UIntList list;
  UIntNode node;
  for (int i = 1; i <= 10; i++)
        {} //list.AddFront(i);
}


/******************************************/

template Foo26(T)
{
    void doIt() {
        printf("Foo26(T)\r\n");
    }
}

template Foo26(T : T[])
{
    private alias Foo26!(T) bug;
    void doIt() {
        printf("Foo26(T[])\r\n");
        bug.doIt();
    }
}

void test26()
{
    alias Foo26!(int[]) foo;
    foo.doIt();
}


/******************************************/

template Foo27(T)
{
    public const T[] empty = [];
}

void test27()
{
    alias Foo27!(int) bug;
}


/******************************************/

template A28(T) {
    public bool all(in T[] array, bool function (T) predicate) {
        for (int i = 0; i < array.length; i++) {
            if (!predicate(array[i])) {
                return false;
            }
        }
        return true;
    }
}

void test28()
{
    static bool isVowel(char c) {
        return (c == 'a') || (c == 'e') || (c == 'i') || (c == 'o') || (c == 'u');
    }

    alias A28!(char) arrays;
    assert(arrays.all("aeiouoeieuiei", &isVowel));
    assert(arrays.all("aeoiuaioeuioaeuiouoiaeu", &isVowel));
    assert(!arrays.all("aaeiouioeujiurioue", &isVowel));
    assert(!arrays.all("bjkqwkjbwqjbkwb", &isVowel));
    assert(arrays.all("", &isVowel));
    printf("A28(char).all tests passed!\r\n");
}


/******************************************/

public template TRange29(T) {
    debug private bool recursing = false;
    public class Range {
        private T _lower;
        private T _upper;
        public this(T lower, T upper) {
            this._lower = lower;
            this._upper = upper;
        }
        public T lower() {
            return this._lower;
        }
        public T upper() {
            return this._upper;
        }
        public bool contains(T item) {
            return (lower() <= item) && (item <= upper());
        }
        public bool intersects(Range other)
        in {
            assert(other !is null);
        } out (result) {
            debug {
                if (!recursing) {
                    recursing = true;
                    assert(result == other.intersects(this));
                } else {
                    recursing = false;
                }
            }
        } do {
            return contains(other.lower()) || contains(other.upper()) || other.includes(this);
        }
        public bool includes(Range other)
        in {
            assert(other !is null);
        } out (result) {
            assert(result == (contains(other.lower()) && contains(other.upper())));
        } do {
            return contains(other.lower()) && contains(other.upper());
        }
    }
}

void test29()
{
    alias TRange29!(int).Range Range;
    Range r1 = new Range(1, 10);
    Range r2 = new Range(5, 15);
    assert(r1.intersects(r2) == 1);
}


/******************************************/

template TCopy30(T)
{
    void copy(out T to, T from)
    {
        to = from;
    }
}

template TCopy30(T : string)
{
    void copy(out string to, in string from)
    {
        printf("Specialization\n");
        to = from;
    }
}

void test30()
{
    int i = 0;
    float f = 0;
    string s;

    alias TCopy30!(int) copyint;
    alias TCopy30!(string) copystr;

    copyint.copy(i, 3);
    printf("%d\n", i);
    assert(i == 3);

    copystr.copy(s, "Here it comes");
    printf("%.*s\n", cast(int)s.length, s.ptr);
    assert(s == "Here it comes");
}

/******************************************/

import core.demangle;

template Foo31(alias X)
{
        alias X.demangle y;
}

void test31()
{
    alias Foo31!(core.demangle) bar;
}


/******************************************/

shared int x32;

template Foo32(alias X)
{
    static shared int* p = &X;
}

alias Foo32!(x32) abc32;

void test32()
{
    alias Foo32!(x32) bar;

    *bar.p = 3;
    assert(x32 == 3);

    *abc32.p = 4;
    assert(x32 == 4);
}

/******************************************/

shared int x33;

template Foo33(alias X)
{
    static shared int* p = &X;
}

template Bar33(alias T)
{
    alias T!(x33) abc;
}

void test33()
{
    alias Bar33!(Foo33) bar;

    *bar.abc.p = 3;
    assert(x33 == 3);
}

/******************************************/

shared int x34;

template Foo34(alias X)
{
    static shared int* p = &X;
}

template Bar34(alias T)
{
    alias T.p q;
}

void test34()
{
    alias Foo34!(x34) foo;
    alias Bar34!(foo) bar;

    *bar.q = 3;
    assert(x34 == 3);
}

/******************************************/

class Foo35
{
    static int p;
}

template Bar35(alias T)
{
    alias T.p q;
}

void test35()
{
    alias Bar35!(Foo35) bar;

    bar.q = 3;
    assert(Foo35.p == 3);
}

/******************************************/

template Bar36(T)
{
    class Bar36
    {
        static T x;
    };
}

void test36()
{
    Bar36!(int).x = 3;
}

/******************************************/

class Bar37(T)
{
    static T x;
}


void test37()
{
    Bar37!(int).x = 3;
}

/******************************************/

class Bar38(T)
{
    static T x = 3;
}


void test38()
{
    int i = template1.Bar38!(int).x;
    assert(i == 3);

    int j = Bar38!(int).x;
    assert(j == 3);
}

/******************************************/

class Bar39(T)
{
    alias T x;
}


void test39()
{
    Bar39!(int).x y = 3;
    assert(y == 3);
}


/******************************************/

template Bar40(T)
{
    alias T Bar40;
}


void test40()
{
    Bar40!(int) y = 3;
    assert(y == 3);
}

/******************************************/

template Bar41(T)
{
    alias T Bar41;
}


void test41()
{
    template1.Bar41!(int) y = 3;
    assert(y == 3);

    assert(template1.Bar41!(int).sizeof == int.sizeof);
}

/******************************************/

template Bar42(T) { T t; }

typeof(Bar42!(int).t) bar42;

void test42()
{
    bar42 = 5;
}

/******************************************/

template factor43(int n : 1)
{
  enum { value = 1 }
}

template factor43(int n)
{
  enum { value = n*factor43!(n-1).value }
}

void test43()
{

  int i = factor43!(3).value;

  printf("%d\n",i);
  assert(i == 6);
}


/******************************************/

template factorial1(int n : 1)
{
    const int x = 1;
}

template factorial1(int n)
{
    const int x = n*.factorial1!(n-1).x;
}

template factorial2(int n : 1)
{
    const int factorial2 = 1;
}

template factorial2(int n)
{
    const int factorial2 = n*.factorial2!(n-1);
}

template factorial3(int n : 1)
{
    enum { x = 1 }
}

template factorial3(int n)
{
    enum { x = n*.factorial3!(n-1).x }
}

template factorial4(int n : 1)
{
    enum { factorial4 = 1 }
}

template factorial4(int n)
{
    enum { factorial4 = n*.factorial4!(n-1) }
}

void test44()
{

  int i = factorial1!(4).x;
  printf("%d\n",i);
  assert(i == 24);

  i = factorial2!(4);
  printf("%d\n",i);
  assert(i == 24);

  i = factorial3!(4).x;
  printf("%d\n",i);
  assert(i == 24);

  i = factorial4!(4);
  printf("%d\n",i);
  assert(i == 24);
}


/******************************************/

template factor45(int n)
{
    int value()
    {
        if (n==0 || n==1)
            return 1;
        return n * factor45!(n-1).value();
    }
}

template factor45(int n : 0)
{
    int value()
    {
        return 1;
    }
}

template factor45(int n : 1)
{
    int value()
    {
        return 1;
    }
}

void test45()
{
    int i;

    i = factor45!(4).value();
    printf( "%d\n", i);
    assert(i == 24);
}


/******************************************/

template sqrt46(int n, int lo, int hi : lo)
{
    enum { result = lo }
}

void test46()
{
    int i;

    i = sqrt46!(1, 24, 24).result;
    printf("i = %d\n", i);
    assert(i == 24);
}

/******************************************/

template sqrt47(int n, int lo, int hi)
{
    enum { mid = (lo + hi + 1) / 2 }

    enum { result = (n < mid * mid) ? sqrt47!(n, lo, mid - 1).result
                                    : sqrt47!(n, mid, hi).result }
}

template sqrt47(int n, int lo, int hi : lo)
{
    enum { result = lo }
}

template sqrt47(int n)
{
    enum { sqrt47 = .sqrt47!(n, 1, n).result }
}

void test47()
{
    int i;

    i = sqrt47!(24);
    printf("i = %d\n", i);
}

/******************************************/

class Foo48 (T)
{
    alias T Type;

    class Inner (U)
    {
        alias U Type;
    };
};

struct Bar48 (alias TT)
{
    alias TT!(int).Type A;
    alias TT!(int).Inner!(A).Type B;
};

void test48()
{
    Bar48!(Foo48).A x;
    Bar48!(Foo48).B y;

    int *p;

    p = &x;
    p = &y;
}


/******************************************/

struct Foo49(T)
{
    static Foo49 bar(T c1)
    {
        Foo49 rtn; // Error here
        return rtn;
    }
}

void test49()
{
    alias Foo49!(double) vector;

    vector.bar(1);
}

/******************************************/

struct Foo50(T)
{
  T x = 0;

  static Foo50 bar(T c1)
  {
    .Foo50!(typeof(c1)) rtn;
    rtn.x = c1;
    return rtn;
  }

  static .Foo50!(T) barx(T c1)
  {
    Foo50 rtn;
    rtn.x = c1;
    return rtn;
  }
}

void test50()
{
  alias Foo50!(double) vector;

  vector xAxis = vector.bar(1);
}

/******************************************/

struct Foo51(T)
{
  T x = 0;
  .Foo51!(long)* p;

  static Foo51 bar(T c1)
  {
    .Foo51!(typeof(c1)) rtn;
    rtn.x = c1;
    return rtn;
  }

  static .Foo51!(T) barx(T c1)
  {
    Foo51 rtn;
    .Foo51!(int)* c;
    rtn.x = c1;
    return rtn;
  }
}

void test51()
{
  alias Foo51!(double) vector;

  vector xAxis = vector.bar(1);
}


/******************************************/

interface Interface(T)
{
    void foo52();
}

void bar52(Interface!(Object) i)
{
    i.foo52();
}

class Abstract(T) : Interface!(T)
{
    abstract void foo52();
}

class Concrete(T) : Abstract!(T)
{
    override void foo52() { printf("Concrete.foo52(this = %p)\n", this); }
}

class Sub(T) : Concrete!(T)
{
}

void test52()
{
    Sub!(Object) s = new Sub!(Object)();
    s.foo52();
    bar52(s);
}


/******************************************/

class Foo53
{
    template tmethod (T)
    {
        public static void tmethod (T param)
        {
            printf("param = %d\n", param);
            assert(param == 42);
        }
    }
}


void test53()
{
    Foo53 foo = new Foo53;

    Foo53.tmethod!(int)(42);
}


/******************************************/

class Foo54
{
   template func(W) {
     static void foo(W w) { printf("W_I %d\n", w); assert(w == 3); }
     static int xx;
   }
}

void test54() {

   Foo54 c = new Foo54();
   c.func!(int).foo(3);
   c.func!(int).xx = 4;

}

/******************************************/

template T55(S)
{
    struct Foo55
    {
        static Foo55 test(Foo55 f)
        {
            Foo55 a = f;
            return f;
        }
    }
}

alias T55!(char).Foo55 Foo55;
alias T55!(char).Foo55 Bar55;


void test55()
{
    Bar55 a;
    Foo55 b;
    b.test(a);
    Bar55.test(a);
}

/******************************************/

template CT56(T)
{
  class C
  {
    const char[][1] arrArr=["foo" ];
  }
}

void test56()
{
  alias CT56!(int) Ct;
  Ct.C c= new Ct.C();
  printf("%.*s\n", cast(int)c.arrArr[0].length, c.arrArr[0].ptr);
  assert(c.arrArr[0] == "foo");
}


/******************************************/

template foo57(T : int = int)
{
    T x = 3;
}

void test57()
{
    printf("%d\n", foo57!().x);
    assert(foo57!().x == 3);
}

/******************************************/

template Foo58(T, U = T)
{
    U x = 3;
}

void test58()
{
    alias Foo58!(int) f;
    assert(f.x == 3);
    assert(f.x.sizeof == 4);
}

/******************************************/

template Foo59(T, U = T*)
{
    shared T x = 3;
    shared U px = &x;
}

void test59()
{
    alias Foo59!(uint) f;
    assert(f.x == 3);
    assert(f.x.sizeof == 4);
    assert(*f.px == 3);

    alias Foo59!(long) g;
    assert(g.x == 3);
    assert(g.x.sizeof == 8);
    assert(*g.px == 3);
}

/******************************************/

class A60
{}

template B60(T, U = short)
{
        struct Thing
        {
                T       t;
                U       u;
        };
}

template C60(T, U = A60)
{
        class C60
                : U
        {}

        class C2
        {};
}

void test60()
{
        B60!(int, long).Thing   thing1;
        B60!(int).Thing         thing2;

        printf("thing1.sizeof: %zu\n", thing1.sizeof);
        printf("thing2.sizeof: %zu\n", thing2.sizeof);

        assert(thing1.sizeof == long.alignof + long.sizeof);
        assert(thing2.sizeof == 8);

        C60!(int /*,A60*/ )     container1;

        printf("container1.sizeof: %zu\n", container1.sizeof);
        assert(container1.sizeof == (void*).sizeof);
}

/******************************************/

struct Foo61
{
    int a;

    template Bar(T)
    {
        T abc() { return a; }
    }

    int def() { return 4; }
}

void test61()
{
    Foo61 *f = new Foo61();
    int i;

    f.a = 3;
    i = f.def();
    assert(i == 4);
    i = f.Bar!(int).abc();
    assert(i == 3);

    Foo61 g;
    g.a = 3;
    i = g.def();
    assert(i == 4);
    i = g.Bar!(int).abc();
    assert(i == 3);
}

/******************************************/

class Foo62(T)
{
    template Bar(T)
    {
        int func() { return 3; }
    }
}

void test62()
{
    Foo62!(int) x = new Foo62!(int);

    assert(x.Bar!(int).func() == 3);
}

/******************************************/

class Foo63(T)
{
    template Bar(T)
    {
        int func() { this.def(); return 3; }
        int func2() { return 4; }
    }

    void def()
    {
        assert(Bar!(T).func2() == 4);
    }
}

void test63()
{
    Foo63!(int) x = new Foo63!(int);

    assert(x.Bar!(int).func() == 3);
    x.def();
}

/******************************************/

struct XVector(qfloat)
{
    qfloat x;qfloat y;qfloat z;

    static int opCall (qfloat x, qfloat y, qfloat z) { return 8; }
}

void test64()
{
    int i;
    i = XVector!(int)(1,2,3);
    assert(i == 8);
    i = XVector!(real).opCall(1,2,3);
    assert(i == 8);
}

/******************************************/
// https://www.digitalmars.com/d/archives/28052.html

alias int value_type;

struct Foo65
{
    uint length() { return 47; }

    size_t test()
    {
        value_type[] e = new value_type[length];
        return e.length;
    }
}

void test65()
{
    Foo65 f;

    assert(f.test() == 47);
}

/******************************************/

class Thing66
{
        template print(T2)
        {
                void print(T2 t)
                {
                    printf("t = %d\n", t);
                    assert(t == 10);
                }
        }
}


void test66()
{
        Thing66 thing = new Thing66;

        thing.print!(int)(10);
}

/******************************************/

template Foo67(alias T)
{
    void Foo67()
    {
        printf("T = '%.*s'\n", cast(int)T.length, T.ptr);
        assert(T == "hello");
    }
}

void test67()
{
    static string x = "hello";

    Foo67!(x)();
}


/******************************************/

template T68(int a) {
    int[a] vec;
}

void test68()
{
        int i;

        i = T68!(4>1?4:1).vec[0];
        assert(i == 0);
        i = T68!(4==1?1:(1==1?4:(4>1?1:4))).vec[0];
        assert(i == 0);
}

/******************************************/

size_t printx(string s)
{
    printf("s = '%.*s'\n", cast(int)s.length, s.ptr);
    return s.length;
}

size_t printx(int i)
{
    printf("i = %d\n", i);
    return 28;
}

template Foo69(alias T)
{
 size_t Foo69()
 {
  return printx(T);
 }
}

void test69()
{
 static string x = "hello";
 static string z = "abc";
 static int y=100;
 size_t i;

 alias Foo69!(x) foox;
 alias Foo69!(y) fooy;

    i = Foo69!(x)();
    assert(i == 5);
    i = Foo69!(y)();
    assert(i == 28);
    i = Foo69!(z)();
    assert(i == 3);
    i = foox();
    assert(i == 5);
    i = fooy();
    assert(i == 28);
}

/******************************************/

template temptt70(alias func)
{
   void temp()
   {
        func();
   }
}

int x70;

void myfunc70()
{
    printf("myfunc70()\n");
    x70 = 6;
}

alias temptt70!(myfunc70).temp foo70;

void test70()
{
   foo70();
   assert(x70 == 6);
}

/******************************************/

struct A71(T)
{
    alias .A71!(T) AT;
    int x;
}

alias A71!(int) Aint71;

void test71()
{
    Aint71.AT a;
    a.x = 3;
}

/******************************************/

template foo72(T)
{
    char[] foo72(T d)
    {
        uint sz = typeof(d[0]).sizeof * 2;
        return null;
    }
}

void test72()
{
    static ulong[5] a = [0,1,2,3,4];
    static uint[5] b = [0,1,2,3,4];
    char[] r;
    r = foo72!(ulong[5])(a); printf("%.*s\n", cast(int)r.length, r.ptr);
    r = foo72!(uint[5])(b);  printf("%.*s\n", cast(int)r.length, r.ptr);
}


/******************************************/

alias int Int73;
class Test73(T = Int73);
alias Test73!() Foo73;

void test73()
{
}

/******************************************/

class A74
{
    alias A74 atype;
    int x;
}


class B74(R, int V = R.sizeof)
{
    int v = V;
}

void test74()
{
    B74!(A74,3) b = new B74!(A74,3)();
    assert(b.v == 3);

    B74!(A74) c = new B74!(A74)();
    assert(c.v == A74.sizeof);
}


/******************************************/

interface NotionalRange75(V)
{
}

class MatchedNotionalRange75(R)
    : NotionalRange75!(R.value_type)
{
}

class Range75
{
    alias   int   value_type;
}

class List75
{

    MatchedNotionalRange75!(Range75) x;
}

void test75()
{
}


/******************************************/

interface Indian(T)
{
}

interface Iterable(T)
{
  Indian!(T) foo();
}

class Lope(T) : Iterable!(T)
{
  Indian!(T) foo()
  {
        return new Corn!(T);
  }
}

class Corn(T) : Indian!(T)
{
}

void test76()
{
  Lope!(int) x = new Lope!(int);
}


/******************************************/

class RawFile
{
}

class Stream : RawFile
{
        template readLineT(T) { bool readLineT()
        {
                if (super)
                        return false;
                return true;
        }}

        bool readLine()
        {
                return readLineT!(int)();
        }
}

void test77()
{
}


/******************************************/

class Four(U, V, X, Y)
{
  U i;  V j;  X k;  Y l;
}

template WhatFour(U,V,X,Y)
{
    int func(Four!(U,V,X,Y) four)
    {
        printf("general template\n");
        return 1;
    }
}

template WhatFour(U:int,V,X,Y)
{
    int func(Four!(int,V,X,Y) four)
    {
        printf("specialization:: first int\n");
        return 2;
    }
}

template WhatFour(U,V:U,X,Y:X)
{
    int func(Four!(U,U,X,X) four)
    {
        printf("specialization:: first two equal, second two equal\n");
        return 3;
    }
}

alias WhatFour!(int,float,char,bool).func whatfour;
alias WhatFour!(float,float,char,bool).func whatfour;
alias WhatFour!(float,float,char,char).func whatfour;
alias WhatFour!(int,int,float,char).func whatfour;  // ambiguous match

void test78()
{ int j;

  Four!(int,float,char,bool) f;
  Four!(float,float,char,bool) g;
  Four!(float,float,char,char) h;
  Four!(int,int,float,char) i;

  j = whatfour(f);
  assert(j == 2);
  j = whatfour(g);
  assert(j == 1);
  j = whatfour(h);
  assert(j == 3);
  j = whatfour(i);
  assert(j == 2);

  /*
  will print:
specialization:: first int
general template
specialization:: first two equal, second two equal
specialization:: first int
  */
}


/******************************************/
// https://www.digitalmars.com/d/archives/digitalmars/D/bugs/2117.html

class Conversion(T,U){
        alias char Small;
        class Big{
                char[2] dummy;
        }
        static Small Test(U u);
        static Big Test(...);
        static T MakeT();
        enum {
                exists = (Test(MakeT())).sizeof == (Small).sizeof
        }
}

void variadicDummy(...){
}

void test79()
{
        variadicDummy(Conversion!(double,int).exists);
}

/******************************************/

class A80(T)
{
   T s;

   int foo(int delegate (T) d) { return 3 + d(s); }

   int bar()
   {
     return foo(delegate int (T t) { return 6 + t.x; });
   }
}

class B80: A80!(B80)
{
    int x = 20;
}

class C80: A80!(C80)
{
    int y = 3;
    int x = 10;
}

void test80()
{
    B80 b = new B80();
    C80 c = new C80();

    b.s = b;
    c.s = c;

    assert(b.bar() == 9+20);
    assert(c.bar() == 9+10);
}

/******************************************/

struct T81(FOO)
{
        S81 s;
}

struct S81
{
        T81!(int)* pt;
}

void test81()
{
}

/******************************************/

T foo82(T : const(U)*, U=char)(T t)
{
    return null;
}

void test82()
{   int i;
    const int ci;

    //writeln(typeid(typeof(foo82(&ci))));
    //writeln(typeid(typeof(foo82(&i))));
    assert(typeof(foo82(&ci)).stringof == "const(int)*");
    assert(typeof(foo82(&i)).stringof == "int*");
}

/******************************************/

struct A83
{
    void foo(int) {}
    void bar(T)(T) {}
}

void test83()
{
    A83 a;
    a.foo = 5;
    a.bar = 6;
}

/******************************************/

int main()
{
    test1();
    test2();
    test3();
    test4();
    test5();
    test6();
    test7();
    test8();
    test9();
    test10();
    test11();
    test12();
    test13();
    test14();
    test15();
    test16();
    test17();
    test18();
//    test19();
    test20();
    test21();
    test22();
    test23();
    test24();
    test25();
    test26();
    test27();
    test28();
    test29();
    test30();
    test31();
    test32();
    test33();
    test34();
    test35();
    test36();
    test37();
    test38();
    test39();
    test40();
    test41();
    test42();
    test43();
    test44();
    test45();
    test46();
    test47();
    test48();
    test49();
    test50();
    test51();
    test52();
    test53();
    test54();
    test55();
    test56();
    test57();
    test58();
    test59();
    test60();
    test61();
    test62();
    test63();
    test64();
    test65();
    test66();
    test67();
    test68();
    test69();
    test70();
    test71();
    test72();
    test73();
    test74();
    test75();
    test76();
    test77();
    test78();
    test79();
    test80();
    test81();
    test82();
    test83();

    printf("Success\n");
    return 0;
}
