Skip to content

Commit 3ed1d6c

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.
1 parent 8626404 commit 3ed1d6c

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)