| //===--- ParameterPassing.swift -------------------------------*- swift -*-===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See https://swift.org/LICENSE.txt for license information |
| // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| // RUN: %empty-directory(%t) |
| // RUN: %gyb %s -o %t/ParameterPassing.swift |
| // RUN: %line-directive %t/ParameterPassing.swift -- %target-build-swift %t/ParameterPassing.swift -o %t/a.out_Release -O |
| // RUN: %target-run %t/a.out_Release |
| // REQUIRES: executable_test |
| |
| import StdlibUnittest |
| |
| let tests = TestSuite("ParameterPassing") |
| |
| struct MyError : Error { |
| let val = 127 |
| } |
| |
| %{ |
| errorMethodTypes = [ |
| ('Throwing', 'throws', True, 'true'), |
| ('Throws', 'throws', True, 'false'), |
| ('', '', False, 'false'), |
| ] |
| }% |
| |
| // Float values. |
| % for TestType in 'Float', 'Double': |
| % for Num in range(0, 10): |
| @inline(__always) |
| func value${TestType}${Num}() -> ${TestType} { |
| return 1.${Num+1} |
| } |
| % end |
| % end |
| |
| // Integer values. |
| % for TestType in 'UInt8', 'UInt16', 'UInt32', 'UInt64', 'Int8', 'Int16', 'Int32', 'Int64': |
| |
| enum Enum${TestType} : Equatable { |
| case Empty |
| case Value(${TestType}) |
| } |
| func == (lhs: Enum${TestType}, rhs: Enum${TestType}) -> Bool { |
| switch lhs { |
| case .Empty: |
| switch rhs { |
| case .Empty: |
| return true |
| case .Value(_): |
| return false |
| } |
| case .Value(let lhsVal): |
| switch lhs { |
| case .Empty: |
| return false |
| case .Value(let rhsVal): |
| return lhsVal == rhsVal |
| } |
| } |
| } |
| |
| struct Struct${TestType} : Equatable { |
| let f0 : ${TestType} |
| let f1: Float |
| let f2: Double |
| init(f0: ${TestType}, f1: Float, f2: Double) { |
| self.f0 = f0 |
| self.f1 = f1 |
| self.f2 = f2 |
| } |
| } |
| func ==(lhs: Struct${TestType}, rhs: Struct${TestType}) -> Bool { |
| return lhs.f0 == rhs.f0 && lhs.f1 == rhs.f1 && lhs.f2 == rhs.f2 |
| } |
| |
| % for Num in range(0, 10): |
| @inline(__always) |
| func value${TestType}${Num}() -> ${TestType} { |
| return ${Num+1} |
| } |
| @inline(__always) |
| func valueEnum${TestType}${Num}() -> Enum${TestType} { |
| return Enum${TestType}.Value(${Num+1}) |
| } |
| func valueStruct${TestType}${Num}() -> Struct${TestType} { |
| return Struct${TestType}(f0: ${Num+1}, f1: 1.${Num}, f2: 2.${Num}) |
| } |
| % end |
| % end |
| |
| // Float80 values. |
| #if arch(i386) || arch(x86_64) |
| % for Num in range(0, 10): |
| @inline(__always) |
| func valueFloat80${Num}() -> Float80 { |
| return 1.${Num+1} |
| } |
| % end |
| #endif |
| |
| % for (FuncName, Throw, MayThrow, DoesThrow) in errorMethodTypes: |
| |
| @inline(never) |
| func clobber${FuncName}( |
| _ d0: Double, _ d1: Double, _ d2: Double, _ d3: Double, _ d4: Double, _ d5: Double, |
| _ d6: Double, _ d7: Double, _ d8: Double, _ d9: Double, _ i0: Int, _ i1: Int, |
| _ i2: Int, _ i3: Int, _ i4: Int, _ i5: Int, _ i6: Int, _ i7: Int, _ i8: Int, |
| _ i9: Int |
| ) ${Throw} -> (Double, Int) { |
| let sumD = d0 + d1 + d2 + d3 + d4 + d5 + d6 + d7 + d8 + d9 |
| let sumI = i0 + i1 + i2 + i3 + i4 + i5 + i6 + i7 + i8 + i9 |
| % if MayThrow: |
| var shouldThrow = ${DoesThrow} |
| withUnsafeMutablePointer(to: &shouldThrow, { _blackHole($0) }) |
| if shouldThrow { |
| throw MyError() |
| } |
| % end |
| return (sumD, sumI) |
| } |
| |
| %end |
| |
| %{ testTypes = [ |
| 'Float', 'Float80', 'Double', 'UInt8', 'UInt16', 'UInt32', 'UInt64', |
| 'Int8', 'Int16', 'Int32', 'Int64', |
| 'EnumUInt8', 'EnumUInt16', 'EnumUInt32', 'EnumUInt64', 'EnumInt8', |
| 'EnumInt16', 'EnumInt32', 'EnumInt64', |
| 'StructUInt8', 'StructUInt16', 'StructUInt32', 'StructUInt64', |
| 'StructInt8', 'StructInt16', 'StructInt32', 'StructInt64', |
| ] |
| }% |
| % for TestType in testTypes: |
| |
| % if TestType == 'Float80': |
| #if arch(i386) || arch(x86_64) |
| % end |
| |
| % for (FuncName, Throw, MayThrow, DoesThrow) in errorMethodTypes: |
| |
| @inline(never) |
| func verifyParameters${TestType}${FuncName}( |
| _ p0: ${TestType}, _ p1: ${TestType}, _ p2: ${TestType}, _ p3: ${TestType}, _ p4: ${TestType}, _ p5: ${TestType}, |
| _ p6: ${TestType}, _ p7: ${TestType}, _ p8: ${TestType}, _ p9 : ${TestType} |
| ) ${Throw} { |
| % for Num in range(0, 10): |
| precondition(p${Num} == value${TestType}${Num}()) |
| % end |
| % if MayThrow: |
| let res = try clobber${FuncName}(0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, |
| % else: |
| let res = clobber${FuncName}(0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, |
| % end |
| 2, 3, 5, 7, 11, 13, 17, 19, 23, 29) |
| precondition(res.0 == 5.5) |
| precondition(res.1 == 129) |
| % for Num in range(0, 10): |
| precondition(p${Num} == value${TestType}${Num}()) |
| % end |
| } |
| |
| @inline(never) |
| func verifyReturn${TestType}${FuncName}() ${Throw} -> ( |
| % for Num in range(0, 9): |
| ${TestType}, |
| % end |
| ${TestType} |
| ) |
| { |
| % if MayThrow: |
| var shouldThrow = ${DoesThrow} |
| withUnsafeMutablePointer(to: &shouldThrow, { _blackHole($0) }) |
| if shouldThrow { |
| throw MyError() |
| } |
| % end |
| |
| return ( |
| % for Num in range(0, 9): |
| value${TestType}${Num}(), |
| % end |
| value${TestType}9() |
| ) |
| } |
| |
| @inline(never) |
| func verifyReturnAndParameters${TestType}${FuncName}( |
| _ p0: ${TestType}, _ p1: ${TestType}, _ p2: ${TestType}, _ p3: ${TestType}, _ p4: ${TestType}, _ p5: ${TestType}, |
| _ p6: ${TestType}, _ p7: ${TestType}, _ p8: ${TestType}, _ p9 : ${TestType} |
| ) ${Throw} -> ( |
| % for Num in range(0, 9): |
| ${TestType}, |
| % end |
| ${TestType} |
| ) |
| { |
| % for Num in range(0, 10): |
| precondition(p${Num} == value${TestType}${Num}()) |
| % end |
| % if MayThrow: |
| let res = try clobber${FuncName}(0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, |
| % else: |
| let res = clobber${FuncName}(0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, |
| % end |
| 2, 3, 5, 7, 11, 13, 17, 19, 23, 29) |
| precondition(res.0 == 5.5) |
| precondition(res.1 == 129) |
| % for Num in range(0, 10): |
| precondition(p${Num} == value${TestType}${Num}()) |
| % end |
| return ( |
| % for Num in range(0, 9): |
| value${TestType}${Num}(), |
| % end |
| value${TestType}9() |
| ) |
| } |
| % end |
| |
| protocol Proto${TestType} { |
| % for (FuncName, Throw, _, _) in errorMethodTypes: |
| func verifyParameters${FuncName}( |
| _ p0: ${TestType}, _ p1: ${TestType}, _ p2: ${TestType}, _ p3: ${TestType}, _ p4: ${TestType}, _ p5: ${TestType}, |
| _ p6: ${TestType}, _ p7: ${TestType}, _ p8: ${TestType}, _ p9 : ${TestType} |
| ) ${Throw} |
| |
| func verifyReturn${FuncName}() ${Throw} -> ( |
| % for Num in range(0, 9): |
| ${TestType}, |
| % end |
| ${TestType} |
| ) |
| |
| @inline(never) |
| func verifyReturnAndParameters${FuncName}( |
| _ p0: ${TestType}, _ p1: ${TestType}, _ p2: ${TestType}, _ p3: ${TestType}, _ p4: ${TestType}, _ p5: ${TestType}, |
| _ p6: ${TestType}, _ p7: ${TestType}, _ p8: ${TestType}, _ p9 : ${TestType} |
| ) ${Throw} -> ( |
| % for Num in range(0, 9): |
| ${TestType}, |
| % end |
| ${TestType} |
| ) |
| %end |
| } |
| |
| public class A${TestType} : Proto${TestType} { |
| var dontStripSelfArg: Int = 7 |
| |
| init() {} |
| |
| % for (FuncName, Throw, MayThrow, _) in errorMethodTypes: |
| @inline(never) |
| func verifyParameters${FuncName}( |
| _ p0: ${TestType}, _ p1: ${TestType}, _ p2: ${TestType}, _ p3: ${TestType}, _ p4: ${TestType}, _ p5: ${TestType}, |
| _ p6: ${TestType}, _ p7: ${TestType}, _ p8: ${TestType}, _ p9 : ${TestType} |
| ) ${Throw} { |
| % for Num in range(0, 10): |
| precondition(p${Num} == value${TestType}${Num}()) |
| % end |
| % if MayThrow: |
| let res = try clobber${FuncName}(0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, |
| % else: |
| let res = clobber${FuncName}(0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, |
| % end |
| 2, 3, 5, 7, 11, 13, 17, 19, 23, 29) |
| precondition(dontStripSelfArg == 7) |
| precondition(res.0 == 5.5) |
| precondition(res.1 == 129) |
| % for Num in range(0, 10): |
| precondition(p${Num} == value${TestType}${Num}()) |
| % end |
| } |
| |
| func verifyReturn${FuncName}() ${Throw} -> ( |
| % for Num in range(0, 9): |
| ${TestType}, |
| % end |
| ${TestType} |
| ) |
| { |
| % if MayThrow: |
| var shouldThrow = ${DoesThrow} |
| withUnsafeMutablePointer(to: &shouldThrow, { _blackHole($0) }) |
| if shouldThrow { |
| throw MyError() |
| } |
| % end |
| |
| return ( |
| % for Num in range(0, 9): |
| value${TestType}${Num}(), |
| % end |
| value${TestType}9() |
| ) |
| } |
| |
| @inline(never) |
| func verifyReturnAndParameters${FuncName}( |
| _ p0: ${TestType}, _ p1: ${TestType}, _ p2: ${TestType}, _ p3: ${TestType}, _ p4: ${TestType}, _ p5: ${TestType}, |
| _ p6: ${TestType}, _ p7: ${TestType}, _ p8: ${TestType}, _ p9 : ${TestType} |
| ) ${Throw} -> ( |
| % for Num in range(0, 9): |
| ${TestType}, |
| % end |
| ${TestType} |
| ) |
| { |
| % for Num in range(0, 10): |
| precondition(p${Num} == value${TestType}${Num}()) |
| % end |
| % if MayThrow: |
| let res = try clobber${FuncName}(0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, |
| % else: |
| let res = clobber${FuncName}(0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, |
| % end |
| 2, 3, 5, 7, 11, 13, 17, 19, 23, 29) |
| precondition(res.0 == 5.5) |
| precondition(res.1 == 129) |
| % for Num in range(0, 10): |
| precondition(p${Num} == value${TestType}${Num}()) |
| % end |
| return ( |
| % for Num in range(0, 9): |
| value${TestType}${Num}(), |
| % end |
| value${TestType}9() |
| ) |
| } |
| |
| % end |
| } |
| |
| % for (FuncName, throw, MayThrow, DoesThrow) in errorMethodTypes: |
| tests.test("${TestType}/Fun${FuncName}") { |
| // Test a regular function call. |
| % if MayThrow: |
| do { |
| try verifyParameters${TestType}${FuncName}( |
| %for Num in range(0, 9): |
| value${TestType}${Num}(), |
| %end |
| value${TestType}9() |
| ) |
| % if DoesThrow == 'true': |
| } catch let e as MyError { |
| expectEqual(127, e.val) |
| % end |
| } catch { |
| preconditionFailure("Should not get there") |
| } |
| % else: |
| verifyParameters${TestType}${FuncName}( |
| %for Num in range(0, 9): |
| value${TestType}${Num}(), |
| %end |
| value${TestType}9() |
| ) |
| % end |
| } |
| |
| tests.test("${TestType}/RetFun${FuncName}") { |
| // Test a regular function call. |
| % if MayThrow: |
| do { |
| let res = try verifyReturn${TestType}${FuncName}() |
| % for Num in range(0, 10): |
| expectEqual(value${TestType}${Num}(), res.${Num}) |
| % end |
| % if DoesThrow == 'true': |
| } catch let e as MyError { |
| expectEqual(127, e.val) |
| % end |
| } catch { |
| preconditionFailure("Should not get there") |
| } |
| % else: |
| let res = verifyReturn${TestType}${FuncName}() |
| %for Num in range(0, 10): |
| expectEqual(value${TestType}${Num}(), res.${Num}) |
| % end |
| % end |
| } |
| |
| tests.test("${TestType}/RetAndParamFun${FuncName}") { |
| // Test a regular function call. |
| % if MayThrow: |
| do { |
| let res = try verifyReturnAndParameters${TestType}${FuncName}( |
| %for Num in range(0, 9): |
| value${TestType}${Num}(), |
| %end |
| value${TestType}9() |
| ) |
| % for Num in range(0, 10): |
| expectEqual(value${TestType}${Num}(), res.${Num}) |
| % end |
| % if DoesThrow == 'true': |
| } catch let e as MyError { |
| expectEqual(127, e.val) |
| % end |
| } catch { |
| preconditionFailure("Should not get there") |
| } |
| % else: |
| let res = verifyReturnAndParameters${TestType}${FuncName}( |
| %for Num in range(0, 9): |
| value${TestType}${Num}(), |
| %end |
| value${TestType}9() |
| ) |
| % for Num in range(0, 10): |
| expectEqual(value${TestType}${Num}(), res.${Num}) |
| % end |
| % end |
| } |
| |
| tests.test("${TestType}/Method${FuncName}") { |
| var klazz = A${TestType}() |
| // Defeat type analysis such that the call below remains a method call. |
| withUnsafeMutablePointer(to: &klazz, { _blackHole($0) }) |
| |
| // Test a method call. |
| % if MayThrow: |
| do { |
| try klazz.verifyParameters${FuncName}( |
| %for Num in range(0, 9): |
| value${TestType}${Num}(), |
| %end |
| value${TestType}9() |
| ) |
| % if DoesThrow == 'true': |
| } catch let e as MyError { |
| expectEqual(127, e.val) |
| % end |
| } catch { |
| preconditionFailure("Should not get there") |
| } |
| % else: |
| klazz.verifyParameters${FuncName}( |
| %for Num in range(0, 9): |
| value${TestType}${Num}(), |
| %end |
| value${TestType}9() |
| ) |
| % end |
| } |
| |
| tests.test("${TestType}/RetMethod${FuncName}") { |
| var klazz = A${TestType}() |
| // Defeat type analysis such that the call below remains a method call. |
| withUnsafeMutablePointer(to: &klazz, { _blackHole($0) }) |
| |
| // Test a method call. |
| % if MayThrow: |
| do { |
| let res = try klazz.verifyReturn${FuncName}() |
| % for Num in range(0, 10): |
| expectEqual(value${TestType}${Num}(), res.${Num}) |
| % end |
| % if DoesThrow == 'true': |
| } catch let e as MyError { |
| expectEqual(127, e.val) |
| % end |
| } catch { |
| preconditionFailure("Should not get there") |
| } |
| % else: |
| let res = klazz.verifyReturn${FuncName}() |
| %for Num in range(0, 10): |
| expectEqual(value${TestType}${Num}(), res.${Num}) |
| % end |
| % end |
| } |
| |
| tests.test("${TestType}/RetAndParamMethod${FuncName}") { |
| var klazz = A${TestType}() |
| // Defeat type analysis such that the call below remains a method call. |
| withUnsafeMutablePointer(to: &klazz, { _blackHole($0) }) |
| |
| // Test a method call. |
| % if MayThrow: |
| do { |
| let res = try klazz.verifyReturnAndParameters${FuncName}( |
| %for Num in range(0, 9): |
| value${TestType}${Num}(), |
| %end |
| value${TestType}9() |
| ) |
| %for Num in range(0, 10): |
| expectEqual(value${TestType}${Num}(), res.${Num}) |
| % end |
| % if DoesThrow == 'true': |
| } catch let e as MyError { |
| expectEqual(127, e.val) |
| % end |
| } catch { |
| preconditionFailure("Should not get there") |
| } |
| % else: |
| let res = klazz.verifyReturnAndParameters${FuncName}( |
| %for Num in range(0, 9): |
| value${TestType}${Num}(), |
| %end |
| value${TestType}9() |
| ) |
| %for Num in range(0, 10): |
| expectEqual(value${TestType}${Num}(), res.${Num}) |
| % end |
| % end |
| } |
| |
| tests.test("${TestType}/WitnessMethod${FuncName}") { |
| var p : Proto${TestType} = A${TestType}() |
| withUnsafeMutablePointer(to: &p, { _blackHole($0) }) |
| |
| // Test a witness method call. |
| % if MayThrow: |
| do { |
| try p.verifyParameters${FuncName}( |
| %for Num in range(0, 9): |
| value${TestType}${Num}(), |
| %end |
| value${TestType}9() |
| ) |
| % if DoesThrow == 'true': |
| } catch let e as MyError { |
| expectEqual(127, e.val) |
| % end |
| } catch { |
| preconditionFailure("Should not get there") |
| } |
| % else: |
| p.verifyParameters${FuncName}( |
| %for Num in range(0, 9): |
| value${TestType}${Num}(), |
| %end |
| value${TestType}9() |
| ) |
| % end |
| } |
| |
| tests.test("${TestType}/RetWitnessMethod${FuncName}") { |
| var p : Proto${TestType} = A${TestType}() |
| withUnsafeMutablePointer(to: &p, { _blackHole($0) }) |
| |
| // Test a witness method call. |
| % if MayThrow: |
| do { |
| let res = try p.verifyReturn${FuncName}() |
| % for Num in range(0, 10): |
| expectEqual(value${TestType}${Num}(), res.${Num}) |
| % end |
| % if DoesThrow == 'true': |
| } catch let e as MyError { |
| expectEqual(127, e.val) |
| % end |
| } catch { |
| preconditionFailure("Should not get there") |
| } |
| % else: |
| let res = p.verifyReturn${FuncName}() |
| %for Num in range(0, 10): |
| expectEqual(value${TestType}${Num}(), res.${Num}) |
| % end |
| % end |
| } |
| |
| tests.test("${TestType}/RetAndParamWitnessMethod${FuncName}") { |
| var p : Proto${TestType} = A${TestType}() |
| withUnsafeMutablePointer(to: &p, { _blackHole($0) }) |
| |
| // Test a method call. |
| % if MayThrow: |
| do { |
| let res = try p.verifyReturnAndParameters${FuncName}( |
| %for Num in range(0, 9): |
| value${TestType}${Num}(), |
| %end |
| value${TestType}9() |
| ) |
| %for Num in range(0, 10): |
| expectEqual(value${TestType}${Num}(), res.${Num}) |
| % end |
| % if DoesThrow == 'true': |
| } catch let e as MyError { |
| expectEqual(127, e.val) |
| % end |
| } catch { |
| preconditionFailure("Should not get there") |
| } |
| % else: |
| let res = p.verifyReturnAndParameters${FuncName}( |
| %for Num in range(0, 9): |
| value${TestType}${Num}(), |
| %end |
| value${TestType}9() |
| ) |
| %for Num in range(0, 10): |
| expectEqual(value${TestType}${Num}(), res.${Num}) |
| % end |
| % end |
| } |
| |
| % end |
| |
| % if TestType == 'Float80': |
| #endif |
| % end |
| |
| % end |
| |
| runAllTests() |