Skip to content

Commit eb277d9

Browse files
authored
Merge pull request #67498 from angela-laar/implicit-sendable-for-methods
[Sema] Implicitly add @sendable attribute to partial methods
2 parents 1f363be + c09ec72 commit eb277d9

File tree

7 files changed

+307
-8
lines changed

7 files changed

+307
-8
lines changed

include/swift/Basic/Features.def

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,6 @@ EXPERIMENTAL_FEATURE(RawLayout, true)
243243
/// Enables the "embedded" swift mode (no runtime).
244244
EXPERIMENTAL_FEATURE(Embedded, true)
245245

246-
247246
/// Enables noncopyable generics
248247
EXPERIMENTAL_FEATURE(NoncopyableGenerics, false)
249248

@@ -260,6 +259,10 @@ EXPERIMENTAL_FEATURE(NonEscapableTypes, false)
260259
/// Enable the `@_extern` attribute.
261260
EXPERIMENTAL_FEATURE(Extern, true)
262261

262+
// Infer Sendability of unapplied and partial applied methods,
263+
// global functions and key paths.
264+
EXPERIMENTAL_FEATURE(InferSendableFromCaptures, false)
265+
263266
#undef EXPERIMENTAL_FEATURE_EXCLUDED_FROM_MODULE_INTERFACE
264267
#undef EXPERIMENTAL_FEATURE
265268
#undef UPCOMING_FEATURE

include/swift/Sema/ConstraintSystem.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5433,6 +5433,8 @@ class ConstraintSystem {
54335433
return range.isValid() ? range : llvm::Optional<SourceRange>();
54345434
}
54355435

