Skip to content

Commit 383c8c8

Browse files
committed
[Sema] WitnessMatching: Warn about sendability mismatches associated with ObjC requirements
Since importer ignored `swift_attr` that appeared in a type context until recently we need to maintain status quo with concurrency stripping from ObjC requirements in modes that don't have full concurrency checking enabled. (cherry picked from commit c06a1a8)
1 parent da067e8 commit 383c8c8

File tree

3 files changed

+59
-52
lines changed

3 files changed

+59
-52
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5578,6 +5578,35 @@ bool ConstraintSystem::repairFailures(
55785578
return false;
55795579
}
55805580

5581+
if (auto *VD = getAsDecl<ValueDecl>(anchor)) {
5582+
// Matching a witness to a ObjC protocol requirement.
5583+
if (VD->isObjC() && VD->isProtocolRequirement() &&
5584+
path[0].is<LocatorPathElt::Witness>() &&
5585+
// Note that the condition below is very important,
5586+
// we need to wait until the very last moment to strip
5587+
// the concurrency annotations from the inner most type.
5588+
conversionsOrFixes.empty()) {
5589+
// `swift_attr` attributes in the type context were ignored before,
5590+
// which means that we need to maintain status quo to avoid breaking
5591+
// witness matching by stripping everything concurrency related from
5592+
// inner types in non-full checking mode.
5593+
if (!(Context.isSwiftVersionAtLeast(6) ||
5594+
Context.LangOpts.StrictConcurrencyLevel ==
5595+
StrictConcurrency::Complete)) {
5596+
auto strippedLHS = lhs->stripConcurrency(/*resursive=*/true,
5597+
/*dropGlobalActor=*/true);
5598+
auto strippedRHS = rhs->stripConcurrency(/*resursive=*/true,
5599+
/*dropGlobalActor=*/true);
5600+
auto result = matchTypes(strippedLHS, strippedRHS, matchKind,
5601+
flags | TMF_ApplyingFix, locator);
5602+
if (!result.isFailure()) {
5603+
increaseScore(SK_MissingSynthesizableConformance, locator);
5604+
return true;
5605+
}
5606+
}
5607+
}
5608+
}
5609+
55815610
auto elt = path.back();
55825611
switch (elt.getKind()) {
55835612
case ConstraintLocator::LValueConversion: {

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 25 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1172,43 +1172,6 @@ swift::matchWitness(WitnessChecker::RequirementEnvironmentCache &reqEnvCache,
11721172
// Match a type in the requirement to a type in the witness.
11731173
auto matchTypes = [&](Type reqType,
11741174
Type witnessType) -> std::optional<RequirementMatch> {
1175-
// `swift_attr` attributes in the type context were ignored before,
1176-
// which means that we need to maintain status quo to avoid breaking
1177-
// witness matching by stripping everything concurrency related from
1178-
// inner types.
1179-
auto shouldStripConcurrency = [&]() {
1180-
if (!req->isObjC())
1181-
return false;
1182-
1183-
auto &ctx = dc->getASTContext();
1184-
return !(ctx.isSwiftVersionAtLeast(6) ||
1185-
ctx.LangOpts.StrictConcurrencyLevel ==
1186-
StrictConcurrency::Complete);
1187-
};
1188-
1189-
if (shouldStripConcurrency()) {
1190-
if (reqType->is<FunctionType>()) {
1191-
auto *fnTy = reqType->castTo<FunctionType>();
1192-
SmallVector<AnyFunctionType::Param, 4> params;
1193-
llvm::transform(fnTy->getParams(), std::back_inserter(params),
1194-
[&](const AnyFunctionType::Param &param) {
1195-
return param.withType(
1196-
param.getPlainType()->stripConcurrency(
1197-
/*recursive=*/true,
1198-
/*dropGlobalActor=*/true));
1199-
});
1200-
1201-
auto resultTy =
1202-
fnTy->getResult()->stripConcurrency(/*recursive=*/true,
1203-
/*dropGlobalActor=*/true);
1204-
1205-
reqType = FunctionType::get(params, resultTy, fnTy->getExtInfo());
1206-
} else {
1207-
reqType = reqType->stripConcurrency(/*recursive=*/true,
1208-
/*dropGlobalActor=*/true);
1209-
}
1210-
}
1211-
12121175
cs->addConstraint(ConstraintKind::Bind, reqType, witnessType,
12131176
witnessLocator);
12141177
// FIXME: Check whether this has already failed.
@@ -1234,14 +1197,31 @@ swift::matchWitness(WitnessChecker::RequirementEnvironmentCache &reqEnvCache,
12341197
return *result;
12351198
}
12361199
}
1237-
bool requiresNonSendable = false;
1238-
if (!solution || solution->Fixes.size()) {
1239-
/// If the *only* problems are that `@Sendable` attributes are missing,
1240-
/// allow the match in some circumstances.
1241-
requiresNonSendable = solution
1242-
&& llvm::all_of(solution->Fixes, [](constraints::ConstraintFix *fix) {
1243-
return fix->getKind() == constraints::FixKind::AddSendableAttribute;
1244-
});
1200+
1201+
bool requiresNonSendable = [&]() {
1202+
if (!solution)
1203+
return false;
1204+
1205+
// If the *only* problems are that `@Sendable` attributes are missing,
1206+
// allow the match in some circumstances.
1207+
if (!solution->Fixes.empty()) {
1208+
return llvm::all_of(solution->Fixes,
1209+
[](constraints::ConstraintFix *fix) {
1210+
return fix->getKind() ==
1211+
constraints::FixKind::AddSendableAttribute;
1212+
});
1213+
}
1214+
1215+
// If there are no other issues, let's check whether this are
1216+
// missing Sendable conformances when matching ObjC requirements.
1217+
// This is not an error until Swift 6 because `swift_attr` wasn't
1218+
// allowed in type contexts initially.
1219+
return req->isObjC() &&
1220+
solution->getFixedScore()
1221+
.Data[SK_MissingSynthesizableConformance] > 0;
1222+
}();
1223+
1224+
if (!solution || !solution->Fixes.empty()) {
12451225
if (!requiresNonSendable)
12461226
return RequirementMatch(witness, MatchKind::TypeConflict,
12471227
witnessType);

test/Concurrency/sendable_objc_attr_in_type_context_swift5.swift

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -109,21 +109,19 @@ func test_sendable_attr_in_type_context(test: Test) {
109109
}
110110

111111
class TestConformanceWithStripping : InnerSendableTypes {
112-
func test(_ options: [String: Any]) { // Ok
112+
func test(_ options: [String: Any]) {
113+
// expected-warning@-1 {{sendability of function types in instance method 'test' does not match requirement in protocol 'InnerSendableTypes'; this is an error in the Swift 6 language mode}}
113114
}
114115

115116
func test(withCallback name: String, handler: @escaping @MainActor ([String : Any], (any Error)?) -> Void) { // Ok
117+
// expected-warning@-1 {{sendability of function types in instance method 'test(withCallback:handler:)' does not match requirement in protocol 'InnerSendableTypes'; this is an error in the Swift 6 language mode}}
116118
}
117119
}
118120

119121
class TestConformanceWithoutStripping : InnerSendableTypes {
120-
// expected-error@-1 {{type 'TestConformanceWithoutStripping' does not conform to protocol 'InnerSendableTypes'}}
121-
122-
func test(_ options: [String: any Sendable]) {
123-
// expected-note@-1 {{candidate has non-matching type '([String : any Sendable]) -> ()'}}
122+
func test(_ options: [String: any Sendable]) { // Ok
124123
}
125124

126-
func test(withCallback name: String, handler: @escaping @MainActor ([String : any Sendable], (any Error)?) -> Void) {
127-
// expected-note@-1 {{candidate has non-matching type '(String, @escaping @MainActor ([String : any Sendable], (any Error)?) -> Void) -> ()'}}
125+
func test(withCallback name: String, handler: @escaping @MainActor ([String : any Sendable], (any Error)?) -> Void) { // Ok
128126
}
129127
}

0 commit comments

Comments
 (0)