Skip to content

Commit 157e71a

Browse files
authored
Merge pull request #79478 from xedin/sendable-completion-handler-fixes
[TypeChecker/NameLookup] SE-0463: A few fixes for `SendableCompletionHandlers` feature
2 parents eb7b765 + bb247d7 commit 157e71a

9 files changed

+353
-87
lines changed

include/swift/AST/DiagnosticsSema.def

+5
Original file line numberDiff line numberDiff line change
@@ -1898,6 +1898,11 @@ ERROR(objc_implementation_type_mismatch,none,
18981898
"%kind0 of type %1 does not match type %2 declared by the header",
18991899
(ValueDecl *, Type, Type))
19001900

1901+
ERROR(objc_implementation_sendability_mismatch,none,
1902+
"sendability of function types in %kind0 of type %1 does not match "
1903+
"type %2 declared by the header",
1904+
(ValueDecl *, Type, Type))
1905+
19011906
ERROR(objc_implementation_required_attr_mismatch,none,
19021907
"%kind0 %select{should not|should}2 be 'required' to match %1 declared "
19031908
"by the header",

include/swift/AST/TypeMatcher.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,8 @@ class TypeMatcher {
375375
if (firstFunc->isNoEscape() != secondFunc->isNoEscape())
376376
return mismatch(firstFunc.getPointer(), secondFunc, sugaredFirstType);
377377

378-
if (firstFunc->isSendable() != secondFunc->isSendable())
378+
if (!Matcher.asDerived().allowSendableFunctionMismatch() &&
379+
firstFunc->isSendable() != secondFunc->isSendable())
379380
return mismatch(firstFunc.getPointer(), secondFunc, sugaredFirstType);
380381

381382
auto sugaredFirstFunc = sugaredFirstType->castTo<AnyFunctionType>();
@@ -554,6 +555,8 @@ class TypeMatcher {
554555

555556
bool alwaysMismatchTypeParameters() const { return false; }
556557

558+
bool allowSendableFunctionMismatch() const { return false; }
559+
557560
void pushPosition(Position pos) {}
558561
void popPosition(Position pos) {}
559562

lib/AST/NameLookup.cpp

+14
Original file line numberDiff line numberDiff line change
@@ -827,6 +827,20 @@ static void recordShadowedDeclsAfterSignatureMatch(
827827
else
828828
type = removeThrownError(decl->getInterfaceType()->getCanonicalType());
829829

830+
// Strip `@Sendable` annotations for declarations that come from
831+
// or are exposed to Objective-C to make it possible to introduce
832+
// new annotations without breaking shadowing rules.
833+
//
834+
// This is a narrow fix for specific backwards-incompatible cases
835+
// we know about, it could be extended to use `isObjC()` in the
836+
// future if we find problematic cases were a more general change
837+
// is required.
838+
if (decl->hasClangNode() || decl->getAttrs().hasAttribute<ObjCAttr>()) {
839+
type =
840+
type->stripConcurrency(/*recursive=*/true, /*dropGlobalActor=*/false)
841+
->getCanonicalType();
842+
}
843+
830844
// Record this declaration based on its signature.
831845
auto &known = collisions[type];
832846
if (known.size() == 1) {

lib/Sema/AssociatedTypeInference.cpp

+19
Original file line numberDiff line numberDiff line change
@@ -2269,6 +2269,25 @@ AssociatedTypeInference::getPotentialTypeWitnessesByMatchingTypes(ValueDecl *req
22692269
return true;
22702270
}
22712271

2272+
bool allowSendableFunctionMismatch() const {
2273+
// Allow mismatches on `@Sendable` only if the witness comes
2274+
// from ObjC as a very narrow fix to avoid introducing new
2275+
// ambiguities like this:
2276+
//
2277+
// protocol P {
2278+
// associatedtype T
2279+
// func test(_: (T) -> Void)
2280+
// }
2281+
//
2282+
// struct S : P {
2283+
// func test(_: @Sendable (Int) -> Void) {}
2284+
// func test(_: (Int) -> Void) {}
2285+
// }
2286+
//
2287+
// Currently, there is only one binding for `T` - `Int`.
2288+
return Inferred.Witness && Inferred.Witness->hasClangNode();
2289+
}
2290+
22722291
bool mismatch(GenericTypeParamType *selfParamType,
22732292
TypeBase *secondType, Type sugaredFirstType) {
22742293
if (selfParamType->isEqual(Conformance->getProtocol()->getSelfInterfaceType())) {

lib/Sema/ConstraintSystem.cpp

+7-2
Original file line numberDiff line numberDiff line change
@@ -331,9 +331,14 @@ void ConstraintSystem::recordAppliedDisjunction(
331331
/// Retrieve a dynamic result signature for the given declaration.
332332
static std::tuple<char, ObjCSelector, CanType>
333333
getDynamicResultSignature(ValueDecl *decl) {
334+
// Handle functions.
334335
if (auto func = dyn_cast<AbstractFunctionDecl>(decl)) {
335-
// Handle functions.
336-
auto type = func->getMethodInterfaceType();
336+
// Strip `@Sendable` and `any Sendable` because it should be
337+
// possible to add them without affecting lookup results and
338+
// shadowing. All of the declarations that are processed here
339+
// are `@objc` and hence `@preconcurrency`.
340+
auto type = func->getMethodInterfaceType()->stripConcurrency(
341+
/*recursive=*/true, /*dropGlobalActor=*/false);
337342
return std::make_tuple(func->isStatic(), func->getObjCSelector(),
338343
type->getCanonicalType());
339344
}

lib/Sema/TypeCheckAttr.cpp

+83-39
Original file line numberDiff line numberDiff line change
@@ -3873,62 +3873,106 @@ findSimilarFunction(DeclNameRef replacedFunctionName,
38733873
// Note: we might pass a constant attribute when typechecker is nullptr.
38743874
// Any modification to attr must be guarded by a null check on TC.
38753875
//
3876-
SmallVector<ValueDecl *, 4> results;
3877-
lookupReplacedDecl(replacedFunctionName, attr, base, results);
3876+
SmallVector<ValueDecl *, 4> lookupResults;
3877+
lookupReplacedDecl(replacedFunctionName, attr, base, lookupResults);
38783878

3879-
for (auto *result : results) {
3879+
SmallVector<AbstractFunctionDecl *, 4> candidates;
3880+
for (auto *result : lookupResults) {
38803881
// Protocol requirements are not replaceable.
38813882
if (isa<ProtocolDecl>(result->getDeclContext()))
38823883
continue;
38833884
// Check for static/instance mismatch.
38843885
if (result->isStatic() != base->isStatic())
38853886
continue;
38863887

3887-
auto resultTy = result->getInterfaceType();
3888-
auto replaceTy = base->getInterfaceType();
3889-
TypeMatchOptions matchMode = TypeMatchFlags::AllowABICompatible;
3890-
matchMode |= TypeMatchFlags::AllowCompatibleOpaqueTypeArchetypes;
3891-
if (resultTy->matches(replaceTy, matchMode)) {
3892-
if (forDynamicReplacement && !result->isDynamic()) {
3893-
if (Diags) {
3894-
Diags->diagnose(attr->getLocation(),
3895-
diag::dynamic_replacement_function_not_dynamic,
3896-
result->getName());
3897-
attr->setInvalid();
3898-
}
3899-
return nullptr;
3888+
if (auto *AFD = dyn_cast<AbstractFunctionDecl>(result))
3889+
candidates.push_back(AFD);
3890+
}
3891+
3892+
if (candidates.empty()) {
3893+
if (Diags) {
3894+
Diags->diagnose(attr->getLocation(),
3895+
forDynamicReplacement
3896+
? diag::dynamic_replacement_function_not_found
3897+
: diag::specialize_target_function_not_found,
3898+
replacedFunctionName);
3899+
}
3900+
3901+
attr->setInvalid();
3902+
return nullptr;
3903+
}
3904+
3905+
auto replaceTy = base->getInterfaceType();
3906+
3907+
// Filter based on the exact type match first.
3908+
SmallVector<AbstractFunctionDecl *> matches;
3909+
llvm::copy_if(candidates, std::back_inserter(matches),
3910+
[&replaceTy](AbstractFunctionDecl *F) {
3911+
auto resultTy = F->getInterfaceType();
3912+
TypeMatchOptions matchMode =
3913+
TypeMatchFlags::AllowABICompatible;
3914+
matchMode |=
3915+
TypeMatchFlags::AllowCompatibleOpaqueTypeArchetypes;
3916+
return resultTy->matches(replaceTy, matchMode);
3917+
});
3918+
3919+
// If there are no exact matches, strip sendability annotations
3920+
// from functions imported from Objective-C. This is a narrow
3921+
// fix for now but it could be extended to cover all `@preconcurrency`
3922+
// declarations.
3923+
if (matches.empty()) {
3924+
llvm::copy_if(candidates, std::back_inserter(matches),
3925+
[&replaceTy](AbstractFunctionDecl *F) {
3926+
if (!F->hasClangNode())
3927+
return false;
3928+
3929+
auto resultTy = F->getInterfaceType();
3930+
TypeMatchOptions matchMode =
3931+
TypeMatchFlags::AllowABICompatible;
3932+
matchMode |=
3933+
TypeMatchFlags::AllowCompatibleOpaqueTypeArchetypes;
3934+
matchMode |= TypeMatchFlags::IgnoreFunctionSendability;
3935+
matchMode |= TypeMatchFlags::IgnoreSendability;
3936+
return resultTy->matches(replaceTy, matchMode);
3937+
});
3938+
}
3939+
3940+
if (matches.size() == 1) {
3941+
auto result = matches.front();
3942+
if (forDynamicReplacement && !result->isDynamic()) {
3943+
if (Diags) {
3944+
Diags->diagnose(attr->getLocation(),
3945+
diag::dynamic_replacement_function_not_dynamic,
3946+
result->getName());
3947+
attr->setInvalid();
39003948
}
3901-
return cast<AbstractFunctionDecl>(result);
3949+
return nullptr;
39023950
}
3951+
3952+
return result;
39033953
}
39043954

3955+
attr->setInvalid();
3956+
39053957
if (!Diags)
39063958
return nullptr;
39073959

3908-
if (results.empty()) {
3909-
Diags->diagnose(attr->getLocation(),
3910-
forDynamicReplacement
3911-
? diag::dynamic_replacement_function_not_found
3912-
: diag::specialize_target_function_not_found,
3913-
replacedFunctionName);
3914-
} else {
3915-
Diags->diagnose(attr->getLocation(),
3916-
forDynamicReplacement
3917-
? diag::dynamic_replacement_function_of_type_not_found
3918-
: diag::specialize_target_function_of_type_not_found,
3919-
replacedFunctionName,
3920-
base->getInterfaceType()->getCanonicalType());
3960+
Diags->diagnose(attr->getLocation(),
3961+
forDynamicReplacement
3962+
? diag::dynamic_replacement_function_of_type_not_found
3963+
: diag::specialize_target_function_of_type_not_found,
3964+
replacedFunctionName,
3965+
base->getInterfaceType()->getCanonicalType());
39213966

3922-
for (auto *result : results) {
3923-
Diags->diagnose(SourceLoc(),
3924-
forDynamicReplacement
3925-
? diag::dynamic_replacement_found_function_of_type
3926-
: diag::specialize_found_function_of_type,
3927-
result->getName(),
3928-
result->getInterfaceType()->getCanonicalType());
3929-
}
3967+
for (auto *result : matches) {
3968+
Diags->diagnose(SourceLoc(),
3969+
forDynamicReplacement
3970+
? diag::dynamic_replacement_found_function_of_type
3971+
: diag::specialize_found_function_of_type,
3972+
result->getName(),
3973+
result->getInterfaceType()->getCanonicalType());
39303974
}
3931-
attr->setInvalid();
3975+
39323976
return nullptr;
39333977
}
39343978

0 commit comments

Comments
 (0)