// 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(_ 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(_ 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 { var x: X var y: Y // CHECK-LABEL: @methodWithGeneric // CHECK-NOT: error: @_semantics("constant_evaluable") @_optimize(none) func methodWithGeneric(_ z: Z) -> SGeneric { return SGeneric(x: z, y: y) } } @_semantics("test_driver") func interpretStructAndMethodWithGeneric() -> SGeneric { let s = SGeneric(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.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 { case integer(T) case rational(T, T) } // CHECK-LABEL: @testAddressOnlyEnum // CHECK-NOT: error: @_semantics("constant_evaluable") func testAddressOnlyEnum(_ number: Number) -> 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() } @_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(_ 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(_ 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() }