// RUNNABLE_PHOBOS_TEST
// PERMUTE_ARGS:

int magicVariable()
{
    if (__ctfe)
        return 3;

    shared int var = 2;
    return var;
}

static assert(magicVariable()==3);

/************************************/
// https://issues.dlang.org/show_bug.cgi?id=11159

void test11159()
{
    import std.math : pow;
    enum ulong
        e_2_pow_64 = 2uL^^64,
        e_10_pow_19 = 10uL^^19,
        e_10_pow_20 = 10uL^^20;
    assert(e_2_pow_64 == pow(2uL, 64));
    assert(e_10_pow_19 == pow(10uL, 19));
    assert(e_10_pow_20 == pow(10uL, 20));
}

// https://issues.dlang.org/show_bug.cgi?id=991 -- invalid.
// https://issues.dlang.org/show_bug.cgi?id=3500 -- is this related to 2127?

// Tests for ^^
// TODO: These tests should not require import std.math.

import std.math;
// Test float ^^ int
static assert( 27.0 ^^ 5 == 27.0 * 27.0 * 27.0 * 27.0 * 27.0);
static assert( 2.0 ^^ 3 == 8.0);

static assert( 2.0 ^^ 4 == 16.0);
static assert( 2 ^^ 4 == 16);

static assert((2 ^^ 8) == 256);
static assert((3 ^^ 8.0) == 6561);
static assert((4.0 ^^ 8) == 65536);
static assert((5.0 ^^ 8.0) == 390625);

static assert((0.5 ^^ 3) == 0.125);
static assert((1.5 ^^ 3.0) == 3.375);
static assert((2.5 ^^ 3) == 15.625);
static assert((3.5 ^^ 3.0) == 42.875);

static assert(((-2) ^^ -5.0) == -0.031250);
static assert(((-2.0) ^^ -6) == 0.015625);
static assert(((-2.0) ^^ -7.0) == -0.0078125);

static assert((144 ^^ 0.5) == 12);
static assert((1089 ^^ 0.5) == 33);
static assert((1764 ^^ 0.5) == 42);
static assert((650.25 ^^ 0.5) == 25.5);

// Check the typing rules.
static assert( is (typeof(2.0^^7) == double));
static assert( is (typeof(7^^3) == int));

static assert( is (typeof(7L^^3) == long));
static assert( is (typeof(7^^3L) == long));
enum short POW_SHORT_1 = 3;
enum short POW_SHORT_3 = 7;
static assert( is (typeof(POW_SHORT_1 * POW_SHORT_1) ==
typeof(POW_SHORT_1*POW_SHORT_1)));

static assert( is (typeof(7.0^^3) == double));
static assert( is (typeof(7.0L^^3) == real));
static assert( is (typeof(7.0f^^3) == float));
static assert( is (typeof(POW_SHORT_1^^3.1) == double));
static assert( is (typeof(POW_SHORT_1^^3.1f) == float));
static assert( is (typeof(2.1f ^^ POW_SHORT_1) == float));
static assert( is (typeof(7.0f^^3.1) == double));
static assert( is (typeof(7.0^^3.1f) == double));
static assert( is (typeof(7.0f^^3.1f) == float));
static assert( is (typeof(7.0f^^3.1L) == real));
static assert( is (typeof(7.0L^^3.1f) == real));
// Check typing for special cases
static assert( is (typeof(7.0f^^2) == float));
static assert( is (typeof(7.0f^^2.0) == double));
static assert( is (typeof(7.0f^^8.0) == double));
static assert( is (typeof(1^^0.5f) == float));
static assert( is (typeof(7^^0.5f) == float));
static assert( is (typeof(3L^^0.5) == double));
static assert( is (typeof(123^^17.0f) == float));

static assert(POW_SHORT_1 ^^ 2 == 9);
static assert(4.0 ^^ POW_SHORT_1 == 4.0*4.0*4.0);
static assert(4.0 ^^ 7.0 == 4.0*4.0*4.0*4.0*4.0*4.0*4.0);

// ^^ has higher precedence than multiply
static assert( 2 * 2 ^^ 3 + 1 == 17);
static assert( 2 ^^ 3 * 2 + 1 == 17);
// ^^ has higher precedence than negate
static assert( -2 ^^ 3 * 2 - 1 == -17);

