Merge pull request #70499 from slavapestov/fix-rdar119541554

AST: Fix ExistentialLayout::isObjC() handling of marker protocols
This commit is contained in:
Slava Pestov
2023-12-16 07:36:01 -05:00
committed by GitHub
7 changed files with 39 additions and 26 deletions

View File

@@ -31,7 +31,8 @@ struct ExistentialLayout {
ExistentialLayout() {
hasExplicitAnyObject = false;
containsNonObjCProtocol = false;
containsObjCProtocol = false;
containsSwiftProtocol = false;
containsParameterized = false;
representsAnyObject = false;
}
@@ -46,8 +47,11 @@ struct ExistentialLayout {
/// Whether the existential contains an explicit '& AnyObject' constraint.
bool hasExplicitAnyObject : 1;
/// Whether any protocol members are non-@objc.
bool containsNonObjCProtocol : 1;
/// Whether any protocol members are @objc.
bool containsObjCProtocol : 1;
/// Whether any protocol members require a witness table.
bool containsSwiftProtocol : 1;
/// Whether any protocol members are parameterized.s
bool containsParameterized : 1;
@@ -74,8 +78,8 @@ struct ExistentialLayout {
// FIXME: Does the superclass have to be @objc?
return ((explicitSuperclass ||
hasExplicitAnyObject ||
!getProtocols().empty()) &&
!containsNonObjCProtocol);
containsObjCProtocol) &&
!containsSwiftProtocol);
}
/// Whether the existential requires a class, either via an explicit
@@ -109,10 +113,6 @@ private:
/// Zero or more primary associated type requirements from a
/// ParameterizedProtocolType
ArrayRef<Type> sameTypeRequirements;
/// Existentials allow a relaxed notion of \c ValueDecl::isObjC
/// that includes `Sendable` protocol.
static bool isObjCProtocol(ProtocolDecl *P);
};
}

View File

@@ -1703,7 +1703,7 @@ public:
auto concreteLayout = concreteTy->getCanonicalType()
->getExistentialLayout();
canBeClass = concreteLayout.getKind() == ExistentialLayout::Kind::Class
&& !concreteLayout.containsNonObjCProtocol;
&& !concreteLayout.containsSwiftProtocol;
} else {
canBeClass = false;
}

View File

@@ -372,7 +372,9 @@ ExistentialLayout::ExistentialLayout(CanProtocolType type) {
auto *protoDecl = type->getDecl();
hasExplicitAnyObject = false;
containsNonObjCProtocol = !isObjCProtocol(protoDecl);
containsObjCProtocol = protoDecl->isObjC();
containsSwiftProtocol = (!protoDecl->isObjC() &&
!protoDecl->isMarkerProtocol());
containsParameterized = false;
representsAnyObject = false;
@@ -384,7 +386,8 @@ ExistentialLayout::ExistentialLayout(CanProtocolType type) {
ExistentialLayout::ExistentialLayout(CanProtocolCompositionType type) {
hasExplicitAnyObject = type->hasExplicitAnyObject();
containsNonObjCProtocol = false;
containsObjCProtocol = false;
containsSwiftProtocol = false;
containsParameterized = false;
auto members = type.getMembers();
@@ -404,7 +407,10 @@ ExistentialLayout::ExistentialLayout(CanProtocolCompositionType type) {
protoDecl = parameterized->getProtocol();
containsParameterized = true;
}
containsNonObjCProtocol |= !isObjCProtocol(protoDecl);
if (protoDecl->isObjC())
containsObjCProtocol = true;
else if (!protoDecl->isMarkerProtocol())
containsSwiftProtocol = true;
protocols.push_back(protoDecl);
}
@@ -421,10 +427,6 @@ ExistentialLayout::ExistentialLayout(CanParameterizedProtocolType type)
containsParameterized = true;
}
bool ExistentialLayout::isObjCProtocol(ProtocolDecl *P) {
return P->isObjC() || P->isSpecificProtocol(KnownProtocolKind::Sendable);
}
ExistentialLayout TypeBase::getExistentialLayout() {
return getCanonicalType().getExistentialLayout();
}

View File

@@ -60,7 +60,7 @@ static bool isNSObjectOrAnyHashable(ASTContext &ctx, Type type) {
}
static bool isAnyObjectOrAny(Type type) {
return type->isAnyObject() || type->isAny();
return type->isAnyObject() || type->isMarkerExistential();
}
// For a given Decl and Type, if the type is not an optional return
@@ -2377,7 +2377,7 @@ private:
// Use the type as bridged to Objective-C unless the element type is itself
// an imported type or a collection.
const StructDecl *SD = ty->getStructOrBoundGenericStruct();
if (ty->isAny()) {
if (ty->isMarkerExistential()) {
ty = ctx.getAnyObjectType();
} else if (!ty->isKnownStdlibCollectionType() && !isSwiftNewtype(SD)) {
ty = ctx.getBridgedToObjC(&owningPrinter.M, ty);

View File

@@ -255,12 +255,8 @@ static bool isSingleSwiftRefcounted(SILModule &M,
if (Ty->isAnyExistentialType()) {
auto layout = Ty->getExistentialLayout();
// Must be no protocol constraints that aren't @objc or @_marker.
if (layout.containsNonObjCProtocol) {
for (auto proto : layout.getProtocols()) {
if (!proto->isObjC() && !proto->isMarkerProtocol()) {
return false;
}
}
if (layout.containsSwiftProtocol) {
return false;
}
// The Error existential has its own special layout.
@@ -592,6 +588,7 @@ SILType::getPreferredExistentialRepresentation(Type containedType) const {
return ExistentialRepresentation::Class;
// Otherwise, we need to use a fixed-sized buffer.
assert(!layout.isObjC());
return ExistentialRepresentation::Opaque;
}

View File

@@ -20,7 +20,7 @@ import Foundation
@objc public protocol Q {
// CHECK: - (NSArray<NSDictionary<NSString *, id> *> * _Nonnull)data1 SWIFT_WARN_UNUSED_RESULT;
func data1() -> [[String: any Sendable]]
// CHECK: - (NSArray<id> * _Nullable)data2 SWIFT_WARN_UNUSED_RESULT;
// CHECK: - (NSArray * _Nullable)data2 SWIFT_WARN_UNUSED_RESULT;
func data2() -> [any Sendable]?
// CHECK: - (void)data3:(id _Nonnull)_;
func data3(_: any Sendable)

View File

@@ -0,0 +1,14 @@
// RUN: %empty-directory(%t)
// RUN: %target-build-swift %s -o %t/a.out -O -target %target-future-triple
// RUN: %target-codesign %t/a.out
// RUN: %target-run %t/a.out
// REQUIRES: executable_test
// REQUIRES: macos_min_version_13
struct S {
var x = 42
}
_ = [S() as Sendable]