Skip to content

Commit e6d508b

Browse files
authored
Merge pull request #18086 from jckarter/inout-existential-opened-type-function-conversion-4.2
[4.2] SILGen: Delay function conversions to types with opened archetype arguments.
2 parents 1253f0d + d4d66ca commit e6d508b

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
@@ -1869,7 +1869,10 @@ class DelayedArgument {
18691869
/// A string r-value needs to be converted to a pointer type.
18701870
RValueStringToPointer,
18711871

1872-
LastRVKind = RValueStringToPointer,
1872+
/// A function conversion needs to occur.
1873+
FunctionConversion,
1874+
1875+
LastRVKind = FunctionConversion,
18731876

18741877
/// A default argument that needs to be evaluated.
18751878
DefaultArgument,
@@ -2040,6 +2043,7 @@ class DelayedArgument {
20402043
case LValueArrayToPointer:
20412044
case RValueArrayToPointer:
20422045
case RValueStringToPointer:
2046+
case FunctionConversion:
20432047
args[argIndex] = finishOriginalArgument(SGF);
20442048
return;
20452049
case DefaultArgument:
@@ -2123,7 +2127,8 @@ class DelayedArgument {
21232127
// Done with the recursive cases. Make sure we handled everything.
21242128
assert(isa<InOutToPointerExpr>(expr) ||
21252129
isa<ArrayToPointerExpr>(expr) ||
2126-
isa<StringToPointerExpr>(expr));
2130+
isa<StringToPointerExpr>(expr) ||
2131+
isa<FunctionConversionExpr>(expr));
21272132

21282133
switch (Kind) {
21292134
case InOut:
@@ -2156,6 +2161,17 @@ class DelayedArgument {
21562161
return SGF.emitStringToPointer(pointerExpr, stringValue,
21572162
pointerExpr->getType());
21582163
}
2164+
case FunctionConversion: {
2165+
auto funcConv = cast<FunctionConversionExpr>(expr);
2166+
auto optFuncValue = RV().RV;
2167+
auto funcValue =
2168+
emitBindOptionals(SGF, optFuncValue, funcConv->getSubExpr());
2169+
return {SGF.emitTransformedValue(funcConv, funcValue,
2170+
funcConv->getSubExpr()->getType()->getCanonicalType(),
2171+
funcConv->getType()->getCanonicalType(),
2172+
SGFContext()),
2173+
ManagedValue()};
2174+
}
21592175
}
21602176
llvm_unreachable("bad kind");
21612177
}
@@ -2739,6 +2755,37 @@ class ArgEmitter {
27392755
if (auto stringToPointer = dyn_cast<StringToPointerExpr>(expr)) {
27402756
return emitDelayedConversion(stringToPointer, original);
27412757
}
2758+
2759+
// Delay function conversions involving the opened Self type of an
2760+
// existential whose opening is itself delayed.
2761+
//
2762+
// This comes up when invoking protocol methods on an existential that
2763+
// have covariant arguments of function type with Self arguments, e.g.:
2764+
//
2765+
// protocol P {
2766+
// mutating func foo(_: (Self) -> Void)
2767+
// }
2768+
//
2769+
// func bar(x: inout P) {
2770+
// x.foo { y in return }
2771+
// }
2772+
//
2773+
// Although the type-erased method is presented as formally taking an
2774+
// argument of the existential type P, it still has a conversion thunk to
2775+
// perform type erasure on the argument coming from the underlying
2776+
// implementation. Since the `self` argument is inout, it isn't formally
2777+
// opened until late when formal accesses begin, so this closure conversion
2778+
// must also be deferred until after that occurs.
2779+
if (auto funcConv = dyn_cast<FunctionConversionExpr>(expr)) {
2780+
auto destTy = funcConv->getType()->castTo<AnyFunctionType>();
2781+
auto srcTy = funcConv->getSubExpr()->getType()->castTo<AnyFunctionType>();
2782+
2783+
if (destTy->hasOpenedExistential()
2784+
&& !srcTy->hasOpenedExistential()
2785+
&& destTy->getRepresentation() == srcTy->getRepresentation()) {
2786+
return emitDelayedConversion(funcConv, original);
2787+
}
2788+
}
27422789

27432790
// Any recursive cases we handle here need to be handled in
27442791
// DelayedArgument::finishOriginalExpr.
@@ -2820,6 +2867,16 @@ class ArgEmitter {
28202867
Args.push_back(ManagedValue());
28212868
return true;
28222869
}
2870+
2871+
bool emitDelayedConversion(FunctionConversionExpr *funcConv,
2872+
OriginalArgument original) {
2873+
auto rvalueExpr = lookThroughBindOptionals(funcConv->getSubExpr());
2874+
ManagedValue value = SGF.emitRValueAsSingleValue(rvalueExpr);
2875+
DelayedArguments.emplace_back(DelayedArgument::FunctionConversion,
2876+
value, original);
2877+
Args.push_back(ManagedValue());
2878+
return true;
2879+
}
28232880

28242881
static Expr *lookThroughBindOptionals(Expr *expr) {
28252882
while (true) {
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// RUN: %target-swift-frontend -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)