5436+
bool isPartialApplication(ConstraintLocator *locator);
5437+
54365438
bool isTooComplex(size_t solutionMemory) {
54375439
if (isAlreadyTooComplex.first)
54385440
return true;

lib/AST/ASTPrinter.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3559,12 +3559,18 @@ static bool usesFeatureParameterPacks(Decl *decl) {
35593559

35603560
static bool usesFeatureRegionBasedIsolation(Decl *decl) { return false; }
35613561

3562-
static bool usesFeatureGlobalConcurrency(Decl *decl) { return false; }
3562+
static bool usesFeatureGlobalConcurrency(Decl *decl) {
3563+
return false;
3564+
}
35633565

35643566
static bool usesFeatureIsolatedDefaultValues(Decl *decl) {
35653567
return false;
35663568
}
35673569

3570+
static bool usesFeatureInferSendableFromCaptures(Decl *decl) {
3571+
return false;
3572+
}
3573+
35683574
static bool usesFeaturePlaygroundExtendedCallbacks(Decl *decl) {
35693575
return false;
35703576
}

lib/Sema/CSSimplify.cpp

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@
2929
#include "swift/AST/ParameterList.h"
3030
#include "swift/AST/PropertyWrappers.h"
3131
#include "swift/AST/ProtocolConformance.h"
32+
#include "swift/AST/Requirement.h"
3233
#include "swift/AST/SourceFile.h"
34+
#include "swift/AST/Types.h"
3335
#include "swift/Basic/StringExtras.h"
3436
#include "swift/ClangImporter/ClangModule.h"
3537
#include "swift/Sema/CSFix.h"
@@ -9511,16 +9513,18 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
95119513
Type baseObjTy = baseTy->getRValueType();
95129514
Type instanceTy = baseObjTy;
95139515

9516+
auto &ctx = getASTContext();
95149517
auto memberNode = simplifyLocatorToAnchor(memberLocator);
95159518
auto memberLoc = memberNode ? memberNode.getStartLoc() : SourceLoc();
95169519

95179520
if (auto baseObjMeta = baseObjTy->getAs<AnyMetatypeType>()) {
95189521
instanceTy = baseObjMeta->getInstanceType();
95199522
}
95209523

9524+
MemberLookupResult result;
9525+
95219526
if (instanceTy->isTypeVariableOrMember() ||
95229527
instanceTy->is<UnresolvedType>()) {
9523-
MemberLookupResult result;
95249528
result.OverallResult = MemberLookupResult::Unsolved;
95259529
return result;
95269530
}
@@ -9530,14 +9534,40 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
95309534
if (isSingleUnlabeledPackExpansionTuple(instanceTy)) {
95319535
auto elementTy = instanceTy->castTo<TupleType>()->getElementType(0);
95329536
if (elementTy->is<TypeVariableType>()) {
9533-
MemberLookupResult result;
95349537
result.OverallResult = MemberLookupResult::Unsolved;
95359538
return result;
95369539
}
95379540
}
95389541

9542+
// Delay solving member constraint for unapplied methods
9543+
// where the base type has a conditional Sendable conformance
9544+
if (Context.LangOpts.hasFeature(Feature::InferSendableFromCaptures)) {
9545+
if (isPartialApplication(memberLocator)) {
9546+
auto sendableProtocol =
9547+
Context.getProtocol(
9548+
KnownProtocolKind::Sendable);
9549+
auto baseConformance = DC->getParentModule()->lookupConformance(
9550+
instanceTy, sendableProtocol);
9551+
9552+
if (llvm::any_of(
9553+
baseConformance.getConditionalRequirements(),
9554+
[&](const auto &req) {
9555+
if (req.getKind() != RequirementKind::Conformance)
9556+
return false;
9557+
9558+
if (auto protocolTy = req.getSecondType()->template getAs<ProtocolType>()) {
9559+
return req.getFirstType()->hasTypeVariable() &&
9560+
protocolTy->getDecl()->isSpecificProtocol(KnownProtocolKind::Sendable);
9561+
}
9562+
return false;
9563+
})) {
9564+
result.OverallResult = MemberLookupResult::Unsolved;
9565+
return result;
9566+
}
9567+
}
9568+
}
9569+
95399570
// Okay, start building up the result list.
9540-
MemberLookupResult result;
95419571
result.OverallResult = MemberLookupResult::HasResults;
95429572

95439573
// Add key path result.
@@ -9559,7 +9589,6 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
95599589

95609590
// If the base type is a tuple type, look for the named or indexed member
95619591
// of the tuple.
9562-
auto &ctx = getASTContext();
95639592
if (auto baseTuple = baseObjTy->getAs<TupleType>()) {
95649593
if (!memberName.isSpecial()) {
95659594
StringRef nameStr = memberName.getBaseIdentifier().str();

lib/Sema/ConstraintSystem.cpp

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1160,7 +1160,6 @@ FunctionType *ConstraintSystem::openFunctionType(
11601160
DeclContext *outerDC) {
11611161
if (auto *genericFn = funcType->getAs<GenericFunctionType>()) {
11621162
auto signature = genericFn->getGenericSignature();
1163-
11641163
openGenericParameters(outerDC, signature, replacements, locator);
11651164

11661165
openGenericRequirements(outerDC, signature,
@@ -1612,6 +1611,7 @@ AnyFunctionType *ConstraintSystem::adjustFunctionTypeForConcurrency(
16121611
AnyFunctionType *fnType, ValueDecl *decl, DeclContext *dc,
16131612
unsigned numApplies, bool isMainDispatchQueue, OpenedTypeMap &replacements,
16141613
ConstraintLocatorBuilder locator) {
1614+
16151615
return swift::adjustFunctionTypeForConcurrency(
16161616
fnType, decl, dc, numApplies, isMainDispatchQueue,
16171617
GetClosureType{*this}, ClosureIsolatedByPreconcurrency{*this},
@@ -1665,6 +1665,8 @@ ConstraintSystem::getTypeOfReference(ValueDecl *value,
16651665
FunctionRefKind functionRefKind,
16661666
ConstraintLocatorBuilder locator,
16671667
DeclContext *useDC) {
1668+
auto &ctx = getASTContext();
1669+
16681670
if (value->getDeclContext()->isTypeContext() && isa<FuncDecl>(value)) {
16691671
// Unqualified lookup can find operator names within nominal types.
16701672
auto func = cast<FuncDecl>(value);
@@ -1711,6 +1713,14 @@ ConstraintSystem::getTypeOfReference(ValueDecl *value,
17111713
auto numLabelsToRemove = getNumRemovedArgumentLabels(
17121714
funcDecl, /*isCurriedInstanceReference=*/false, functionRefKind);
17131715

1716+
if (Context.LangOpts.hasFeature(Feature::InferSendableFromCaptures)) {
1717+
// All global functions should be @Sendable
1718+
if (!funcDecl->getDeclContext()->isTypeContext() && !funcDecl->getDeclContext()->isLocalContext() ) {
1719+
funcType =
1720+
funcType->withExtInfo(funcType->getExtInfo().withConcurrent());
1721+
}
1722+
}
1723+
17141724
auto openedType = openFunctionType(funcType, locator, replacements,
17151725
funcDecl->getDeclContext())
17161726
->removeArgumentLabels(numLabelsToRemove);
@@ -2416,6 +2426,36 @@ Type ConstraintSystem::getMemberReferenceTypeFromOpenedType(
24162426
return type;
24172427
}
24182428

2429+
bool ConstraintSystem::isPartialApplication(ConstraintLocator *locator) {
2430+
// If this is a compiler synthesized implicit conversion, let's skip
2431+
// the check because the base of `UDE` is not the base of the injected
2432+
// initializer.
2433+
if (locator->isLastElement<LocatorPathElt::ConstructorMember>() &&
2434+
locator->findFirst<LocatorPathElt::ImplicitConversion>())
2435+
return false;
2436+
2437+
auto *UDE = getAsExpr<UnresolvedDotExpr>(locator->getAnchor());
2438+
if (UDE == nullptr)
2439+
return false;
2440+
2441+
auto baseTy =
2442+
simplifyType(getType(UDE->getBase()))->getWithoutSpecifierType();
2443+
2444+
// If base is a metatype it would be ignored (unless this is an initializer
2445+
// call), but if it is some other type it means that we have a single
2446+
// application level already.
2447+
unsigned level = 0;
2448+
if (!baseTy->is<MetatypeType>())
2449+
++level;
2450+
2451+
if (auto *call = dyn_cast_or_null<CallExpr>(getParentExpr(UDE))) {
2452+
if (UDE == call->getFn()->getSemanticsProvidingExpr())
2453+
level += 1;
2454+
}
2455+
2456+
return level < 2;
2457+
}
2458+
24192459
DeclReferenceType
24202460
ConstraintSystem::getTypeOfMemberReference(
24212461
Type baseTy, ValueDecl *value, DeclContext *useDC,
@@ -2626,6 +2666,17 @@ ConstraintSystem::getTypeOfMemberReference(
26262666
functionType, locator);
26272667
// FIXME: Verify ExtInfo state is correct, not working by accident.
26282668
FunctionType::ExtInfo info;
2669+
2670+
if (Context.LangOpts.hasFeature(Feature::InferSendableFromCaptures)) {
2671+
if (isPartialApplication(locator) &&
2672+
isSendableType(DC->getParentModule(), baseOpenedTy)) {
2673+
// Add @Sendable to functions without conditional conformances
2674+
functionType = functionType->withExtInfo(functionType->getExtInfo().withConcurrent())->getAs<FunctionType>();
2675+
}
2676+
// Unapplied values should always be Sendable
2677+
info = info.withConcurrent();
2678+
}
2679+
26292680
openedType =
26302681
FunctionType::get(fullFunctionType->getParams(), functionType, info);
26312682
}

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1952,7 +1952,6 @@ bool swift::diagnoseApplyArgSendability(ApplyExpr *apply, const DeclContext *dec
19521952
isolationCrossing.value().getDiagnoseIsolation()))
19531953
return true;
19541954
}
1955-
19561955
auto fnType = fnExprType->getAs<FunctionType>();
19571956
if (!fnType)
19581957
return false;
@@ -5527,6 +5526,7 @@ AnyFunctionType *swift::adjustFunctionTypeForConcurrency(
55275526
// Apply unsafe concurrency features to the given function type.
55285527
bool strictChecking = contextRequiresStrictConcurrencyChecking(
55295528
dc, getType, isolatedByPreconcurrency);
5529+
55305530
fnType = applyUnsafeConcurrencyToFunctionType(
55315531
fnType, decl, strictChecking, numApplies, isMainDispatchQueue);
55325532

0 commit comments

Comments
 (0)