Skip to content

Commit 08ec1ba

Browse files
authored
Merge pull request swiftlang#18085 from jckarter/inout-existential-opened-type-function-conversion
SILGen: Delay function conversions to types with opened archetype arguments.
2 parents 103170b + 3474079 commit 08ec1ba

File tree

2 files changed

+68
-2
lines changed

2 files changed

+68
-2
lines changed

lib/SILGen/SILGenApply.cpp

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1867,7 +1867,10 @@ class DelayedArgument {
18671867
/// A string r-value needs to be converted to a pointer type.
18681868
RValueStringToPointer,
18691869

1870-
LastRVKind = RValueStringToPointer,
1870+
/// A function conversion needs to occur.
1871+
FunctionConversion,
1872+
1873+
LastRVKind = FunctionConversion,
18711874

18721875
/// A default argument that needs to be evaluated.
18731876
DefaultArgument,
@@ -2038,6 +2041,7 @@ class DelayedArgument {
20382041
case LValueArrayToPointer:
20392042
case RValueArrayToPointer:
20402043
case RValueStringToPointer:
2044+
case FunctionConversion:
20412045
args[argIndex] = finishOriginalArgument(SGF);
20422046
return;
20432047
case DefaultArgument:
@@ -2121,7 +2125,8 @@ class DelayedArgument {
21212125
// Done with the recursive cases. Make sure we handled everything.
21222126
assert(isa<InOutToPointerExpr>(expr) ||
21232127
isa<ArrayToPointerExpr>(expr) ||
2124-
isa<StringToPointerExpr>(expr));
2128+
isa<StringToPointerExpr>(expr) ||
2129+
isa<FunctionConversionExpr>(expr));
21252130

21262131
switch (Kind) {
21272132
case InOut:
@@ -2154,6 +2159,17 @@ class DelayedArgument {
21542159
return SGF.emitStringToPointer(pointerExpr, stringValue,
21552160
pointerExpr->getType());
21562161
}
2162+
case FunctionConversion: {
2163+
auto funcConv = cast<FunctionConversionExpr>(expr);
2164+
auto optFuncValue = RV().RV;
2165+
auto funcValue =
2166+
emitBindOptionals(SGF, optFuncValue, funcConv->getSubExpr());
2167+
return {SGF.emitTransformedValue(funcConv, funcValue,
2168+
funcConv->getSubExpr()->getType()->getCanonicalType(),
2169+
funcConv->getType()->getCanonicalType(),
2170+
SGFContext()),
2171+
ManagedValue()};
2172+
}
21572173
}
21582174
llvm_unreachable("bad kind");
21592175
}
@@ -2747,6 +2763,37 @@ class ArgEmitter {
27472763
if (auto stringToPointer = dyn_cast<StringToPointerExpr>(expr)) {
27482764
return emitDelayedConversion(stringToPointer, original);
27492765
}
2766+
2767+
// Delay function conversions involving the opened Self type of an
2768+
// existential whose opening is itself delayed.
2769+
//
2770+
// This comes up when invoking protocol methods on an existential that
2771+
// have covariant arguments of function type with Self arguments, e.g.:
2772+
//
2773+
// protocol P {
2774+
// mutating func foo(_: (Self) -> Void)
2775+
// }
2776+
//
2777+
// func bar(x: inout P) {
2778+
// x.foo { y in return }
2779+
// }
2780+
//
2781+
// Although the type-erased method is presented as formally taking an
2782+
// argument of the existential type P, it still has a conversion thunk to
2783+
// perform type erasure on the argument coming from the underlying
2784+
// implementation. Since the `self` argument is inout, it isn't formally
2785+
// opened until late when formal accesses begin, so this closure conversion
2786+
// must also be deferred until after that occurs.
2787+
if (auto funcConv = dyn_cast<FunctionConversionExpr>(expr)) {
2788+
auto destTy = funcConv->getType()->castTo<AnyFunctionType>();
2789+
auto srcTy = funcConv->getSubExpr()->getType()->castTo<AnyFunctionType>();
2790+
2791+
if (destTy->hasOpenedExistential()
2792+
&& !srcTy->hasOpenedExistential()
2793+
&& destTy->getRepresentation() == srcTy->getRepresentation()) {
2794+
return emitDelayedConversion(funcConv, original);
2795+
}
2796+
}
27502797

27512798
// Any recursive cases we handle here need to be handled in
27522799
// DelayedArgument::finishOriginalExpr.
@@ -2828,6 +2875,16 @@ class ArgEmitter {
28282875
Args.push_back(ManagedValue());
28292876
return true;
28302877
}
2878+
2879+
bool emitDelayedConversion(FunctionConversionExpr *funcConv,
2880+
OriginalArgument original) {
2881+
auto rvalueExpr = lookThroughBindOptionals(funcConv->getSubExpr());
2882+
ManagedValue value = SGF.emitRValueAsSingleValue(rvalueExpr);
2883+
DelayedArguments.emplace_back(DelayedArgument::FunctionConversion,
2884+
value, original);
2885+
Args.push_back(ManagedValue());
2886+
return true;
2887+
}
28312888

28322889
static Expr *lookThroughBindOptionals(Expr *expr) {
28332890
while (true) {
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// RUN: %target-swift-emit-silgen -verify %s
2+
3+
protocol P {
4+
mutating func foo(_: (Self) -> Void)
5+
}
6+
7+
func foo(x: inout P) {
8+
x.foo { y in return }
9+
}

0 commit comments

Comments
 (0)