Skip to content

Commit 2de86dc

Browse files
authored
Merge pull request swiftlang#72679 from xedin/improvements-to-protocol-witness-matching-6.0
[6.0][Sema/ClangImporter] Improvements to witness matching
2 parents a172a42 + 2ec39ba commit 2de86dc

12 files changed

+114
-81
lines changed

include/swift/Sema/ConstraintLocator.h

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -820,18 +820,6 @@ class LocatorPathElt::Witness final : public StoredPointerElement<ValueDecl> {
820820
}
821821
};
822822

823-
class LocatorPathElt::ProtocolRequirement final : public StoredPointerElement<ValueDecl> {
824-
public:
825-
ProtocolRequirement(ValueDecl *decl)
826-
: StoredPointerElement(PathElementKind::ProtocolRequirement, decl) {}
827-
828-
ValueDecl *getDecl() const { return getStoredPointer(); }
829-
830-
static bool classof(const LocatorPathElt *elt) {
831-
return elt->getKind() == PathElementKind::ProtocolRequirement;
832-
}
833-
};
834-
835823
class LocatorPathElt::GenericParameter final : public StoredPointerElement<GenericTypeParamType> {
836824
public:
837825
GenericParameter(GenericTypeParamType *type)

include/swift/Sema/ConstraintLocatorPathElts.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ SIMPLE_LOCATOR_PATH_ELT(ParentType)
161161

162162
/// The requirement that we're matching during protocol conformance
163163
/// checking.
164-
CUSTOM_LOCATOR_PATH_ELT(ProtocolRequirement)
164+
SIMPLE_LOCATOR_PATH_ELT(ProtocolRequirement)
165165

166166
/// Type parameter requirements.
167167
ABSTRACT_LOCATOR_PATH_ELT(AnyRequirement)

lib/AST/Type.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -989,6 +989,9 @@ Type TypeBase::stripConcurrency(bool recurse, bool dropGlobalActor) {
989989
existentialType->getConstraintType().getPointer())
990990
return Type(this);
991991

992+
if (newConstraintType->getClassOrBoundGenericClass())
993+
return newConstraintType;
994+
992995
return ExistentialType::get(newConstraintType);
993996
}
994997

lib/ClangImporter/ImportType.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1916,7 +1916,13 @@ class GetSendableType :
19161916
auto composition =
19171917
ProtocolCompositionType::get(ctx, members, inverses, explicitAnyObject);
19181918

1919-
return { composition, true };
1919+
// If we started from a protocol or a composition we should already
1920+
// be in an existential context. Otherwise we'd have to wrap a new
1921+
// composition into an existential.
1922+
if (isa<ProtocolType>(ty) || isa<ProtocolCompositionType>(ty))
1923+
return {composition, true};
1924+
1925+
return {ExistentialType::get(composition), true};
19201926
}
19211927

19221928
/// Visitor action: Recurse into the children of this type and try to add

lib/Sema/CSSimplify.cpp

Lines changed: 30 additions & 1 deletion
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+
// Allow requirements to introduce `swift_attr` annotations
5590+
// (note that `swift_attr` in type contexts weren't supported
5591+
// before) and for witnesses to adopt them gradually by matching
5592+
// with a warning in non-strict concurrency 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: {
@@ -8552,7 +8581,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
85528581
auto synthesizeConformance = [&]() {
85538582
ProtocolConformanceRef synthesized(protocol);
85548583
auto witnessLoc = getConstraintLocator(
8555-
/*anchor=*/{}, LocatorPathElt::Witness(witness));
8584+
locator.getAnchor(), LocatorPathElt::Witness(witness));
85568585
SynthesizedConformances.insert({witnessLoc, synthesized});
85578586
return recordConformance(synthesized);
85588587
};

