// RUN: %target-swift-frontend -emit-sil -primary-file %s -o /dev/null -verify
// RUN: %target-swift-frontend -emit-sil -primary-file %s -o /dev/null -verify
//
// These are tests for diagnostics produced by constant propagation pass
// on floating-point operations.

import StdlibUnittest

func testFPToIntConversion() {
  _blackHole(Int8(-1.28E2))
  _blackHole(Int8(-128.5)) // the result is -128 and is not an overflow
  _blackHole(Int8(1.27E2))
  _blackHole(Int8(-0))
  _blackHole(Int8(3.33333))
  _blackHole(Int8(-2E2)) // expected-error {{invalid conversion: '-2E2' overflows 'Int8'}}

  _blackHole(UInt8(2E2))
  _blackHole(UInt8(3E2)) // expected-error {{invalid conversion: '3E2' overflows 'UInt8'}}
  _blackHole(UInt8(-0E0))
  _blackHole(UInt8(-2E2)) // expected-error {{negative literal '-2E2' cannot be converted to 'UInt8'}}

  _blackHole(Int8(1E6000)) // expected-error {{invalid conversion: '1E6000' overflows 'Int8'}}
                           // expected-warning@-1 {{'1E6000' overflows to inf because its magnitude exceeds the limits of a float literal}}

  _blackHole(UInt8(1E6000)) // expected-error {{invalid conversion: '1E6000' overflows 'UInt8'}}
                            // expected-warning@-1 {{'1E6000' overflows to inf because its magnitude exceeds the limits of a float literal}}

  _blackHole(Int16(3.2767E4))
  _blackHole(Int16(3.2768E4)) // expected-error {{invalid conversion: '3.2768E4' overflows 'Int16'}}
  _blackHole(Int16(-4E4)) // expected-error {{invalid conversion: '-4E4' overflows 'Int16'}}

  _blackHole(UInt16(6.5535E4))
  _blackHole(UInt16(6.5536E4)) // expected-error {{invalid conversion: '6.5536E4' overflows 'UInt16'}}
  _blackHole(UInt16(7E4)) // expected-error {{invalid conversion: '7E4' overflows 'UInt16'}}
  _blackHole(UInt16(-0E0))
  _blackHole(UInt16(-2E2)) // expected-error {{negative literal '-2E2' cannot be converted to 'UInt16'}}

  _blackHole(Int32(-2.147483648E9))
  _blackHole(Int32(-2.147483649E9)) // expected-error {{invalid conversion: '-2.147483649E9' overflows 'Int32'}}
  _blackHole(Int32(3E9)) // expected-error {{invalid conversion: '3E9' overflows 'Int32'}}

  _blackHole(UInt32(4.294967295E9))
  _blackHole(UInt32(4.294967296E9)) // expected-error {{invalid conversion: '4.294967296E9' overflows 'UInt32'}}
  _blackHole(UInt32(5E9)) // expected-error {{invalid conversion: '5E9' overflows 'UInt32'}}
  _blackHole(UInt32(-0E0))
  _blackHole(UInt32(-2E2)) // expected-error {{negative literal '-2E2' cannot be converted to 'UInt32'}}

  _blackHole(Int64(9.223372036854775E18))

  // A case where the imprecision due to the implicit conversion of
  // float literals to 'Double' results in an overflow.
  _blackHole(Int64(9.223372036854775807E18)) // expected-error {{invalid conversion: '9.223372036854775807E18' overflows 'Int64'}}

  // A case where implicit conversion of the float literal to 'Double'
  // elides an overflow that one would expect during conversion to 'Int64'.
  _blackHole(Int64(-9.223372036854775809E18))

  // Cases of definite overflow.
  _blackHole(Int64(9.223372036854775808E18)) // expected-error {{invalid conversion: '9.223372036854775808E18' overflows 'Int64'}}
  _blackHole(Int64(1E19)) // expected-error {{invalid conversion: '1E19' overflows 'Int64'}}

  // A case where implicit conversion of the float literal to 'Double'
  // results in an overflow during conversion to 'UInt64''.
  _blackHole(UInt64(1.844674407370955E19))
  _blackHole(UInt64(1.8446744073709551615E19)) // expected-error {{invalid conversion: '1.8446744073709551615E19' overflows 'UInt64'}}

  _blackHole(UInt64(2E19)) // expected-error {{invalid conversion: '2E19' overflows 'UInt64'}}
  _blackHole(UInt64(-0E0))
  _blackHole(UInt64(-2E2)) // expected-error {{negative literal '-2E2' cannot be converted to 'UInt64'}}

  _blackHole(Int64(1E6000)) // expected-error {{invalid conversion: '1E6000' overflows 'Int64'}}
                            // expected-warning@-1 {{'1E6000' overflows to inf because its magnitude exceeds the limits of a float literal}}

  _blackHole(UInt64(1E6000)) // expected-error {{invalid conversion: '1E6000' overflows 'UInt64'}}
                             // expected-warning@-1 {{'1E6000' overflows to inf because its magnitude exceeds the limits of a float literal}}
}

