Skip to content

Commit b4985f7

Browse files
committed
[NFC] replace canBeNoncopyable
First, "can have an absence of Copyable" is a rather confusing notion, so the query is flipped to "can be Copyable". Next, it's more robust to ask if a conformance exists for the TypeDecl to answer that question, rather than trying to replicate what happens within that conformance lookup. Also renames `TypeDecl::isEscapable` to match.
1 parent 483b569 commit b4985f7

23 files changed

+144
-65
lines changed

include/swift/AST/Decl.h

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3191,13 +3191,33 @@ class TypeDecl : public ValueDecl {
31913191

31923192
void setInherited(ArrayRef<InheritedEntry> i) { Inherited = i; }
31933193

3194-
/// Is it possible for this type to lack a Copyable constraint?
3194+
/// Indicates how "strongly" a TypeDecl will conform to an invertible
3195+
/// protocol. Supports inequality comparisons and casts to bool.
3196+
enum CanBeInvertibleResult: unsigned {
3197+
CBI_Never = 0, // Never conforms.
3198+
CBI_Conditionally = 1, // Conditionally conforms.
3199+
CBI_Always = 2, // Always conforms.
3200+
};
3201+
3202+
/// "Does a conformance for Copyable exist for this type declaration?"
3203+
///
3204+
/// This doesn't mean that all instance of this type are Copyable, because
3205+
/// if a conditional conformance to Copyable exists, this method will return
3206+
/// true.
3207+
///
31953208
/// If you need a more precise answer, ask this Decl's corresponding
3196-
/// Type if it `isNoncopyable` instead of using this.
3197-
bool canBeNoncopyable() const;
3209+
/// Type if it `isCopyable` instead of using this.
3210+
CanBeInvertibleResult canBeCopyable() const;
31983211

3199-
/// Is this declaration escapable?
3200-
bool isEscapable() const;
3212+
/// "Does a conformance for Escapable exist for this type declaration?"
3213+
///
3214+
/// This doesn't mean that all instance of this type are Escapable, because
3215+
/// if a conditional conformance to Escapable exists, this method will return
3216+
/// true.
3217+
///
3218+
/// If you need a more precise answer, ask this Decl's corresponding
3219+
/// Type if it `isEscapable` instead of using this.
3220+
CanBeInvertibleResult canBeEscapable() const;
32013221

32023222
/// Determine how the given invertible protocol was written on this TypeDecl,
32033223
/// if at all.

lib/AST/ASTVerifier.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3288,7 +3288,7 @@ class Verifier : public ASTWalker {
32883288
PrettyStackTraceDecl debugStack("verifying DestructorDecl", DD);
32893289

32903290
auto *ND = DD->getDeclContext()->getSelfNominalTypeDecl();
3291-
if (!isa<ClassDecl>(ND) && !ND->canBeNoncopyable() && !DD->isInvalid()) {
3291+
if (!isa<ClassDecl>(ND) && ND->canBeCopyable() && !DD->isInvalid()) {
32923292
Out << "DestructorDecls outside classes/move only types should be "
32933293
"marked invalid\n";
32943294
abort();

lib/AST/ConformanceLookup.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -620,10 +620,10 @@ LookupConformanceInModuleRequest::evaluate(
620620
// We only need to do this until we are properly dealing with or
621621
// omitting Copyable conformances in modules/interfaces.
622622

623-
if (nominal->canBeNoncopyable())
624-
return ProtocolConformanceRef::forMissingOrInvalid(type, protocol);
625-
else
623+
if (nominal->canBeCopyable())
626624
return ProtocolConformanceRef(protocol);
625+
else
626+
return ProtocolConformanceRef::forMissingOrInvalid(type, protocol);
627627
}
628628

629629
// Try to infer the conformance.

lib/AST/Decl.cpp

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4930,14 +4930,52 @@ InverseMarking TypeDecl::getMarking(InvertibleProtocolKind ip) const {
49304930
);
49314931
}
49324932

4933-
bool TypeDecl::canBeNoncopyable() const {
4934-
auto copyable = getMarking(InvertibleProtocolKind::Copyable);
4935-
return bool(copyable.getInverse()) && !copyable.getPositive();
4933+
static TypeDecl::CanBeInvertibleResult
4934+
conformanceExists(TypeDecl const *decl, InvertibleProtocolKind ip) {
4935+
auto *proto = decl->getASTContext().getProtocol(getKnownProtocolKind(ip));
4936+
assert(proto);
4937+
4938+
// Handle protocols specially, without building a GenericSignature.
4939+
if (auto *protoDecl = dyn_cast<ProtocolDecl>(decl))
4940+
return protoDecl->requiresInvertible(ip)
4941+
? TypeDecl::CBI_Always
4942+
: TypeDecl::CBI_Never;
4943+
4944+
Type selfTy = decl->getDeclaredInterfaceType();
4945+
assert(selfTy);
4946+
4947+
auto conformance = decl->getModuleContext()->lookupConformance(selfTy, proto,
4948+
/*allowMissing=*/false);
4949+
4950+
if (conformance.isInvalid())
4951+
return TypeDecl::CBI_Never;
4952+
4953+
if (!conformance.getConditionalRequirements().empty())
4954+
return TypeDecl::CBI_Conditionally;
4955+
4956+
return TypeDecl::CBI_Always;
49364957
}
49374958

4938-
bool TypeDecl::isEscapable() const {
4939-
auto escapable = getMarking(InvertibleProtocolKind::Escapable);
4940-
return !escapable.getInverse() || bool(escapable.getPositive());
4959+
TypeDecl::CanBeInvertibleResult TypeDecl::canBeCopyable() const {
4960+
if (!getASTContext().LangOpts.hasFeature(Feature::NoncopyableGenerics)) {
4961+
auto copyable = getMarking(InvertibleProtocolKind::Copyable);
4962+
return !copyable.getInverse() || bool(copyable.getPositive())
4963+
? CBI_Always
4964+
: CBI_Never;
4965+
}
4966+
4967+
return conformanceExists(this, InvertibleProtocolKind::Copyable);
4968+
}
4969+
4970+
TypeDecl::CanBeInvertibleResult TypeDecl::canBeEscapable() const {
4971+
if (!getASTContext().LangOpts.hasFeature(Feature::NoncopyableGenerics)) {
4972+
auto escapable = getMarking(InvertibleProtocolKind::Escapable);
4973+
return !escapable.getInverse() || bool(escapable.getPositive())
4974+
? CBI_Always
4975+
: CBI_Never;
4976+
}
4977+
4978+
return conformanceExists(this, InvertibleProtocolKind::Escapable);
49414979
}
49424980

49434981
Type TypeDecl::getDeclaredInterfaceType() const {

lib/AST/ProtocolConformance.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1070,13 +1070,15 @@ void NominalTypeDecl::prepareConformanceTable() const {
10701070
}
10711071

10721072
SmallPtrSet<ProtocolDecl *, 2> protocols;
1073+
const bool haveNoncopyableGenerics =
1074+
ctx.LangOpts.hasFeature(Feature::NoncopyableGenerics);
10731075

10741076
auto addSynthesized = [&](ProtocolDecl *proto) {
10751077
if (!proto)
10761078
return;
10771079

10781080
// No synthesized conformances for move-only nominals.
1079-
if (canBeNoncopyable()) {
1081+
if (!haveNoncopyableGenerics && !canBeCopyable()) {
10801082
// assumption is Sendable gets synthesized elsewhere.
10811083
assert(!proto->isSpecificProtocol(KnownProtocolKind::Sendable));
10821084
return;

lib/AST/SwiftNameTranslation.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ swift::cxx_translation::getDeclRepresentation(const ValueDecl *VD) {
234234
if (isa<ProtocolDecl>(typeDecl))
235235
return {Unsupported, UnrepresentableProtocol};
236236
// Swift's consume semantics are not yet supported in C++.
237-
if (typeDecl->canBeNoncopyable())
237+
if (!typeDecl->canBeCopyable())
238238
return {Unsupported, UnrepresentableMoveOnly};
239239
if (typeDecl->isGeneric()) {
240240
if (isa<ClassDecl>(VD))

lib/AST/Type.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ bool TypeBase::isMarkerExistential() {
161161
/// that does not rely on conformances.
162162
static bool alwaysNoncopyable(Type ty) {
163163
if (auto *nominal = ty->getNominalOrBoundGenericNominal())
164-
return nominal->canBeNoncopyable();
164+
return !nominal->canBeCopyable();
165165

166166
if (auto *expansion = ty->getAs<PackExpansionType>()) {
167167
return alwaysNoncopyable(expansion->getPatternType());
@@ -219,7 +219,7 @@ bool TypeBase::isEscapable(GenericEnvironment *env) {
219219
// for legacy-mode queries that are not dependent on conformances to Escapable
220220
if (!ctx.LangOpts.hasFeature(Feature::NoncopyableGenerics)) {
221221
if (auto nom = canType.getAnyNominal())
222-
return nom->isEscapable();
222+
return nom->canBeEscapable();
223223
else
224224
return true;
225225
}

lib/IRGen/GenDecl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1067,7 +1067,7 @@ void IRGenModule::addObjCClassStub(llvm::Constant *classPtr) {
10671067

10681068
void IRGenModule::addRuntimeResolvableType(GenericTypeDecl *type) {
10691069
// Collect the nominal type records we emit into a special section.
1070-
if (type->canBeNoncopyable()) {
1070+
if (!type->canBeCopyable()) {
10711071
// Older runtimes should not be allowed to discover noncopyable types, since
10721072
// they will try to expose them dynamically as copyable types. Record
10731073
// noncopyable type descriptors in a separate vector so that future

lib/IRGen/GenEnum.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6622,7 +6622,7 @@ SingletonEnumImplStrategy::completeEnumTypeLayout(TypeConverter &TC,
66226622
llvm::StructType *enumTy) {
66236623
auto deinit = theEnum->getValueTypeDestructor()
66246624
? IsNotTriviallyDestroyable : IsTriviallyDestroyable;
6625-
auto copyable = theEnum->canBeNoncopyable()
6625+
auto copyable = !theEnum->canBeCopyable()
66266626
? IsNotCopyable : IsCopyable;
66276627
if (ElementsWithPayload.empty()) {
66286628
enumTy->setBody(ArrayRef<llvm::Type*>{}, /*isPacked*/ true);
@@ -6698,7 +6698,7 @@ NoPayloadEnumImplStrategy::completeEnumTypeLayout(TypeConverter &TC,
66986698

66996699
auto deinit = theEnum->getValueTypeDestructor()
67006700
? IsNotTriviallyDestroyable : IsTriviallyDestroyable;
6701-
auto copyable = theEnum->canBeNoncopyable()
6701+
auto copyable = !theEnum->canBeCopyable()
67026702
? IsNotCopyable : IsCopyable;
67036703
return registerEnumTypeInfo(new LoadableEnumTypeInfo(*this,
67046704
enumTy, tagSize, std::move(spareBits),
@@ -6818,7 +6818,7 @@ TypeInfo *SinglePayloadEnumImplStrategy::completeFixedLayout(
68186818

68196819
auto deinit = theEnum->getValueTypeDestructor()
68206820
? IsNotTriviallyDestroyable : IsTriviallyDestroyable;
6821-
auto copyable = theEnum->canBeNoncopyable()
6821+
auto copyable = !theEnum->canBeCopyable()
68226822
? IsNotCopyable : IsCopyable;
68236823
getFixedEnumTypeInfo(
68246824
enumTy, Size(sizeWithTag), spareBits.build(), alignment,
@@ -6853,7 +6853,7 @@ TypeInfo *SinglePayloadEnumImplStrategy::completeDynamicLayout(
68536853

68546854
auto deinit = theEnum->getValueTypeDestructor()
68556855
? IsNotTriviallyDestroyable : IsTriviallyDestroyable;
6856-
auto copyable = theEnum->canBeNoncopyable()
6856+
auto copyable = !theEnum->canBeCopyable()
68576857
? IsNotCopyable : IsCopyable;
68586858
return registerEnumTypeInfo(new NonFixedEnumTypeInfo(*this, enumTy,
68596859
alignment,
@@ -6889,7 +6889,7 @@ MultiPayloadEnumImplStrategy::completeFixedLayout(TypeConverter &TC,
68896889
// of the largest payload.
68906890
CommonSpareBits = {};
68916891
Alignment worstAlignment(1);
6892-
auto isCopyable = theEnum->canBeNoncopyable()
6892+
auto isCopyable = !theEnum->canBeCopyable()
68936893
? IsNotCopyable : IsCopyable;
68946894
auto isTriviallyDestroyable = theEnum->getValueTypeDestructor()
68956895
? IsNotTriviallyDestroyable : IsTriviallyDestroyable;
@@ -7071,7 +7071,7 @@ TypeInfo *MultiPayloadEnumImplStrategy::completeDynamicLayout(
70717071

70727072
auto enumAccessible = IsABIAccessible_t(TC.IGM.isTypeABIAccessible(Type));
70737073

7074-
auto cp = theEnum->canBeNoncopyable()
7074+
auto cp = !theEnum->canBeCopyable()
70757075
? IsNotCopyable : IsCopyable;
70767076
return registerEnumTypeInfo(new NonFixedEnumTypeInfo(*this, enumTy,
70777077
alignment, td, bt, cp,
@@ -7095,7 +7095,7 @@ ResilientEnumImplStrategy::completeEnumTypeLayout(TypeConverter &TC,
70957095
EnumDecl *theEnum,
70967096
llvm::StructType *enumTy) {
70977097
auto abiAccessible = IsABIAccessible_t(TC.IGM.isTypeABIAccessible(Type));
7098-
auto copyable = theEnum->canBeNoncopyable()
7098+
auto copyable = !theEnum->canBeCopyable()
70997099
? IsNotCopyable : IsCopyable;
71007100
return registerEnumTypeInfo(
71017101
new ResilientEnumTypeInfo(*this, enumTy, copyable,

lib/IRGen/GenStruct.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1693,7 +1693,7 @@ const TypeInfo *TypeConverter::convertStructType(TypeBase *key, CanType type,
16931693
|| IGM.getSILTypes().getTypeLowering(SILType::getPrimitiveAddressType(type),
16941694
TypeExpansionContext::minimal())
16951695
.getRecursiveProperties().isInfinite()) {
1696-
auto copyable = D->canBeNoncopyable()
1696+
auto copyable = !D->canBeCopyable()
16971697
? IsNotCopyable : IsCopyable;
16981698
auto structAccessible =
16991699
IsABIAccessible_t(IGM.getSILModule().isTypeMetadataAccessible(type));

0 commit comments

Comments
 (0)