// ^^ is right associative
static assert( 2 ^^ 3 ^^ 2 == 2 ^^ 9);
static assert( 2.0 ^^ -3 ^^ 2 == 2.0 ^^ -9);

// 1 ^^ n is always 1, even if n is negative
static assert( 1 ^^ -5.0 == 1);

// -1.0 ^^ n is either 1 or -1 if n is integral.
static assert( (-1.0) ^^ -5 == -1);
static assert( (-1.0) ^^ -4 == 1);
static assert( (-1.0) ^^ 0 == 1);
// -1.0 ^^ n is otherwise always NaN.
static assert( (-1.0) ^^ -5.5 is double.nan);
static assert( (-1.0) ^^ -4.4 is double.nan);
static assert( (-1.0) ^^ -0.1 is double.nan);

// n ^^ 0 is always 1
static assert( (-5) ^^ 0 == 1);

// n ^^ 1 is always n
static assert( 6.0 ^^ 1 == 6.0);

// n ^^ -1.0 gets transformed into 1.0 / n, even if n is negative
static assert( (-4) ^^ -1.0 == 1.0 / -4);
static assert( 9 ^^ -1.0 == 1.0 / 9);

// Other integers raised to negative powers create an error
static assert( !is(typeof(2 ^^ -5)));
static assert( !is(typeof((-2) ^^ -4)));

// https://issues.dlang.org/show_bug.cgi?id=3535
struct StructWithCtor
{
    this(int _n) {
        n = _n; x = 5;
    }
    this(int _n, float _x) {
        n = _n; x = _x;
    }
    int n;
    float x;
}

int containsAsm()
{
    version (D_InlineAsm_X86)
        asm { nop; }
    else version (D_InlineAsm_X86_64)
        asm { nop; }
    else version (LDC)
    {
        import ldc.llvmasm;
        __asm("", "");
    }
    return 0;
}

enum A = StructWithCtor(1);
enum B = StructWithCtor(7, 2.3);

static assert(A.n == 1);
static assert(A.x == 5.0);
static assert(B.n == 7);
static assert(B.x == 2.3);

int bazra(int x)
{
   StructWithCtor p = StructWithCtor(4);
   return p.n ^^ 3;

}

static assert(bazra(14)==64);

void moreCommaTests()
{
   (containsAsm(), containsAsm());
   auto k = containsAsm();
   for (int i=0; i< k^^2; i+=StructWithCtor(1).n) {}
}

// Test copy constructors
struct CopyTest {
   double x;
   this(double a) { x = a * 10.0;}
   this(this) {  x+=2.0;}
}

struct CopyTest2
{
   int x; int x1; int x2; int x3;
   this(int a) { x = a * 2; x1 = 3;}
   this(this) {  x1+=17;}
}


const CopyTest z = CopyTest(5.3);
/+
// TODO: This is not yet supported. But it
// generates an error message instead of wrong-code.
const CopyTest w = z;
static assert(z.x==55.0);
+/

int copytest1()
{
   CopyTest z = CopyTest(3.4);
   CopyTest w = z;
   assert(w.x == 36.0);
   CopyTest2 q = CopyTest2(7);
   CopyTest2 q2 = q;
   CopyTest2 q3 = q2;
   assert(q3.x1 == 37);

  return 123;
}
static assert(copytest1()==123);

// This must not cause a segfault
alias int FILTH;
struct Filth
{
     struct Impl
    {
        FILTH * handle = null;
        this(FILTH* h, uint r, string n)
        {
            handle = h;
        }
    }
    Impl * p;

    this(string name, in char[] stdioOpenmode = "rb")
    {
    }

    ~this()
    {
        if (!p) return;
    }

    this(this)
    {
        if (!p) return;
    }
    }
    struct InputByChar
    {
        private Filth _f;

        this(Filth f)
        {
            _f = f;
        }
}


static int nastyForCtfe=4;

// Can't use a global variable
static assert(!is(typeof( (){ static assert(0!=nastyForCtfe^^2); })));

int anotherPowTest()
{
   double x = 5.0;
   return x^^4 > 2.0 ? 3: 2;
}

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

void main()
{
    assert(!__ctfe);
    assert(magicVariable()==2);
    test11159();
}