func testFloatConvertOverflow() {
  let f1: Float = 1E38
  _blackHole(f1)
  let f2: Float = 1E39 // expected-warning {{'1E39' overflows to inf during conversion to 'Float'}}
  _blackHole(f2)
  let f3: Float = 1234567891012345678912345671234561234512.0 // expected-warning {{'1234567891012345678912345671234561234512.0' overflows to inf during conversion to 'Float'}}
  _blackHole(f3)
  let f4: Float = 0.1234567891012345678912345671234561234512
  _blackHole(f4)
  let f5: Float32 = -3.4028236E+38 // expected-warning {{'-3.4028236E+38' overflows to -inf during conversion to 'Float32' (aka 'Float')}}
  _blackHole(f5)

  // Diagnositcs for Double truncations have architecture dependent
  // messages. See _nonx86 and _x86 test files.
  let d1: Double = 1E308
  _blackHole(d1)
  let d2: Double = 1234567891012345678912345671234561234512.0
  _blackHole(d2)

  // All warnings are disabled during explicit conversions.
  // Except when the number is so large that it wouldn't even fit into largest
  // FP type available.
  _blackHole(Float(1E38))
  _blackHole(Float(1E39))
  _blackHole(Float(100000000000000000000000000000000000000000000000.0))
  _blackHole(Double(1E308))
  _blackHole(Float(1E6000)) // expected-warning {{'1E6000' overflows to inf because its magnitude exceeds the limits of a float literal}}
  _blackHole(Float(-1E6000)) // expected-warning {{'-1E6000' overflows to -inf because its magnitude exceeds the limits of a float literal}}
  _blackHole(Double(1E6000)) // expected-warning {{'1E6000' overflows to inf because its magnitude exceeds the limits of a float literal}}
}

func testFloatConvertUnderflow() {
  let f0: Float =  0.500000006364665322827
  _blackHole(f0)
  let f1: Float = 1E-37
  _blackHole(f1)
  let f2: Float = 1E-39  // expected-warning {{'1E-39' underflows and loses precision during conversion to 'Float'}}
  _blackHole(f2)
  let f3: Float = 1E-45 // expected-warning {{'1E-45' underflows and loses precision during conversion to 'Float'}}
  _blackHole(f3)

  // A number close to 2^-150 (smaller than least non-zero float: 2^-149)
  let f6: Float = 7.0064923E-46  // expected-warning {{'7.0064923E-46' underflows and loses precision during conversion to 'Float'}}
  _blackHole(f6)

  // Some cases where tininess doesn't cause extra imprecision.

  // A number so close to 2^-130 that 2^-130 is its best approximation
  // even in Float80.
  let f4: Float = 7.3468396926392969248E-40
  _blackHole(f4)
  // A number very close to 2^-149.
  let f5: Float = 1.4012984821624085566E-45
  _blackHole(f5)

  let f7: Float = 1.1754943E-38 // expected-warning {{'1.1754943E-38' underflows and loses precision during conversion to 'Float'}}
  _blackHole(f7)
  let f8: Float = 1.17549428E-38 // expected-warning {{'1.17549428E-38' underflows and loses precision during conversion to 'Float'}}
  _blackHole(f8)

  let d1: Double = 1E-307
  _blackHole(d1)

   // All warnings are disabled during explict conversions.
  _blackHole(Float(1E-37))
  _blackHole(Float(1E-39))
  _blackHole(Float(1E-45))
  _blackHole(Double(1E-307))
}

