Skip to content

Commit 31e99e5

Browse files
committed
[CSApply] Continue to finishApply for dynamic callables
Previously we would build our own call expr. However this would skip a few transforms that `finishApply` does such as closing existentials, casting covariant returns, and unwrapping IUOs. Instead, return the new fn and arg exprs, and let `finishApply` do the rest. Resolves SR-12615.
1 parent 62f257d commit 31e99e5

File tree

2 files changed

+58
-32
lines changed

2 files changed

+58
-32
lines changed

lib/Sema/CSApply.cpp

Lines changed: 26 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1542,12 +1542,11 @@ namespace {
15421542
ConstraintLocatorBuilder locator,
15431543
ConstraintLocatorBuilder calleeLocator);
15441544

1545-
// Resolve `@dynamicCallable` applications.
1546-
Expr *finishApplyDynamicCallable(ApplyExpr *apply,
1547-
SelectedOverload selected,
1548-
FuncDecl *method,
1549-
AnyFunctionType *methodType,
1550-
ConstraintLocatorBuilder applyFunctionLoc);
1545+
/// Build the function and argument for a `@dynamicCallable` application.
1546+
std::pair</*fn*/ Expr *, /*arg*/ Expr *>
1547+
buildDynamicCallable(ApplyExpr *apply, SelectedOverload selected,
1548+
FuncDecl *method, AnyFunctionType *methodType,
1549+
ConstraintLocatorBuilder applyFunctionLoc);
15511550

15521551
private:
15531552
/// Simplify the given type by substituting all occurrences of
@@ -7146,12 +7145,11 @@ static Expr *buildCallAsFunctionMethodRef(
71467145
}
71477146

