Skip to content

Commit e4943b1

Browse files
committed
Introduce a function conversion for "adjusted" dynamic member references.
When we have adjusted the type of a dynamic member reference (e.g., for `@objc optional` methods) due to `@preconcurrency` or similar, form the original dynamic member reference based on the original type and then introduce an appropriate conversion. This better reflects the adjustment in the AST, eliminating a SIL verifier crash. Fixes rdar://94597323.
1 parent 755e7bd commit e4943b1

File tree

2 files changed

+63
-2
lines changed

2 files changed

+63
-2
lines changed

lib/Sema/CSApply.cpp

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -896,6 +896,48 @@ namespace {
896896
return closedAny;
897897
}
898898

899+
/// When we have a reference to a declaration whose type in context is
900+
/// different from its normal interface type, introduce the appropriate
901+
/// conversions. This can happen due to `@preconcurrency`.
902+
Expr *adjustTypeForDeclReference(
903+
Expr *expr, Type openedType, Type adjustedOpenedType,
904+
llvm::function_ref<Type(Type)> getNewType = [](Type type) {
905+
return type;
906+
}) {
907+
// If the types are the same, do nothing.
908+
if (openedType->isEqual(adjustedOpenedType))
909+
return expr;
910+
911+
auto &context = cs.getASTContext();
912+
913+
// If we have an optional type, wrap it up in a monadic '?' and recurse.
914+
if (Type objectType = openedType->getOptionalObjectType()) {
915+
Type adjustedRefType = getNewType(adjustedOpenedType);
916+
Type adjustedObjectType = adjustedRefType->getOptionalObjectType();
917+
assert(adjustedObjectType && "Not an optional?");
918+
919+
expr = new (context) BindOptionalExpr(expr, SourceLoc(), 0, objectType);
920+
cs.cacheType(expr);
921+
expr = adjustTypeForDeclReference(expr, objectType, adjustedObjectType);
922+
expr = new (context) InjectIntoOptionalExpr(expr, adjustedRefType);
923+
cs.cacheType(expr);
924+
expr = new (context) OptionalEvaluationExpr(expr, adjustedRefType);
925+
cs.cacheType(expr);
926+
return expr;
927+
}
928+
929+
// For a function type, perform a function conversion.
930+
if (openedType->is<AnyFunctionType>()) {
931+
expr = new (context) FunctionConversionExpr(
932+
expr, getNewType(adjustedOpenedType));
933+
cs.cacheType(expr);
934+
return expr;
935+
}
936+
937+
assert(false && "Unhandled adjustment");
938+
return expr;
939+
}
940+
899941
/// Determines if a partially-applied member reference should be
900942
/// converted into a fully-applied member reference with a pair of
901943
/// closures.
@@ -1388,6 +1430,7 @@ namespace {
13881430
ConstraintLocatorBuilder memberLocator, bool Implicit,
13891431
AccessSemantics semantics) {
13901432
const auto &choice = overload.choice;
1433+
const auto openedType = overload.openedType;
13911434
const auto adjustedOpenedType = overload.adjustedOpenedType;
13921435

13931436
ValueDecl *member = choice.getDecl();
@@ -1597,7 +1640,7 @@ namespace {
15971640

15981641
auto computeRefType = [&](Type openedType) {
15991642
// Compute the type of the reference.
1600-
Type refType = simplifyType(adjustedOpenedType);
1643+
Type refType = simplifyType(openedType);
16011644

16021645
// If the base was an opened existential, erase the opened
16031646
// existential.
@@ -1609,9 +1652,13 @@ namespace {
16091652
return refType;
16101653
};
16111654

1612-
Type refType = computeRefType(adjustedOpenedType);
1655+
Type refType = computeRefType(openedType);
16131656
cs.setType(ref, refType);
16141657

1658+
// Adjust the declaration reference type, if required.
1659+
ref = adjustTypeForDeclReference(
1660+
ref, openedType, adjustedOpenedType, computeRefType);
1661+
16151662
closeExistentials(ref, locator, /*force=*/openedExistential);
16161663

16171664
// We also need to handle the implicitly unwrap of the result

test/SILGen/objc_preconcurrency.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// RUN: %target-swift-emit-silgen -module-name objc_preconcurrency -sdk %S/Inputs -I %S/Inputs -enable-source-import %s -disable-objc-attr-requires-foundation-module | %FileCheck %s
2+
3+
// REQUIRES: objc_interop
4+
5+
@objc protocol P {
6+
@preconcurrency @objc optional func f(_ completionHandler: @Sendable @escaping () -> Void)
7+
}
8+
9+
// CHECK-LABEL: sil hidden [ossa] @$s19objc_preconcurrency19testDynamicDispatch1p17completionHandleryAA1P_p_yyctF
10+
// CHECK: dynamic_method_br
11+
// CHECK: bb{{[0-9]+}}(%{{[0-9]+}} : $@convention(objc_method) (@convention(block) @Sendable () -> (), @opened
12+
func testDynamicDispatch(p: P, completionHandler: @escaping () -> Void) {
13+
p.f?(completionHandler)
14+
}

0 commit comments

Comments
 (0)