mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
939 lines
22 KiB
Swift
939 lines
22 KiB
Swift
// Source Input used by constant_evaluable_subset_test.swift and constant_evaluable_profiler_test.swift
|
|
// Test Swift code snippets that are expected to be constant evaluable and those
|
|
// that are not. If any of the test here fails, it indicates a change in the
|
|
// output of SILGen or the mandatory passes that affects the constant
|
|
// evaluability of the corresponding Swift code.
|
|
|
|
// CHECK-LABEL: @leftShift
|
|
// CHECK-NOT: error:
|
|
@_semantics("constant_evaluable")
|
|
internal func leftShift(x: Int, y: Int) -> Int {
|
|
return x &<< y
|
|
}
|
|
|
|
// The test driver must only call functions marked as constant evaluable
|
|
// with literal arguments.
|
|
@_semantics("test_driver")
|
|
internal func interpretLeftShiftTest() -> Int {
|
|
return leftShift(x: 10, y: 2)
|
|
}
|
|
|
|
// CHECK-LABEL: @leftShiftWithTraps
|
|
// CHECK-NOT: error:
|
|
// This is an expensive function to evaluate requiring evaluating approximately
|
|
// 1024 instructions.
|
|
@_semantics("constant_evaluable")
|
|
internal func leftShiftWithTraps(x: Int, y: Int) -> Int {
|
|
return x << y
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
internal func interpretLeftShiftWithTraps() -> Int {
|
|
return leftShiftWithTraps(x: 34, y: 3)
|
|
}
|
|
|
|
// CHECK-LABEL: @rightShift
|
|
// CHECK-NOT: error:
|
|
@_semantics("constant_evaluable")
|
|
internal func rightShift(x: Int, y: Int) -> Int {
|
|
return x &>> y
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
internal func interpretRightShift() -> Int {
|
|
return rightShift(x: 10, y: 2)
|
|
}
|
|
|
|
// CHECK-LABEL: @rightShiftWithTraps
|
|
// CHECK-NOT: error:
|
|
// This is an expensive function to evaluate requiring evaluating approximately
|
|
// 1024 instructions.
|
|
@_semantics("constant_evaluable")
|
|
internal func rightShiftWithTraps(x: Int, y: Int) -> Int {
|
|
return x >> y
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
internal func interpretRightShiftWithTraps() -> Int {
|
|
return rightShiftWithTraps(x: 34, y: 3)
|
|
}
|
|
|
|
// CHECK-LABEL: @arithmetic
|
|
// CHECK-NOT: error:
|
|
@_semantics("constant_evaluable")
|
|
internal func arithmetic(x: Int, y: Int) -> Int {
|
|
let z = x + y
|
|
let w = x &+ z
|
|
let a = w * y
|
|
let b = a &* z
|
|
let c = b - a
|
|
let d = c &- x
|
|
let e = x / d
|
|
return e
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
internal func interpretArithmetic() -> Int {
|
|
return arithmetic(x: 142, y: 212)
|
|
}
|
|
|
|
// CHECK-LABEL: @booleanoperations
|
|
// CHECK-NOT: error:
|
|
@_semantics("constant_evaluable")
|
|
internal func booleanoperations(a: Bool, b: Bool) -> Bool {
|
|
return (a && b) || (a || b) && !a
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
internal func interpretBooleanOperations() -> Bool {
|
|
return booleanoperations(a: true, b: false)
|
|
}
|
|
|
|
// CHECK-LABEL: @comparisons
|
|
// CHECK-NOT: error:
|
|
@_semantics("constant_evaluable")
|
|
internal func comparisons(a: Int, b: Int, c: Int8, d: Int8) -> Bool {
|
|
let r1 = a < b
|
|
let r2 = c > d
|
|
return r1 && r2
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
internal func interpretComparisons() -> Bool {
|
|
return comparisons(a: 20, b: 55, c: 56, d: 101)
|
|
}
|
|
|
|
// CHECK-LABEL: @heterogenousIntComparisons
|
|
// CHECK-NOT: error:
|
|
@_semantics("constant_evaluable")
|
|
internal func heterogenousIntComparisons(a: Int, b: Int16, c: Int8) -> Bool {
|
|
return (a < b) && (c < b)
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
internal func interpretHeterogenousComparisons() -> Bool {
|
|
return heterogenousIntComparisons(a: 101, b: 20, c: 56)
|
|
}
|
|
|
|
// CHECK-LABEL: @bitwiseOperations
|
|
// CHECK-NOT: error:
|
|
@_semantics("constant_evaluable")
|
|
internal func bitwiseOperations(a: Int16, b: Int16, c: Int16) -> Int16 {
|
|
return a & ((b | c) | ~c)
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
internal func interpretBitWiseOperations() -> Int16 {
|
|
return bitwiseOperations(a: 0xff, b: 0xef, c: 0x7fef)
|
|
}
|
|
|
|
// CHECK-LABEL: @testIntExtensions
|
|
// CHECK-NOT: error:
|
|
@_semantics("constant_evaluable")
|
|
internal func testIntExtensions(a: Int8, b: Int16) -> Int32 {
|
|
return Int32(a) + Int32(b) + Int32(Int16(a))
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
internal func interpretIntExtensions() -> Int32 {
|
|
return testIntExtensions(a: 100, b: -130)
|
|
}
|
|
|
|
// CHECK-LABEL: @testUIntExtensions
|
|
// CHECK-NOT: error:
|
|
@_semantics("constant_evaluable")
|
|
internal func testUIntExtensions(a: UInt8, b: UInt16) -> UInt32 {
|
|
return UInt32(a) + UInt32(b) + UInt32(UInt16(a))
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
internal func interpretUIntExtensions() -> UInt32 {
|
|
return testUIntExtensions(a: 100, b: 130)
|
|
}
|
|
|
|
// CHECK-LABEL: @testIntTruncations
|
|
// CHECK-NOT: error:
|
|
// This is an expensive function to evaluate requiring evaluating approximately
|
|
// 2048 instructions with optimized stdlib and 3000 instructions with
|
|
// unoptimized stdlib.
|
|
@_semantics("constant_evaluable")
|
|
internal func testIntTruncations(a: Int32) -> Int8 {
|
|
let b = Int16(a)
|
|
let c = Int8(b)
|
|
return c
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
internal func interpretIntTruncations() -> Int8 {
|
|
return testIntTruncations(a: 100)
|
|
}
|
|
|
|
// CHECK-LABEL: @testInvalidIntTruncations
|
|
// CHECK: error: not constant evaluable
|
|
@_semantics("constant_evaluable")
|
|
internal func testInvalidIntTruncations(a: Int32) -> Int8 {
|
|
return Int8(a)
|
|
// CHECK: note: {{.*}}: Not enough bits to represent the passed value
|
|
// CHECK: note: operation traps
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
internal func interpretInvalidIntTruncations() -> Int8 {
|
|
return testInvalidIntTruncations(a: 130)
|
|
}
|
|
|
|
// CHECK-LABEL: @testUIntTruncations
|
|
// CHECK-NOT: error:
|
|
// This is an expensive function to evaluate requiring evaluating approximately
|
|
// 2048 instructions.
|
|
@_semantics("constant_evaluable")
|
|
internal func testUIntTruncations(a: UInt32) -> UInt8 {
|
|
let b = UInt32(a)
|
|
let c = UInt16(b)
|
|
let d = UInt8(c)
|
|
return d
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
internal func interpretUIntTruncations() -> UInt8 {
|
|
return testUIntTruncations(a: 100)
|
|
}
|
|
|
|
// CHECK-LABEL: @testSingedUnsignedConversions
|
|
// CHECK-NOT: error:
|
|
// This is an expensive function to evaluate requiring evaluating approximately
|
|
// 2048 instructions.
|
|
@_semantics("constant_evaluable")
|
|
internal func testSingedUnsignedConversions(a: Int32, b: UInt8) -> UInt32 {
|
|
return UInt32(a) + UInt32(Int8(b))
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
internal func interpretSingedUnsignedConversions() -> UInt32 {
|
|
return testSingedUnsignedConversions(a: 100, b: 120)
|
|
}
|
|
|
|
// CHECK-LABEL: @testInvalidSingedUnsignedConversions
|
|
// CHECK: error: not constant evaluable
|
|
@_semantics("constant_evaluable")
|
|
internal func testInvalidSingedUnsignedConversions(a: Int64) -> UInt64 {
|
|
return UInt64(a)
|
|
// CHECK: note: {{.*}}: Negative value is not representable
|
|
// CHECK: note: operation traps
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
internal func interpretInvalidSingedUnsignedConversions() -> UInt64 {
|
|
return testInvalidSingedUnsignedConversions(a: -130)
|
|
}
|
|
|
|
// CHECK-LABEL: @testIO
|
|
// CHECK: error: not constant evaluable
|
|
@_semantics("constant_evaluable")
|
|
internal func testIO() -> String? {
|
|
return readLine()
|
|
// CHECK: note: encountered call to 'readLine(strippingNewline:)' whose body is not available
|
|
// CHECK: note: function whose body is not available
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
internal func interpretIO() -> String? {
|
|
return testIO()
|
|
}
|
|
|
|
// CHECK-LABEL: @testLoop
|
|
// CHECK: error: not constant evaluable
|
|
@_semantics("constant_evaluable")
|
|
func testLoop() -> Int {
|
|
var x = 0
|
|
while x <= 42 {
|
|
x += 1
|
|
}
|
|
return x
|
|
// CHECK: note: control-flow loop found during evaluation
|
|
// CHECK: note: found loop here
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
internal func interpretLoop() -> Int {
|
|
return testLoop()
|
|
}
|
|
|
|
// CHECK-LABEL: @testRecursion
|
|
// CHECK-NOT: error:
|
|
@_semantics("constant_evaluable")
|
|
func testRecursion(_ a: Int) -> Int {
|
|
return a <= 0 ? 0 : testRecursion(a-1)
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
internal func interpretRecursion() -> Int {
|
|
return testRecursion(10)
|
|
}
|
|
|
|
// CHECK-LABEL: @testLongRecursion
|
|
// CHECK: error: not constant evaluable
|
|
@_semantics("constant_evaluable")
|
|
func testLongRecursion(_ a: Int) -> Int {
|
|
return a == 0 ? 0 : testLongRecursion(a-1)
|
|
// CHECK: note: exceeded instruction limit:
|
|
// CHECK: note: limit exceeded here
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
internal func interpretLongRecursion() -> Int {
|
|
return testLongRecursion(-100)
|
|
}
|
|
|
|
// CHECK-LABEL: @testConditional
|
|
// CHECK-NOT: error:
|
|
@_semantics("constant_evaluable")
|
|
func testConditional(_ x: Int) -> Int {
|
|
if x < 0 {
|
|
return 0
|
|
} else {
|
|
return x
|
|
}
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
func interpretConditional() -> Int {
|
|
testConditional(-1)
|
|
}
|
|
|
|
// CHECK-LABEL: @testIntAddOverflow
|
|
// CHECK: error: not constant evaluable
|
|
@_semantics("constant_evaluable")
|
|
func testIntAddOverflow(_ x: Int8) -> Int8 {
|
|
return x + 1
|
|
// CHECK: note: integer overflow detected
|
|
// CHECK: note: operation overflows
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
func interpretIntAddOverflow() -> Int8 {
|
|
return testIntAddOverflow(127)
|
|
}
|
|
|
|
// CHECK-LABEL: @testDivideByZero
|
|
// CHECK: error: not constant evaluable
|
|
@_semantics("constant_evaluable")
|
|
func testDivideByZero(_ x: Int, _ y: Int) -> Int {
|
|
return x / y
|
|
// CHECK: note: {{.*}}: Division by zero
|
|
// CHECK: note: operation traps
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
func interpretDivideByZero() -> Int {
|
|
return testDivideByZero(127, 0)
|
|
}
|
|
|
|
// CHECK-LABEL: @testDividingFullWidthByZero
|
|
// CHECK: error: not constant evaluable
|
|
@_semantics("constant_evaluable")
|
|
func testDividingFullWidthByZero(_ x: Int, _ y: Int, _ z: UInt) -> Int {
|
|
return x.dividingFullWidth((y, z)).1
|
|
} // CHECK: note: {{.*}}: Division by zero
|
|
// CHECK: note: operation performed during this call traps
|
|
|
|
@_semantics("test_driver")
|
|
func interpretDividingFullWidthByZero() -> Int {
|
|
return testDividingFullWidthByZero(0, 1, 1)
|
|
}
|
|
|
|
// CHECK-LABEL: @testDivideOverflow
|
|
// CHECK: error: not constant evaluable
|
|
@_semantics("constant_evaluable")
|
|
func testDivideOverflow(_ x: Int8, _ y: Int8) -> Int8 {
|
|
return x / y
|
|
// CHECK: note: {{.*}}: Division results in an overflow
|
|
// CHECK: note: operation traps
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
func interpretDivideOverflow() -> Int8 {
|
|
return testDivideOverflow(-128, -1)
|
|
}
|
|
|
|
// CHECK-LABEL: @testDistance
|
|
// CHECK: error: not constant evaluable
|
|
@_semantics("constant_evaluable")
|
|
func testDistance(_ x: UInt, _ y: UInt) -> Int {
|
|
return x.distance(to: y)
|
|
// CHECK: note: {{.*}}: Distance is not representable in Int
|
|
// CHECK: note: operation performed during this call traps
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
func interpretDistanceTest() -> Int {
|
|
return testDistance(0, UInt.max)
|
|
}
|
|
|
|
// CHECK-LABEL: @testInOut
|
|
// CHECK-NOT: error:
|
|
@_semantics("constant_evaluable")
|
|
func testInOut(_ x: inout Int) {
|
|
x += 1
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
func interpretInOut() -> Int {
|
|
var x = 10
|
|
testInOut(&x)
|
|
return x
|
|
}
|
|
|
|
struct A {
|
|
var x, y: Int
|
|
|
|
// CHECK-LABEL: @init(initialValue: Int) -> A
|
|
// CHECK-NOT: error:
|
|
@_semantics("constant_evaluable")
|
|
init(initialValue: Int) {
|
|
x = initialValue
|
|
y = initialValue
|
|
}
|
|
|
|
// CHECK-LABEL: @sum
|
|
// CHECK-NOT: error:
|
|
@_semantics("constant_evaluable")
|
|
@_optimize(none)
|
|
func sum() -> Int {
|
|
return x + y
|
|
}
|
|
|
|
// CHECK-LABEL: @increment
|
|
// CHECK-NOT: error:
|
|
@_semantics("constant_evaluable")
|
|
@_optimize(none)
|
|
mutating func increment(by step: Int) {
|
|
x += step
|
|
y += step
|
|
}
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
func interpretStructInitAndMethods() -> A {
|
|
var a = A(initialValue: 0)
|
|
let z = a.sum();
|
|
a.increment(by: z)
|
|
return a
|
|
}
|
|
|
|
struct OuterStruct {
|
|
var inner: A
|
|
var z: Int
|
|
|
|
// CHECK-LABEL: @sumInner
|
|
// CHECK-NOT: error:
|
|
@_semantics("constant_evaluable")
|
|
@_optimize(none)
|
|
func sumInner() -> Int {
|
|
return inner.sum()
|
|
}
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
func interpretNestedStructAndDefaultInit() -> Int {
|
|
let ostruct = OuterStruct(inner: A(initialValue: 1), z: 10)
|
|
return ostruct.sumInner()
|
|
}
|
|
|
|
struct EmptyStruct {
|
|
func get() -> Int {
|
|
return 0
|
|
}
|
|
}
|
|
|
|
// CHECK-LABEL: @testEmptyStruct
|
|
// CHECK-NOT: error:
|
|
@_semantics("constant_evaluable")
|
|
func testEmptyStruct() -> Int {
|
|
let emp = EmptyStruct()
|
|
return emp.get()
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
func interpretEmptyStructTest() -> Int {
|
|
return testEmptyStruct()
|
|
}
|
|
|
|
// CHECK-LABEL: @testTuple
|
|
// CHECK-NOT: error:
|
|
@_semantics("constant_evaluable")
|
|
func testTuple(_ a: Int, _ b: Bool) -> Bool {
|
|
func extractSecond(_ tuple: (Int, Bool)) -> Bool {
|
|
return tuple.1
|
|
}
|
|
return extractSecond((a, b))
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
func interpretTuple() -> Bool {
|
|
return testTuple(10, false)
|
|
}
|
|
|
|
// CHECK-LABEL: @testGenericFunction
|
|
// CHECK-NOT: error:
|
|
@_semantics("constant_evaluable")
|
|
func testGenericFunction<T: Equatable>(_ a: T, _ b: T) -> Bool {
|
|
return a == b
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
func interpretGenericFunction() -> Bool {
|
|
return testGenericFunction(10, 11)
|
|
}
|
|
|
|
protocol P {
|
|
mutating func clear() -> Int
|
|
}
|
|
|
|
struct PImpl: P {
|
|
var i = 100
|
|
mutating func clear() -> Int {
|
|
let prev = i
|
|
i = 0
|
|
return prev
|
|
}
|
|
}
|
|
|
|
// CHECK-LABEL: @testCustomGenericConstraint
|
|
// CHECK-NOT: error:
|
|
@_semantics("constant_evaluable")
|
|
func testCustomGenericConstraint<T: P>(_ a: inout T) -> Int {
|
|
return a.clear()
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
func interpretCustomGenericConstraint() -> Int {
|
|
var s = PImpl();
|
|
return testCustomGenericConstraint(&s)
|
|
}
|
|
|
|
// CHECK-LABEL: @testProtocolMethodDispatch
|
|
// CHECK: error: not constant evaluable
|
|
@_semantics("constant_evaluable")
|
|
func testProtocolMethodDispatch(_ s: PImpl) -> Int {
|
|
func innerFunc(_ proto: P) -> Int {
|
|
var tmp = proto
|
|
return tmp.clear()
|
|
}
|
|
return innerFunc(s)
|
|
// CHECK: note: encountered operation not supported by the evaluator: init_existential_addr
|
|
// CHECK: note: operation not supported by the evaluator
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
func interpretProtocolMethodDispatch() -> Int {
|
|
return testProtocolMethodDispatch(PImpl())
|
|
}
|
|
|
|
struct SGeneric<X, Y> {
|
|
var x: X
|
|
var y: Y
|
|
|
|
// CHECK-LABEL: @methodWithGeneric
|
|
// CHECK-NOT: error:
|
|
@_semantics("constant_evaluable")
|
|
@_optimize(none)
|
|
func methodWithGeneric<Z>(_ z: Z) -> SGeneric<Z, Y> {
|
|
return SGeneric<Z, Y>(x: z, y: y)
|
|
}
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
func interpretStructAndMethodWithGeneric() -> SGeneric<Int, Bool> {
|
|
let s = SGeneric<Int8, Bool>(x: 10, y: true)
|
|
return s.methodWithGeneric(240)
|
|
}
|
|
|
|
protocol ProtoWithInit {
|
|
init(_ x: Int)
|
|
}
|
|
|
|
struct C : ProtoWithInit {
|
|
init(_ x: Int) {
|
|
}
|
|
}
|
|
|
|
// CHECK-LABEL: @testGenericConstruction
|
|
// CHECK-NOT: error:
|
|
@_semantics("constant_evaluable")
|
|
func testGenericConstruction<T: ProtoWithInit>(_: T.Type) -> T {
|
|
return T(0)
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
func interpretGenericConstruction() -> C {
|
|
return testGenericConstruction(C.self)
|
|
}
|
|
|
|
// CHECK-LABEL: @testSupportedStringOperations
|
|
// CHECK-NOT: error:
|
|
@_semantics("constant_evaluable")
|
|
func testSupportedStringOperations(_ x: String, _ y: String) -> Bool {
|
|
var z = x
|
|
z += y
|
|
return z == x
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
func interpretSupportedStringOperations() -> Bool {
|
|
return testSupportedStringOperations("abc", "zyx")
|
|
}
|
|
|
|
// CHECK-LABEL: @testOptional
|
|
// CHECK-NOT: error:
|
|
@_semantics("constant_evaluable")
|
|
func testOptional(_ xopt: String?) -> String {
|
|
if let x = xopt {
|
|
return x
|
|
}
|
|
return ""
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
func interpretOptionalTest() -> String {
|
|
return testOptional("a")
|
|
}
|
|
|
|
enum Side {
|
|
case right
|
|
case left
|
|
}
|
|
|
|
// CHECK-LABEL: @testEnumSwitch
|
|
// CHECK-NOT: error:
|
|
@_semantics("constant_evaluable")
|
|
func testEnumSwitch(_ side: Side) -> Int {
|
|
switch side {
|
|
case .right:
|
|
return 1
|
|
case .left:
|
|
return 0
|
|
}
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
func interpretEnumSwitch() -> Int {
|
|
return testEnumSwitch(.right)
|
|
}
|
|
|
|
// CHECK-LABEL: @testEnumEquality
|
|
// CHECK-NOT: error:
|
|
@_semantics("constant_evaluable")
|
|
func testEnumEquality(_ side: Side, _ otherSide: Side) -> Bool {
|
|
return side == otherSide
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
func interpretEnumEquality() -> Bool {
|
|
return testEnumEquality(.right, .left)
|
|
}
|
|
|
|
enum Shape {
|
|
case circle(radius: Int)
|
|
case rectangle(length: Int, breadth: Int)
|
|
}
|
|
|
|
// CHECK-LABEL: @testEnumWithData
|
|
// CHECK-NOT: error:
|
|
@_semantics("constant_evaluable")
|
|
func testEnumWithData(_ shape: Shape) -> Int {
|
|
switch shape {
|
|
case .circle(radius: let x):
|
|
return x
|
|
case .rectangle(length: let x, breadth: let y):
|
|
return x + y
|
|
}
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
func interpretEnumWithData() -> Int {
|
|
return testEnumWithData(.circle(radius: 11))
|
|
}
|
|
|
|
enum Number<T: BinaryInteger> {
|
|
case integer(T)
|
|
case rational(T, T)
|
|
}
|
|
|
|
// CHECK-LABEL: @testAddressOnlyEnum
|
|
// CHECK-NOT: error:
|
|
@_semantics("constant_evaluable")
|
|
func testAddressOnlyEnum<T: BinaryInteger>(_ number: Number<T>) -> T {
|
|
switch number {
|
|
case .integer(let x):
|
|
return x
|
|
case .rational(let x, let y):
|
|
return x + y
|
|
}
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
func interpretAddressOnlyEnum() -> Int {
|
|
return testAddressOnlyEnum(.rational(22, 7))
|
|
}
|
|
|
|
indirect enum Nat {
|
|
case zero
|
|
case succ(Nat)
|
|
}
|
|
|
|
// CHECK-LABEL: @testIndirectEnum
|
|
// CHECK: error: not constant evaluable
|
|
@_semantics("constant_evaluable")
|
|
func testIndirectEnum(_ nat: Nat) -> Bool {
|
|
switch nat {
|
|
case .zero:
|
|
return true
|
|
case .succ:
|
|
return false
|
|
}
|
|
// CHECK-NOTE: note: encountered operation not supported by the evaluator: alloc_box
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
func interpretIndirectEnum() -> Bool {
|
|
return testIndirectEnum(.succ(.zero))
|
|
}
|
|
|
|
// CHECK-LABEL: @testEmptyArrayInit
|
|
// CHECK-NOT: error:
|
|
@_semantics("constant_evaluable")
|
|
func testEmptyArrayInit() -> [Int] {
|
|
return Array<Int>()
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
func interpretEmptyArrayInit() -> [Int] {
|
|
return testEmptyArrayInit()
|
|
}
|
|
|
|
// CHECK-LABEL: @testEmptyArrayLiteral
|
|
// CHECK-NOT: error:
|
|
@_semantics("constant_evaluable")
|
|
func testEmptyArrayLiteral() -> [Int] {
|
|
return []
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
func interpretEmptyArrayLiteral() -> [Int] {
|
|
return testEmptyArrayLiteral()
|
|
}
|
|
|
|
// CHECK-LABEL: @testArrayLiteral
|
|
// CHECK-NOT: error:
|
|
@_semantics("constant_evaluable")
|
|
func testArrayLiteral(_ x: Int, _ y: Int) -> [Int] {
|
|
return [x, y, 4]
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
func interpretArrayLiteral() -> [Int] {
|
|
return testArrayLiteral(2, 3)
|
|
}
|
|
|
|
// CHECK-LABEL: @testArrayAppend
|
|
// CHECK-NOT: error:
|
|
@_semantics("constant_evaluable")
|
|
func testArrayAppend(_ x: Int) -> [Int] {
|
|
var a: [Int] = []
|
|
a.append(x)
|
|
return a
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
func interpretArrayAppend() -> [Int] {
|
|
return testArrayAppend(25)
|
|
}
|
|
|
|
// CHECK-LABEL: @testArrayAppendNonEmpty
|
|
// CHECK-NOT: error:
|
|
@_semantics("constant_evaluable")
|
|
func testArrayAppendNonEmpty(_ x: String) -> [String] {
|
|
var a: [String] = ["ls", "cat", "echo", "cd"]
|
|
a.append(x)
|
|
return a
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
func interpretArrayAppendNonEmpty() -> [String] {
|
|
return testArrayAppendNonEmpty("mkdir")
|
|
}
|
|
|
|
struct StructContainingArray {
|
|
var array: [Int]
|
|
}
|
|
|
|
// CHECK-LABEL: @testArrayFieldAppend
|
|
// CHECK-NOT: error:
|
|
@_semantics("constant_evaluable")
|
|
func testArrayFieldAppend(_ x: Int) -> StructContainingArray {
|
|
var s = StructContainingArray(array: [])
|
|
s.array.append(x)
|
|
return s
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
func interpretArrayFieldAppend() -> StructContainingArray {
|
|
return testArrayFieldAppend(0)
|
|
}
|
|
|
|
// CHECK-LABEL: @testClosureInit
|
|
// CHECK-NOT: error:
|
|
@_semantics("constant_evaluable")
|
|
func testClosureInit(_ x: Int) -> () -> Int {
|
|
return { x }
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
func interpretClosureCreation() -> () -> Int {
|
|
return testClosureInit(19)
|
|
}
|
|
|
|
// CHECK-LABEL: @testClosureChaining
|
|
// CHECK-NOT: error:
|
|
@_semantics("constant_evaluable")
|
|
func testClosureChaining(_ x: Int, _ y: Int) -> () -> Int {
|
|
let clo: (Int) -> Int = { $0 + x }
|
|
return { clo(y) }
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
func interpretClosureChains() -> () -> Int {
|
|
return testClosureChaining(191, 201)
|
|
}
|
|
|
|
// CHECK-LABEL: @testClosureWithNonConstantCaptures
|
|
// CHECK-NOT: error:
|
|
@_semantics("constant_evaluable")
|
|
func testClosureWithNonConstantCaptures(_ x: @escaping () -> Int) -> () -> Int {
|
|
return x
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
func interpretClosureWithNonConstantCaptures(_ x: Int) -> () -> Int {
|
|
return testClosureWithNonConstantCaptures({ x })
|
|
}
|
|
|
|
// CHECK-LABEL: @testAutoClosure
|
|
// CHECK-NOT: error:
|
|
@_semantics("constant_evaluable")
|
|
func testAutoClosure(_ x: @escaping @autoclosure () -> Int) -> () -> Int {
|
|
return x
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
func interpretAutoClosure(_ x: Int) -> () -> Int {
|
|
return testAutoClosure(x)
|
|
}
|
|
|
|
// Test thin-to-thick function conversion.
|
|
|
|
func someFunction(_ x: Int) -> Int {
|
|
return x + 1
|
|
}
|
|
|
|
// CHECK-LABEL: @testThinToThick
|
|
// CHECK-NOT: error:
|
|
@_semantics("constant_evaluable")
|
|
func testThinToThick() -> (Int) -> Int {
|
|
return someFunction
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
func interpretThinToThick() -> (Int) -> Int {
|
|
return testThinToThick()
|
|
}
|
|
|
|
// Test closures and arrays combination.
|
|
|
|
// CHECK-LABEL: @testArrayOfClosures
|
|
// CHECK-NOT: error:
|
|
@_semantics("constant_evaluable")
|
|
func testArrayOfClosures(_ byte: @escaping () -> Int) -> [(Int) -> Int] {
|
|
var closureArray: [(Int) -> Int] = []
|
|
// Append a simple closure.
|
|
closureArray.append({ arg in
|
|
return 0
|
|
})
|
|
// Append a closure that does computation.
|
|
closureArray.append({ arg in
|
|
return byte() + arg
|
|
})
|
|
return closureArray
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
func interpretArrayOfClosures() -> [(Int) -> Int] {
|
|
return testArrayOfClosures({ 10 })
|
|
}
|
|
|
|
// Test checked casts.
|
|
|
|
// CHECK-LABEL: @testMetaTypeCast
|
|
// CHECK-NOT: error:
|
|
@_semantics("constant_evaluable")
|
|
func testMetaTypeCast<T>(_ x: T.Type) -> Bool {
|
|
return (x is Int.Type)
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
func interpretMetaTypeCast() -> Bool {
|
|
return testMetaTypeCast(Int.self)
|
|
}
|
|
|
|
// FIXME: this cast is not found to be false by the classifyDynamicCast utility.
|
|
func interpretMetaTypeCast2() -> Bool {
|
|
return testMetaTypeCast(((Int) -> Int).self)
|
|
}
|
|
|
|
// CHECK-LABEL: @testBinaryIntegerDescription
|
|
// CHECK-NOT: error:
|
|
@_semantics("constant_evaluable")
|
|
func testBinaryIntegerDescription<T: BinaryInteger>(_ x: T) -> String {
|
|
return x.description
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
func interpretBinaryIntegerDescription() -> String {
|
|
var str = testBinaryIntegerDescription(-10)
|
|
str += testBinaryIntegerDescription(UInt(20))
|
|
return str
|
|
}
|
|
|
|
// CHECK-LABEL: @testPreconditionFailure
|
|
// CHECK: error: not constant evaluable
|
|
@_semantics("constant_evaluable")
|
|
func testPreconditionFailure(_ x: Int) -> Int {
|
|
precondition(x > 0, "argument must be positive")
|
|
return x + 1
|
|
// CHECK: note: operation traps
|
|
// Note that the message displayed depends on the assert configuration,
|
|
// therefore it is not checked here. For debug stdlib, the full message
|
|
// must be displayed.
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
func interpretPreconditionFailure() -> Int {
|
|
return testPreconditionFailure(-10)
|
|
}
|
|
|
|
// CHECK-LABEL: @testFatalError
|
|
// CHECK: error: not constant evaluable
|
|
@_semantics("constant_evaluable")
|
|
func testFatalError() -> Int {
|
|
fatalError("invoked an uncallable function")
|
|
return 0
|
|
// CHECK: note: Fatal error: invoked an uncallable function
|
|
// CHECK: note: operation traps
|
|
}
|
|
|
|
@_semantics("test_driver")
|
|
func interpretFatalError() -> Int {
|
|
return testFatalError()
|
|
}
|