Files
swift-mirror/test/SILGen/dynamic_callable_attribute.swift
Hamish Knight a1cf598b65 [CSApply] Hack around existential closing for callables
The current existential closing logic relies on
maintaining a stack of expressions, and closing the
existential when the size of the stack goes below
a certain threshold. This works fine for cases
where we open the existential as a part of an
user-written member reference, as we push it onto
the stack when walking over the AST. However it
doesn't handle cases where we generate an implicit
member reference when visiting a part of the AST
higher up in the tree.

We therefore run into problems with both implicit
`callAsFunction` and `@dynamicCallable`, both of
which generate implicit member refs when we visit
the apply. To hack around this issue, push the
apply's fn expr onto the stack before building the
member reference, such that we don't try to
prematurely close the existential as a part of
applying the curried member ref.

The good news at least is that this hack allows us
to remove the `extraUncurryLevel` param which was
previously working around this issue for the
`shouldBuildCurryThunk` function.

To properly fix this, we'll need to refactor
existential opening to not rely on the shape of the
AST prior to re-writing.

Resolves SR-12590.
2020-04-17 14:12:45 -07:00

79 lines
3.0 KiB
Swift

// RUN: %target-swift-emit-silgen -verify %s | %FileCheck %s
// Check that dynamic calls resolve to the right `dynamicallyCall` method in SIL.
@dynamicCallable
public struct Callable {
func dynamicallyCall(withArguments: [Int]) {}
func dynamicallyCall(withKeywordArguments: KeyValuePairs<String, Int>) {}
}
@_silgen_name("foo")
public func foo(a: Callable) {
// The first two calls should resolve to the `withArguments:` method.
a()
a(1, 2, 3)
// The last call should resolve to the `withKeywordArguments:` method.
a(1, 2, 3, label: 4)
}
// CHECK-LABEL: sil [ossa] @foo
// CHECK: bb0(%0 : $Callable):
// CHECK: [[DYN_CALL_1:%.*]] = function_ref @$s26dynamic_callable_attribute8CallableV15dynamicallyCall13withArgumentsySaySiG_tF
// CHECK-NEXT: apply [[DYN_CALL_1]]
// CHECK: [[DYN_CALL_2:%.*]] = function_ref @$s26dynamic_callable_attribute8CallableV15dynamicallyCall13withArgumentsySaySiG_tF
// CHECK-NEXT: apply [[DYN_CALL_2]]
// CHECK: [[DYN_CALL_3:%.*]] = function_ref @$s26dynamic_callable_attribute8CallableV15dynamicallyCall20withKeywordArgumentsys13KeyValuePairsVySSSiG_tF
@dynamicCallable
public struct Callable2 {
func dynamicallyCall(withKeywordArguments: KeyValuePairs<String, Any>) {}
}
// CHECK-LABEL: sil [ossa] @keywordCoerceBug
// CHECK:[[DYN_CALL:%.*]] = function_ref @$s26dynamic_callable_attribute9Callable2V15dynamicallyCall20withKeywordArgumentsys13KeyValuePairsVySSypG_tF
@_silgen_name("keywordCoerceBug")
public func keywordCoerceBug(a: Callable2, s: Int) {
a(s)
}
@dynamicCallable
struct S {
func dynamicallyCall(withArguments x: [Int]) -> Int! { nil }
}
@dynamicCallable
protocol P1 {
func dynamicallyCall(withKeywordArguments: [String: Any])
}
@dynamicCallable
protocol P2 {
func dynamicallyCall(withArguments x: [Int]) -> Self
}
@dynamicCallable
class C {
func dynamicallyCall(withKeywordArguments x: [String: String]) -> Self { return self }
}
// CHECK-LABEL: sil hidden [ossa] @$s26dynamic_callable_attribute05test_A10_callablesyyAA1SV_AA2P1_pAA2P2_pxtAA1CCRbzlF : $@convention(thin) <T where T : C> (S, @in_guaranteed P1, @in_guaranteed P2, @guaranteed T) -> ()
func test_dynamic_callables<T : C>(_ s: S, _ p1: P1, _ p2: P2, _ t: T) {
// SR-12615: Compiler crash on @dynamicCallable IUO.
// CHECK: function_ref @$s26dynamic_callable_attribute1SV15dynamicallyCall13withArgumentsSiSgSaySiG_tF : $@convention(method) (@guaranteed Array<Int>, S) -> Optional<Int>
// CHECK: switch_enum %{{.+}} : $Optional<Int>
let _: Int = s(0)
// CHECK: witness_method $@opened({{.+}}) P1, #P1.dynamicallyCall : <Self where Self : P1> (Self) -> ([String : Any]) -> ()
p1(x: 5)
// CHECK: witness_method $@opened({{.+}}) P2, #P2.dynamicallyCall : <Self where Self : P2> (Self) -> ([Int]) -> Self
_ = p2()
// CHECK: class_method %{{.+}} : $C, #C.dynamicallyCall : (C) -> ([String : String]) -> @dynamic_self C, $@convention(method) (@guaranteed Dictionary<String, String>, @guaranteed C) -> @owned C
// CHECK: unchecked_ref_cast %{{.+}} : $C to $T
_ = t("")
}