Skip to content

Commit 379d73c

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 b90aeeb commit 379d73c

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
@@ -1549,12 +1549,11 @@ namespace {
15491549
ConstraintLocatorBuilder locator,
15501550
ConstraintLocatorBuilder calleeLocator);
15511551

1552-
// Resolve `@dynamicCallable` applications.
1553-
Expr *finishApplyDynamicCallable(ApplyExpr *apply,
1554-
SelectedOverload selected,
1555-
FuncDecl *method,
1556-
AnyFunctionType *methodType,
1557-
ConstraintLocatorBuilder applyFunctionLoc);
1552+
/// Build the function and argument for a `@dynamicCallable` application.
1553+
std::pair</*fn*/ Expr *, /*arg*/ Expr *>
1554+
buildDynamicCallable(ApplyExpr *apply, SelectedOverload selected,
1555+
FuncDecl *method, AnyFunctionType *methodType,
1556+
ConstraintLocatorBuilder applyFunctionLoc);
15581557

15591558
private:
15601559
/// Simplify the given type by substituting all occurrences of
@@ -7153,12 +7152,11 @@ static Expr *buildCallAsFunctionMethodRef(
71537152
}
71547153

71557154
// Resolve `@dynamicCallable` applications.
7156-
Expr *
7157-
ExprRewriter::finishApplyDynamicCallable(ApplyExpr *apply,
7158-
SelectedOverload selected,
7159-
FuncDecl *method,
7160-
AnyFunctionType *methodType,
7161-
ConstraintLocatorBuilder loc) {
7155+
std::pair<Expr *, Expr *>
7156+
ExprRewriter::buildDynamicCallable(ApplyExpr *apply, SelectedOverload selected,
7157+
FuncDecl *method,
7158+
AnyFunctionType *methodType,
7159+
ConstraintLocatorBuilder loc) {
71627160
auto &ctx = cs.getASTContext();
71637161
auto *fn = apply->getFn();
71647162

@@ -7210,8 +7208,7 @@ ExprRewriter::finishApplyDynamicCallable(ApplyExpr *apply,
72107208
handleStringLiteralExpr(cast<LiteralExpr>(labelExpr));
72117209

72127210
Expr *valueExpr = coerceToType(arg->getElement(i), valueType, loc);
7213-
if (!valueExpr)
7214-
return nullptr;
7211+
assert(valueExpr && "Failed to coerce?");
72157212
Expr *pair = TupleExpr::createImplicit(ctx, {labelExpr, valueExpr}, {});
72167213
auto eltTypes = { TupleTypeElt(keyType), TupleTypeElt(valueType) };
72177214
cs.setType(pair, TupleType::get(eltTypes, ctx));
@@ -7224,22 +7221,21 @@ ExprRewriter::finishApplyDynamicCallable(ApplyExpr *apply,
72247221
}
72257222
argument->setImplicit();
72267223

7227-
// Construct call to the `dynamicallyCall` method.
7228-
auto result = CallExpr::createImplicit(ctx, member, argument,
7229-
{ argumentLabel });
7230-
cs.setType(result->getArg(), AnyFunctionType::composeInput(ctx, params,
7231-
false));
7232-
cs.setType(result, methodType->getResult());
7233-
cs.cacheExprTypes(result);
7234-
return result;
7224+
// Build the argument list expr.
7225+
argument = TupleExpr::createImplicit(ctx, {argument}, {argumentLabel});
7226+
cs.setType(argument,
7227+
TupleType::get({TupleTypeElt(argumentType, argumentLabel)}, ctx));
7228+
7229+
return std::make_pair(member, argument);
72357230
}
72367231

72377232
Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType,
72387233
ConstraintLocatorBuilder locator,
72397234
ConstraintLocatorBuilder calleeLocator) {
72407235
auto &ctx = cs.getASTContext();
7241-
7242-
auto fn = apply->getFn();
7236+
7237+
auto *arg = apply->getArg();
7238+
auto *fn = apply->getFn();
72437239

72447240
bool hasTrailingClosure =
72457241
isa<CallExpr>(apply) && cast<CallExpr>(apply)->hasTrailingClosure();
@@ -7408,7 +7404,7 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType,
74087404
if (method && methodType) {
74097405
// Handle a call to a @dynamicCallable method.
74107406
if (isValidDynamicCallableMethod(method, methodType))
7411-
return finishApplyDynamicCallable(
7407+
std::tie(fn, arg) = buildDynamicCallable(
74127408
apply, *selected, method, methodType, applyFunctionLoc);
74137409
}
74147410
}
@@ -7465,13 +7461,11 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType,
74657461
// the function.
74667462
SmallVector<Identifier, 2> argLabelsScratch;
74677463
if (auto fnType = cs.getType(fn)->getAs<FunctionType>()) {
7468-
auto origArg = apply->getArg();
7469-
Expr *arg = coerceCallArguments(origArg, fnType, callee,
7470-
apply,
7471-
apply->getArgumentLabels(argLabelsScratch),
7472-
hasTrailingClosure,
7473-
locator.withPathElement(
7474-
ConstraintLocator::ApplyArgument));
7464+
arg = coerceCallArguments(arg, fnType, callee, apply,
7465+
apply->getArgumentLabels(argLabelsScratch),
7466+
hasTrailingClosure,
7467+
locator.withPathElement(
7468+
ConstraintLocator::ApplyArgument));
74757469
if (!arg) {
74767470
return nullptr;
74777471
}

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)