71487147
// Resolve `@dynamicCallable` applications.
7149-
Expr *
7150-
ExprRewriter::finishApplyDynamicCallable(ApplyExpr *apply,
7151-
SelectedOverload selected,
7152-
FuncDecl *method,
7153-
AnyFunctionType *methodType,
7154-
ConstraintLocatorBuilder loc) {
7148+
std::pair<Expr *, Expr *>
7149+
ExprRewriter::buildDynamicCallable(ApplyExpr *apply, SelectedOverload selected,
7150+
FuncDecl *method,
7151+
AnyFunctionType *methodType,
7152+
ConstraintLocatorBuilder loc) {
71557153
auto &ctx = cs.getASTContext();
71567154
auto *fn = apply->getFn();
71577155

@@ -7203,8 +7201,7 @@ ExprRewriter::finishApplyDynamicCallable(ApplyExpr *apply,
72037201
handleStringLiteralExpr(cast<LiteralExpr>(labelExpr));
72047202

72057203
Expr *valueExpr = coerceToType(arg->getElement(i), valueType, loc);
7206-
if (!valueExpr)
7207-
return nullptr;
7204+
assert(valueExpr && "Failed to coerce?");
72087205
Expr *pair = TupleExpr::createImplicit(ctx, {labelExpr, valueExpr}, {});
72097206
auto eltTypes = { TupleTypeElt(keyType), TupleTypeElt(valueType) };
72107207
cs.setType(pair, TupleType::get(eltTypes, ctx));
@@ -7217,22 +7214,21 @@ ExprRewriter::finishApplyDynamicCallable(ApplyExpr *apply,
72177214
}
72187215
argument->setImplicit();
72197216

7220-
// Construct call to the `dynamicallyCall` method.
7221-
auto result = CallExpr::createImplicit(ctx, member, argument,
7222-
{ argumentLabel });
7223-
cs.setType(result->getArg(), AnyFunctionType::composeInput(ctx, params,
7224-
false));
7225-
cs.setType(result, methodType->getResult());
7226-
cs.cacheExprTypes(result);
7227-
return result;
7217+
// Build the argument list expr.
7218+
argument = TupleExpr::createImplicit(ctx, {argument}, {argumentLabel});
7219+
cs.setType(argument,
7220+
TupleType::get({TupleTypeElt(argumentType, argumentLabel)}, ctx));
7221+
7222+
return std::make_pair(member, argument);
72287223
}
72297224

72307225
Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType,
72317226
ConstraintLocatorBuilder locator,
72327227
ConstraintLocatorBuilder calleeLocator) {
72337228
auto &ctx = cs.getASTContext();
7234-
7235-
auto fn = apply->getFn();
7229+
7230+
auto *arg = apply->getArg();
7231+
auto *fn = apply->getFn();
72367232

72377233
bool hasTrailingClosure =
72387234
isa<CallExpr>(apply) && cast<CallExpr>(apply)->hasTrailingClosure();
@@ -7401,7 +7397,7 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType,
74017397
if (method && methodType) {
74027398
// Handle a call to a @dynamicCallable method.
74037399
if (isValidDynamicCallableMethod(method, methodType))
7404-
return finishApplyDynamicCallable(
7400+
std::tie(fn, arg) = buildDynamicCallable(
74057401
apply, *selected, method, methodType, applyFunctionLoc);
74067402
}
74077403
}
@@ -7458,13 +7454,11 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType,
74587454
// the function.
74597455
SmallVector<Identifier, 2> argLabelsScratch;
74607456
if (auto fnType = cs.getType(fn)->getAs<FunctionType>()) {
7461-
auto origArg = apply->getArg();
7462-
Expr *arg = coerceCallArguments(origArg, fnType, callee,
7463-
apply,
7464-
apply->getArgumentLabels(argLabelsScratch),
7465-
hasTrailingClosure,
7466-
locator.withPathElement(
7467-
ConstraintLocator::ApplyArgument));
7457+
arg = coerceCallArguments(arg, fnType, callee, apply,
7458+
apply->getArgumentLabels(argLabelsScratch),
7459+
hasTrailingClosure,
7460+
locator.withPathElement(
7461+
ConstraintLocator::ApplyArgument));
74687462
if (!arg) {
74697463
return nullptr;
74707464
}

test/SILGen/dynamic_callable_attribute.swift

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,35 @@ public struct Callable2 {
3838
public func keywordCoerceBug(a: Callable2, s: Int) {
3939
a(s)
4040
}
41+
42+
@dynamicCallable
43+
struct S {
44+
func dynamicallyCall(withArguments x: [Int]) -> Int! { nil }
45+
}
46+
47+
@dynamicCallable
48+
protocol P1 {
49+
func dynamicallyCall(withKeywordArguments: [String: Any])
50+
}
51+
52+
@dynamicCallable
53+
protocol P2 {
54+
func dynamicallyCall(withArguments x: [Int]) -> Self
55+
}
56+
57+
@dynamicCallable
58+
class C {
59+
func dynamicallyCall(withKeywordArguments x: [String: String]) -> Self { return self }
60+
}
61+
62+
// 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) -> ()
63+
func test_dynamic_callables<T : C>(_ s: S, _ p1: P1, _ p2: P2, _ t: T) {
64+
// SR-12615: Compiler crash on @dynamicCallable IUO.
65+
// CHECK: function_ref @$s26dynamic_callable_attribute1SV15dynamicallyCall13withArgumentsSiSgSaySiG_tF : $@convention(method) (@guaranteed Array<Int>, S) -> Optional<Int>
66+
// CHECK: switch_enum %{{.+}} : $Optional<Int>
67+
let _: Int = s(0)
68+
69+
// CHECK: class_method %{{.+}} : $C, #C.dynamicallyCall : (C) -> ([String : String]) -> @dynamic_self C, $@convention(method) (@guaranteed Dictionary<String, String>, @guaranteed C) -> @owned C
70+
// CHECK: unchecked_ref_cast %{{.+}} : $C to $T
71+
_ = t("")
72+
}

0 commit comments

Comments
 (0)