blob: e2723d05413431407f337dfd8478ab538b885952 [file] [log] [blame]
// RUN: %target-typecheck-verify-swift
@dynamicCallable
struct Callable {
func dynamicallyCall(withArguments arguments: [Int]) -> Int {
return arguments.count
}
}
@dynamicCallable
struct DiscardableResult {
@discardableResult
func dynamicallyCall(withArguments arguments: [Double]) -> Int {
return arguments.count
}
}
@dynamicCallable
struct Throwing {
func dynamicallyCall(withArguments arguments: [String]) throws -> Int {
return arguments.count
}
}
@dynamicCallable
struct KeywordArgumentCallable {
@discardableResult
func dynamicallyCall(
withKeywordArguments arguments: KeyValuePairs<String, Float>
) -> Int {
return arguments.count
}
}
func testCallable(
a: Callable, b: DiscardableResult, c: Throwing, d: KeywordArgumentCallable
) {
_ = a()
let a1 = a(1, 2, 3, 4) // expected-warning {{initialization of immutable value 'a1' was never used}}
b()
b(1, 2, 3, 4.0)
_ = try? c()
let c1 = try! c("hello", "world") // expected-warning {{initialization of immutable value 'c1' was never used}}
d()
d(1, 2.0, 3)
d(x1: 1, 2.0, x2: 3)
}
func testIUO(
a: Callable!, b: DiscardableResult!, c: Throwing!, d: KeywordArgumentCallable!
) {
print(a(1, 2, 3))
print(b(1, 2, 3.0))
print(try! c("hello", "world"))
print(d(foo: 1, 2.0, bar: 3))
}
//===----------------------------------------------------------------------===//
// Returning a function
//===----------------------------------------------------------------------===//
@dynamicCallable
struct CallableReturningFunction {
func dynamicallyCall(withArguments arguments: [Int]) -> (Int) -> Void {
return { x in () }
}
}
func testFunction(a: CallableReturningFunction) {
a(1, 2, 3)(1)
}
//===----------------------------------------------------------------------===//
// Error cases
//===----------------------------------------------------------------------===//
// Arguments' type may not be variadic.
// expected-error @+1 {{@dynamicCallable attribute requires 'Invalid1' to have either a valid 'dynamicallyCall(withArguments:)' method or 'dynamicallyCall(withKeywordArguments:)' method}}
@dynamicCallable
struct Invalid1 {
func dynamicallyCall(withArguments arguments: [Int]...) -> Int {
return 1
}
}
// Keyword arguments' key type must be ExpressibleByStringLiteral.
// expected-error @+1 {{@dynamicCallable attribute requires 'Invalid2' to have either a valid 'dynamicallyCall(withArguments:)' method or 'dynamicallyCall(withKeywordArguments:)' method}}
@dynamicCallable
struct Invalid2 {
func dynamicallyCall(
withKeywordArguments arguments: KeyValuePairs<Int, Int>
) -> Int {
return 1
}
}
// Dynamic calls with keyword arguments require `dynamicallyCall(withKeywordArguments:)` to be defined.
@dynamicCallable
class NoKeyword {
func dynamicallyCall(withArguments arguments: [Int]) -> Int { return 1 }
}
@dynamicCallable
protocol NoKeywordProtocol {
func dynamicallyCall(withArguments arguments: [Int]) -> Int
}
func testInvalidKeywordCall(x: NoKeyword, y: NoKeywordProtocol & AnyObject) {
x(a: 1, b: 2) // expected-error {{@dynamicCallable type 'NoKeyword' cannot be applied with keyword arguments; missing 'dynamicCall(withKeywordArguments:)' method}}
y(a: 1, b: 2) // expected-error {{@dynamicCallable type 'NoKeywordProtocol & AnyObject' cannot be applied with keyword arguments; missing 'dynamicCall(withKeywordArguments:)' method}}
}
// expected-error @+1 {{'@dynamicCallable' attribute cannot be applied to this declaration}}
@dynamicCallable
extension Int {
func dynamicallyCall(withArguments arguments: [Int]) -> Int {
return 1
}
}
// expected-error @+1 {{'@dynamicCallable' attribute cannot be applied to this declaration}}
@dynamicCallable
func NotAllowedOnFunc() {}
// @dynamicCallable cannot be declared on a base class and fulfilled with a
// derived class.
// expected-error @+1 {{@dynamicCallable attribute requires 'InvalidBase' to have either a valid 'dynamicallyCall(withArguments:)' method or 'dynamicallyCall(withKeywordArguments:)' method}}
@dynamicCallable
class InvalidBase {}
class InvalidDerived : InvalidBase {
func dynamicallyCall(withArguments arguments: [Int]) -> Int {
return 1
}
}
//===----------------------------------------------------------------------===//
// Multiple `dynamicallyCall` methods
//===----------------------------------------------------------------------===//
@dynamicCallable
struct OverloadedCallable {
// expected-note @+1 {{found this candidate}}
func dynamicallyCall(withArguments arguments: [Int]) -> Int {
return 1
}
// expected-note @+1 {{found this candidate}}
func dynamicallyCall(withArguments arguments: [Int]) -> Float {
return 1.0
}
}
func testOverloaded(x: OverloadedCallable) {
let _: Int = x(1, 2, 3)
let _: Float = x(1, 2, 3)
let _ = x(1, 2, 3) // expected-error {{ambiguous use of 'dynamicallyCall(withArguments:)'}}
}
//===----------------------------------------------------------------------===//
// Existentials
//===----------------------------------------------------------------------===//
@dynamicCallable
protocol CallableProtocol {
func dynamicallyCall(withArguments arguments: [Int]) -> Int
}
@dynamicCallable
protocol KeywordCallableProtocol {}
extension KeywordCallableProtocol {
func dynamicallyCall(
withKeywordArguments arguments: KeyValuePairs<String, Double>
) -> Int {
return arguments.count
}
}
extension String : CallableProtocol, KeywordCallableProtocol {
func dynamicallyCall(withArguments arguments: [Int]) -> Int {
return arguments.count
}
}
func testProtoExtension() -> Int {
let str = "test"
return str(1, 2, 3) + str(label1: 1, 2, label2: 3)
}
struct CallableStruct : CallableProtocol {
func dynamicallyCall(withArguments arguments: [Int]) -> Int {
return arguments.count
}
}
class CallableClass : KeywordCallableProtocol {}
func testExistential(
a: CallableProtocol, b: KeywordCallableProtocol,
c: CallableStruct, d: CallableClass
) -> Int {
// Types that define only the `withKeywordsArguments` method can be called
// with no argument labels.
_ = b() + b(1, 2) + d() + d(1, 2)
return a(1, 2, 3) + b(label1: 1, 2, label2: 3) + c(1, 2, 3) + d(label1: 1, 2, 3)
}
// Verify protocol compositions and refinements work.
protocol SubProtocol : CallableProtocol {}
typealias ProtocolComp = AnyObject & CallableProtocol
typealias ProtocolComp2 = KeywordCallableProtocol & CallableClass
func testExistential2(a: AnyObject & CallableProtocol,
b: SubProtocol,
c: ProtocolComp & AnyObject,
d: CallableClass,
e: CallableProtocol & KeywordCallableProtocol,
f: CallableProtocol & ProtocolComp2) {
print(a(1, 2, 3))
print(b(1, 2, 3))
print(c(1, 2, 3))
print(d(1, 2, 3))
print(e() + e(label1: 1, 2, label2: 3))
print(f() + f(label1: 1, 2, label2: 3))
}
func testConstrainedClassType<C : AnyObject>(
a: C
) -> Int where C : CallableProtocol {
return a(1, 2, 3)
}
func testRefinedProtocolType<P : FloatingPoint>(
a: P
) -> Int where P : CallableProtocol {
return a(1, 2, 3)
}
//===----------------------------------------------------------------------===//
// Extension tests
//===----------------------------------------------------------------------===//
extension Optional : KeywordCallableProtocol {}
extension Array : KeywordCallableProtocol {}
func testExtensions() {
let x: Int? = 3
// Test `Optional` extension.
print(x())
print(x(label: 1, 2))
// Test `Array` extension.
print([1]())
print([1](label: 1, 2))
}
//===----------------------------------------------------------------------===//
// Class inheritance tests
//===----------------------------------------------------------------------===//
@dynamicCallable
class BaseClass {
func dynamicallyCall(withArguments arguments: [Int]) -> Int {
return arguments.count
}
}
class DerivedClass1 : BaseClass {}
class DerivedClass2 : BaseClass {
override func dynamicallyCall(withArguments arguments: [Int]) -> Int {
return arguments.count
}
}
class DerivedClass3 : BaseClass {
func dynamicallyCall(
withKeywordArguments arguments: KeyValuePairs<String, Int>
) -> Int {
return arguments.count
}
}
func testDerivedClass(
a: BaseClass, b: DerivedClass1, c: DerivedClass2, d: DerivedClass3
) -> Int {
return a() - b(1, 2) + c(3, 4) - d(x1: 5, 6, x2: 7)
}
//===----------------------------------------------------------------------===//
// Enum tests
//===----------------------------------------------------------------------===//
@dynamicCallable
enum BinaryOperation<T : Numeric> {
case add
case subtract
case multiply
func dynamicallyCall(withArguments arguments: [T]) -> T {
precondition(arguments.count == 2, "Must have 2 arguments")
let x = arguments[0]
let y = arguments[1]
switch self {
case .add:
return x + y
case .subtract:
return x - y
case .multiply:
return x * y
}
}
}
func testEnum() {
let ops: [BinaryOperation<Int>] = [.add, .subtract, .multiply]
for op in ops {
print(op(3, 4))
}
}
//===----------------------------------------------------------------------===//
// Generics
//===----------------------------------------------------------------------===//
@dynamicCallable
struct CallableGenericArray<A : ExpressibleByArrayLiteral> {
func dynamicallyCall(withArguments arguments: A) -> Int {
return 1
}
}
func testGenericArray<A : ExpressibleByArrayLiteral>(
a: CallableGenericArray<A>, x: A.ArrayLiteralElement
) -> Int {
return a() + a(x, x)
}
@dynamicCallable
struct CallableGenericDictionary<D : ExpressibleByDictionaryLiteral>
where D.Key : ExpressibleByStringLiteral {
func dynamicallyCall(withKeywordArguments arguments: D) -> Int {
return 1
}
}
func testGenericDictionary<D : ExpressibleByDictionaryLiteral>(
a: CallableGenericDictionary<D>, x: D.Value
) -> Int where D.Key : ExpressibleByStringLiteral {
return a() + a(label1: x, x, label2: x)
}
@dynamicCallable
struct CallableGeneric1<T> {
func dynamicallyCall(withArguments arguments: [T]) -> Int {
return arguments.count
}
}
func testGenericType1<T>(a: CallableGeneric1<T>, x: T) -> Int {
return a() + a(x, x)
}
func testConcreteGenericType2(a: CallableGeneric1<Int>) -> Int {
return a() + a(1, 2)
}
@dynamicCallable
struct CallableGeneric2<T> {
func dynamicallyCall(withArguments arguments: [Any]) -> Int {
return arguments.count
}
}
func testGenericType2<T>(a: CallableGeneric2<T>) -> Int {
return a(1, 2) + a("asdf", 123)
}
func testConcreteGenericType2(a: CallableGeneric2<Int>) -> Int {
return a(1, 2) + a("asdf", 123)
}
@dynamicCallable
struct CallableGeneric3<T> {
func dynamicallyCall(
withKeywordArguments arguments: KeyValuePairs<String, T>
) -> Int {
return arguments.count
}
}
func testGenericType3<T>(a: CallableGeneric3<T>, x: T) -> Int {
return a() + a(x1: x, x, x, x2: x)
}
func testConcreteGenericType3(a: CallableGeneric3<Int>) -> Int {
return a() + a(x1: 123, 1, 2, x2: 123)
}
@dynamicCallable
struct CallableGeneric4<T> {
func dynamicallyCall<U>(withArguments arguments: [U]) -> Int {
return arguments.count
}
func dynamicallyCall<U>(
withKeywordArguments arguments: KeyValuePairs<StaticString, U>
) -> Int {
return arguments.count
}
}
func testGenericType4<T>(a: CallableGeneric4<T>) -> Int {
return a() + a(1, 2, 3) + a(x1: 1, 2, x3: 3)
}
@dynamicCallable
class CallableGeneric5<T> {
func dynamicallyCall<U>(withArguments arguments: [U]) -> U {
return arguments[0]
}
func dynamicallyCall<U>(
withKeywordArguments arguments: KeyValuePairs<StaticString, U>
) -> U {
return arguments[0].1
}
}
func testGenericType5<T>(a: CallableGeneric5<T>) -> Double {
return a(1, 2, 3) + a(x1: 1, 2, x3: 3)
}
func testArchetypeType5<T, C : CallableGeneric5<T>>(a: C) -> Double {
return a(1, 2, 3) + a(x1: 1, 2, x3: 3)
}