func testHexFloatImprecision() {
  let f1: Float = 0x0.800000p-126
  _blackHole(f1)
  // Smallest Float subnormal number.
  let f2: Float = 0x0.000002p-126
  _blackHole(f2)
  let f3: Float = 0x1.000002p-127 // expected-warning {{'0x1.000002p-127' loses precision during conversion to 'Float'}}
  _blackHole(f3)
  let f4: Float = 0x1.000001p-127 // expected-warning {{'0x1.000001p-127' loses precision during conversion to 'Float'}}
  _blackHole(f4)
  let f5: Float = 0x1.0000002p-126 // expected-warning {{'0x1.0000002p-126' loses precision during conversion to 'Float'}}
  _blackHole(f5)

  // In the following cases, the literal is truncated to a Float through a
  // (lossless) conversion to Double. There should be no warnings here.
  let t1: Double = 0x1.0000002p-126
  _blackHole(Float(t1))
  let t2: Double = 0x1.000001p-126
  _blackHole(Float(t2))
  let t3 = 0x1.000000fp25
  _blackHole(Float(t3))

  let d1: Double = 0x0.8p-1022
  _blackHole(d1)
  // Smallest non-zero number representable in Double.
  let d2: Double = 0x0.0000000000001p-1022
  _blackHole(d2)
  let d3: Double = 0x1p-1074
  _blackHole(d3)

  // Test the case where conversion results in subnormality in the destination.
  let d4: Float = 0x1p-149
  _blackHole(d4)
  let d5: Float = 0x1.8p-149 // expected-warning {{'0x1.8p-149' loses precision during conversion to 'Float}}
  _blackHole(d5)

  // All warnings are disabled during explict conversions.
  _blackHole(Float(0x1.000002p-126))
  _blackHole(Float(0x1.0000002p-126))
  _blackHole(Float(0x1.000002p-127))
  _blackHole(Float(0x1.000001p-127))
  _blackHole(Float(Double(0x1.000000fp25)))
  _blackHole(Double(0x1p-1074))
}

func testFloatArithmetic() {
  // Ignore inf and Nan during arithmetic operations.
  // This may become a warning in the future.
  let infV: Float = 3.0 / 0.0
  _blackHole(infV)

  let a: Float = 1E38
  let b: Float = 10.0
  _blackHole(a * b)
}

func testIntToFloatConversion() {
  let f1: Float = 16777216
  _blackHole(f1)

  let f2: Float = 1_000_000_000_000 // expected-warning {{'1000000000000' is not exactly representable as 'Float'; it becomes '999999995904'}}
  _blackHole(f2)

  // First positive integer that cannot be precisely represented in Float: 2^24 + 1
  let f3: Float = 16777217 // expected-warning {{'16777217' is not exactly representable as 'Float'; it becomes '16777216'}}
  _blackHole(f3)

  let d1: Double = 9_007_199_254_740_992 // This value is 2^53
  _blackHole(d1)

  let d2: Double = 9_007_199_254_740_993 // expected-warning {{'9007199254740993' is not exactly representable as 'Double'; it becomes '9007199254740992'}}
  _blackHole(d2)

   // No warnings are emitted for conversion through explicit constructor calls.
  _blackHole(Float(16777217))
  _blackHole(Double(2_147_483_647))
}
