| // RUN: %empty-directory(%t) |
| // RUN: %target-swift-frontend -emit-silgen -primary-file %s -o %t/constant_evaluable_subset_test_silgen.sil |
| // |
| // Run the (mandatory) passes on which constant evaluator depends, and test the |
| // constant evaluator on the SIL produced after the dependent passes are run. |
| // |
| // RUN: not %target-sil-opt -silgen-cleanup -raw-sil-inst-lowering -allocbox-to-stack -mandatory-inlining -constexpr-limit 3000 -test-constant-evaluable-subset %t/constant_evaluable_subset_test_silgen.sil > %t/constant_evaluable_subset_test.sil 2> %t/error-output |
| // |
| // RUN: %FileCheck %s < %t/error-output |
| // |
| // Test the constant evaluator on the output of the mandatory pipeline. This is |
| // to test that constant evaluability is not affected by mandatory |
| // optimizations. Note that it can be affected by non-mandatory optimizations, |
| // especially performance inlining as it inlines functions such as String.+= |
| // that the evaluator has special knowledge about. |
| // |
| // RUN: not %target-sil-opt -silgen-cleanup -diagnose-invalid-escaping-captures -diagnose-static-exclusivity -capture-promotion -access-enforcement-selection -allocbox-to-stack -noreturn-folding -mark-uninitialized-fixup -definite-init -raw-sil-inst-lowering -closure-lifetime-fixup -semantic-arc-opts -destroy-hoisting -ownership-model-eliminator -mandatory-inlining -predictable-memaccess-opts -os-log-optimization -diagnostic-constant-propagation -predictable-deadalloc-elim -guaranteed-arc-opts -diagnose-unreachable -diagnose-infinite-recursion -yield-once-check -dataflow-diagnostics -split-non-cond_br-critical-edges -constexpr-limit 3000 -test-constant-evaluable-subset %t/constant_evaluable_subset_test_silgen.sil > /dev/null 2> %t/error-output-mandatory |
| // |
| // RUN: %FileCheck %s < %t/error-output-mandatory |
| |
| // TODO(TF-799): Re-enable test after SR-11336 is fixed. |
| // XFAIL: * |
| |
| // 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 interpretComparisions() -> 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 performed during this call traps |
| // CHECK: function_ref @$sSZss17FixedWidthIntegerRzrlEyxqd__cSzRd__lufC |
| } |
| |
| @_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 performed during this call traps |
| // CHECK: function_ref @$sSUss17FixedWidthIntegerRzrlEyxqd__cSzRd__lufC |
| } |
| |
| @_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 'Swift.readLine(strippingNewline: Swift.Bool) -> Swift.Optional<Swift.String>' 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") |
| } |