Skip to content

Commit 649cf9d

Browse files
committed
[SE-0470] Teach @sendable inference on static methods about non-sendable metatypes
The code that determines whether a reference to a static method (that is not a call) assumed that metatypes were always Sendable. This is no longer the case, so update this code to go through the normal Sendable checking on the metatype. (cherry picked from commit 3ed1d6c)
1 parent 80d68d5 commit 649cf9d

File tree

3 files changed

+33
-13
lines changed

3 files changed

+33
-13
lines changed

lib/Sema/CSApply.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1949,7 +1949,7 @@ namespace {
19491949
solution.setExprTypes(base);
19501950
auto capture = new (ctx) VarDecl(/*static*/ false,
19511951
VarDecl::Introducer::Let,
1952-
SourceLoc(),
1952+
base->getEndLoc(),
19531953
ctx.getIdentifier("$base$"),
19541954
dc);
19551955
capture->setImplicit();

lib/Sema/TypeOfReference.cpp

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -849,19 +849,27 @@ FunctionType *ConstraintSystem::adjustFunctionTypeForConcurrency(
849849
} else if (numApplies < decl->getNumCurryLevels() &&
850850
decl->hasCurriedSelf() ) {
851851
auto shouldMarkMemberTypeSendable = [&]() {
852-
// Static member types are @Sendable on both levels because
853-
// they only capture a metatype "base" that is always Sendable.
854-
// For example, `(S.Type) -> () -> Void`.
855-
if (!decl->isInstanceMember())
856-
return true;
852+
Type capturedBaseType = baseType;
853+
854+
if (!decl->isInstanceMember()) {
855+
// Static member types are Sendable when the metatype of their
856+
// base type is Sendable, because they capture that metatype.
857+
// For example, `(S.Type) -> () -> Void`.
858+
if (!capturedBaseType)
859+
capturedBaseType = decl->getDeclContext()->getSelfTypeInContext();
860+
861+
if (!capturedBaseType->is<AnyMetatypeType>())
862+
capturedBaseType = MetatypeType::get(capturedBaseType);
863+
} else if (capturedBaseType) {
864+
// For instance members we need to check whether instance type
865+
// is Sendable because @Sendable function values cannot capture
866+
// non-Sendable values (base instance type in this case).
867+
// For example, `(C) -> () -> Void` where `C` should be Sendable
868+
// for the inner function type to be Sendable as well.
869+
capturedBaseType = capturedBaseType->getMetatypeInstanceType();
870+
}
857871

858-
// For instance members we need to check whether instance type
859-
// is Sendable because @Sendable function values cannot capture
860-
// non-Sendable values (base instance type in this case).
861-
// For example, `(C) -> () -> Void` where `C` should be Sendable
862-
// for the inner function type to be Sendable as well.
863-
return baseType &&
864-
baseType->getMetatypeInstanceType()->isSendableType();
872+
return capturedBaseType && capturedBaseType->isSendableType();
865873
};
866874

867875
auto referenceTy = adjustedTy->getResult()->castTo<FunctionType>();

test/Concurrency/sendable_metatype_typecheck.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,15 @@ nonisolated func passMetaWithMetaSendableVal<T: SendableMetatype & Q>(_: T.Type)
8787
x.g() // okay, because T is Sendable implies T.Type: Sendable
8888
}
8989
}
90+
91+
struct GenericThingy<Element> {
92+
func searchMe(_: (Element, Element) -> Bool) { }
93+
94+
func test() where Element: Comparable {
95+
// Ensure that this we infer a non-@Sendable function type for Comparable.<
96+
searchMe(<)
97+
98+
let _: (Element, Element) -> Bool = (>)
99+
let _: @Sendable (Element, Element) -> Bool = (>) // expected-error{{converting non-sendable function value to '@Sendable (Element, Element) -> Bool' may introduce data races}}
100+
}
101+
}

0 commit comments

Comments
 (0)