lib/Sema/ConstraintLocator.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -304,9 +304,7 @@ void LocatorPathElt::dump(raw_ostream &out) const {
304304
break;
305305
}
306306
case ConstraintLocator::ProtocolRequirement: {
307-
auto reqElt = elt.castTo<LocatorPathElt::ProtocolRequirement>();
308-
out << "protocol requirement ";
309-
reqElt.getDecl()->dumpRef(out);
307+
out << "protocol requirement";
310308
break;
311309
}
312310
case ConstraintLocator::Witness: {

lib/Sema/ConstraintSystem.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7985,6 +7985,16 @@ void constraints::dumpAnchor(ASTNode anchor, SourceManager *SM,
79857985
out << '@';
79867986
pattern->getLoc().print(out, *SM);
79877987
}
7988+
} else if (auto *decl = anchor.dyn_cast<Decl *>()) {
7989+
if (auto *VD = dyn_cast<ValueDecl>(decl)) {
7990+
VD->dumpRef(out);
7991+
} else {
7992+
out << "<<" << Decl::getKindName(decl->getKind()) << ">>";
7993+
if (SM) {
7994+
out << "@";
7995+
decl->getLoc().print(out, *SM);
7996+
}
7997+
}
79887998
}
79897999
// TODO(diagnostics): Implement the rest of the cases.
79908000
}

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 31 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1027,7 +1027,6 @@ swift::matchWitness(WitnessChecker::RequirementEnvironmentCache &reqEnvCache,
10271027

10281028
// Initialized by the setup operation.
10291029
std::optional<ConstraintSystem> cs;
1030-
ConstraintLocator *locator = nullptr;
10311030
ConstraintLocator *reqLocator = nullptr;
10321031
ConstraintLocator *witnessLocator = nullptr;
10331032
Type witnessType, openWitnessType;
@@ -1116,8 +1115,8 @@ swift::matchWitness(WitnessChecker::RequirementEnvironmentCache &reqEnvCache,
11161115
selfTy = syntheticEnv->mapTypeIntoContext(selfTy);
11171116

11181117
// Open up the type of the requirement.
1119-
reqLocator = cs->getConstraintLocator(
1120-
static_cast<Expr *>(nullptr), LocatorPathElt::ProtocolRequirement(req));
1118+
reqLocator =
1119+
cs->getConstraintLocator(req, ConstraintLocator::ProtocolRequirement);
11211120
OpenedTypeMap reqReplacements;
11221121
reqType = cs->getTypeOfMemberReference(selfTy, req, dc,
11231122
/*isDynamicResult=*/false,
@@ -1152,10 +1151,8 @@ swift::matchWitness(WitnessChecker::RequirementEnvironmentCache &reqEnvCache,
11521151

11531152
// Open up the witness type.
11541153
witnessType = witness->getInterfaceType();
1155-
// FIXME: witness as a base locator?
1156-
locator = cs->getConstraintLocator({});
1157-
witnessLocator = cs->getConstraintLocator({},
1158-
LocatorPathElt::Witness(witness));
1154+
witnessLocator =
1155+
cs->getConstraintLocator(req, LocatorPathElt::Witness(witness));
11591156
if (witness->getDeclContext()->isTypeContext()) {
11601157
openWitnessType = cs->getTypeOfMemberReference(
11611158
selfTy, witness, dc, /*isDynamicResult=*/false,
@@ -1175,44 +1172,8 @@ swift::matchWitness(WitnessChecker::RequirementEnvironmentCache &reqEnvCache,
11751172
// Match a type in the requirement to a type in the witness.
11761173
auto matchTypes = [&](Type reqType,
11771174
Type witnessType) -> std::optional<RequirementMatch> {
1178-
// `swift_attr` attributes in the type context were ignored before,
1179-
// which means that we need to maintain status quo to avoid breaking
1180-
// witness matching by stripping everything concurrency related from
1181-
// inner types.
1182-
auto shouldStripConcurrency = [&]() {
1183-
if (!req->isObjC())
1184-
return false;
1185-
1186-
auto &ctx = dc->getASTContext();
1187-
return !(ctx.isSwiftVersionAtLeast(6) ||
1188-
ctx.LangOpts.StrictConcurrencyLevel ==
1189-
StrictConcurrency::Complete);
1190-
};
1191-
1192-
if (shouldStripConcurrency()) {
1193-
if (reqType->is<FunctionType>()) {
1194-
auto *fnTy = reqType->castTo<FunctionType>();
1195-
SmallVector<AnyFunctionType::Param, 4> params;
1196-
llvm::transform(fnTy->getParams(), std::back_inserter(params),
1197-
[&](const AnyFunctionType::Param &param) {
1198-
return param.withType(
1199-
param.getPlainType()->stripConcurrency(
1200-
/*recursive=*/true,
1201-
/*dropGlobalActor=*/true));
1202-
});
1203-
1204-
auto resultTy =
1205-
fnTy->getResult()->stripConcurrency(/*recursive=*/true,
1206-
/*dropGlobalActor=*/true);
1207-
1208-
reqType = FunctionType::get(params, resultTy, fnTy->getExtInfo());
1209-
} else {
1210-
reqType = reqType->stripConcurrency(/*recursive=*/true,
1211-
/*dropGlobalActor=*/true);
1212-
}
1213-
}
1214-
1215-
cs->addConstraint(ConstraintKind::Bind, reqType, witnessType, locator);
1175+
cs->addConstraint(ConstraintKind::Bind, reqType, witnessType,
1176+
witnessLocator);
12161177
// FIXME: Check whether this has already failed.
12171178
return std::nullopt;
12181179
};
@@ -1236,14 +1197,31 @@ swift::matchWitness(WitnessChecker::RequirementEnvironmentCache &reqEnvCache,
12361197
return *result;
12371198
}
12381199
}
1239-
bool requiresNonSendable = false;
1240-
if (!solution || solution->Fixes.size()) {
1241-
/// If the *only* problems are that `@Sendable` attributes are missing,
1242-
/// allow the match in some circumstances.
1243-
requiresNonSendable = solution
1244-
&& llvm::all_of(solution->Fixes, [](constraints::ConstraintFix *fix) {
1245-
return fix->getKind() == constraints::FixKind::AddSendableAttribute;
1246-
});
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()) {
12471225
if (!requiresNonSendable)
12481226
return RequirementMatch(witness, MatchKind::TypeConflict,
12491227
witnessType);

test/Concurrency/sendable_objc_attr_in_type_context_swift5.swift

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ void doSomethingConcurrently(__attribute__((noescape)) void SWIFT_SENDABLE (^blo
5858
@end
5959

6060
@protocol InnerSendableTypes
61+
-(void) testComposition:(SWIFT_SENDABLE MyValue *)composition;
6162
-(void) test:(NSDictionary<NSString *, SWIFT_SENDABLE id> *)options;
6263
-(void) testWithCallback:(NSString *)name handler:(MAIN_ACTOR void (^)(NSDictionary<NSString *, SWIFT_SENDABLE id> *, NSError * _Nullable))handler;
6364
@end
@@ -109,21 +110,26 @@ func test_sendable_attr_in_type_context(test: Test) {
109110
}
110111

111112
class TestConformanceWithStripping : InnerSendableTypes {
112-
func test(_ options: [String: Any]) { // Ok
113+
func testComposition(_: MyValue) {
114+
// expected-warning@-1 {{sendability of function types in instance method 'testComposition' does not match requirement in protocol 'InnerSendableTypes'; this is an error in the Swift 6 language mode}}
115+
}
116+
117+
func test(_ options: [String: Any]) {
118+
// 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}}
113119
}
114120

115121
func test(withCallback name: String, handler: @escaping @MainActor ([String : Any], (any Error)?) -> Void) { // Ok
122+
// 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}}
116123
}
117124
}
118125

119126
class TestConformanceWithoutStripping : InnerSendableTypes {
120-
// expected-error@-1 {{type 'TestConformanceWithoutStripping' does not conform to protocol 'InnerSendableTypes'}}
127+
func testComposition(_: any MyValue & Sendable) { // Ok
128+
}
121129

122-
func test(_ options: [String: any Sendable]) {
123-
// expected-note@-1 {{candidate has non-matching type '([String : any Sendable]) -> ()'}}
130+
func test(_ options: [String: any Sendable]) { // Ok
124131
}
125132

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) -> ()'}}
133+
func test(withCallback name: String, handler: @escaping @MainActor ([String : any Sendable], (any Error)?) -> Void) { // Ok
128134
}
129135
}

test/Concurrency/sendable_objc_attr_in_type_context_swift5_strict.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ void doSomethingConcurrently(__attribute__((noescape)) void SWIFT_SENDABLE (^blo
5959
@end
6060

6161
@protocol InnerSendableTypes
62+
-(void) testComposition:(SWIFT_SENDABLE MyValue *)composition;
6263
-(void) test:(NSDictionary<NSString *, SWIFT_SENDABLE id> *)options;
6364
-(void) testWithCallback:(NSString *)name handler:(MAIN_ACTOR void (^)(NSDictionary<NSString *, SWIFT_SENDABLE id> *, NSError * _Nullable))handler;
6465
@end
@@ -116,6 +117,10 @@ func test_sendable_attr_in_type_context(test: Test) {
116117
class TestConformanceWithStripping : InnerSendableTypes {
117118
// expected-error@-1 {{type 'TestConformanceWithStripping' does not conform to protocol 'InnerSendableTypes'}}
118119

120+
func testComposition(_: MyValue) {
121+
// expected-note@-1 {{candidate has non-matching type '(MyValue) -> ()'}}
122+
}
123+
119124
func test(_ options: [String: Any]) {
120125
// expected-note@-1 {{candidate has non-matching type '([String : Any]) -> ()'}}
121126
}
@@ -126,6 +131,9 @@ class TestConformanceWithStripping : InnerSendableTypes {
126131
}
127132

128133
class TestConformanceWithoutStripping : InnerSendableTypes {
134+
func testComposition(_: MyValue & Sendable) { // Ok
135+
}
136+
129137
func test(_ options: [String: any Sendable]) { // Ok
130138
}
131139

0 commit comments

Comments
 (0)