Skip to content

Commit b00b5aa

Browse files
Merge pull request #72646 from nate-chandler/bitwise-copyable/20240327/1
[BitwiseCopyable] Allow suppression via ~.
2 parents 15fd443 + eb1f0ac commit b00b5aa

35 files changed

+589
-82
lines changed

include/swift/AST/Decl.h

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1628,17 +1628,29 @@ struct InheritedEntry : public TypeLoc {
16281628
/// Whether there was an @preconcurrency attribute.
16291629
bool IsPreconcurrency : 1;
16301630

1631+
/// Whether there was a ~ indicating suppression.
1632+
///
1633+
/// This is true in cases like ~Copyable but not (P & ~Copyable).
1634+
bool IsSuppressed : 1;
1635+
16311636
public:
16321637
InheritedEntry(const TypeLoc &typeLoc);
16331638

16341639
InheritedEntry(const TypeLoc &typeLoc, bool isUnchecked, bool isRetroactive,
1635-
bool isPreconcurrency)
1640+
bool isPreconcurrency, bool isSuppressed = false)
16361641
: TypeLoc(typeLoc), IsUnchecked(isUnchecked),
1637-
IsRetroactive(isRetroactive), IsPreconcurrency(isPreconcurrency) {}
1642+
IsRetroactive(isRetroactive), IsPreconcurrency(isPreconcurrency),
1643+
IsSuppressed(isSuppressed) {}
16381644

16391645
bool isUnchecked() const { return IsUnchecked; }
16401646
bool isRetroactive() const { return IsRetroactive; }
16411647
bool isPreconcurrency() const { return IsPreconcurrency; }
1648+
bool isSuppressed() const { return IsSuppressed; }
1649+
1650+
void setSuppressed() {
1651+
assert(!IsSuppressed && "setting suppressed again!?");
1652+
IsSuppressed = true;
1653+
}
16421654
};
16431655

16441656
/// A wrapper for the collection of inherited types for either a `TypeDecl` or
@@ -4436,6 +4448,8 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
44364448
/// Type if it `isEscapable` instead of using this.
44374449
CanBeInvertible::Result canBeEscapable() const;
44384450

4451+
bool suppressesConformance(KnownProtocolKind kp) const;
4452+
44394453
// Implement isa/cast/dyncast/etc.
44404454
static bool classof(const Decl *D) {
44414455
return D->getKind() >= DeclKind::First_NominalTypeDecl &&

include/swift/AST/DiagnosticsSema.def

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7694,6 +7694,8 @@ ERROR(non_bitwise_copyable_type_indirect_enum_element,none,
76947694
"enum with indirect case cannot conform to 'BitwiseCopyable'", ())
76957695
NOTE(note_non_bitwise_copyable_type_indirect_enum_element,none,
76967696
"indirect case is here", ())
7697+
ERROR(non_bitwise_copyable_type_suppressed,none,
7698+
"cannot both conform to and suppress conformance to 'BitwiseCopyable'", ())
76977699
ERROR(non_bitwise_copyable_type_cxx_nontrivial,none,
76987700
"non-trivial C++ type cannot conform to 'BitwiseCopyable'", ())
76997701
ERROR(non_bitwise_copyable_c_type_nontrivial,none,
@@ -7719,6 +7721,12 @@ NOTE(add_generic_parameter_non_bitwise_copyable_conformance,none,
77197721
ERROR(bitwise_copyable_outside_module,none,
77207722
"conformance to 'BitwiseCopyable' must occur in the same module as %kind0",
77217723
(const ValueDecl *))
7724+
ERROR(suppress_inferrable_protocol_extension,none,
7725+
"conformance to inferrable protocol %0 cannot be suppressed in an extension", (const ProtocolDecl *))
7726+
ERROR(suppress_nonsuppressable_protocol,none,
7727+
"conformance to %0 cannot be suppressed", (const ProtocolDecl *))
7728+
WARNING(suppress_already_suppressed_protocol,none,
7729+
"already suppressed conformance to %0", (const ProtocolDecl *))
77227730

77237731
// -- older ones below --
77247732
ERROR(noncopyable_parameter_requires_ownership, none,

include/swift/AST/KnownProtocols.def

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,16 @@
4949
PROTOCOL_WITH_NAME(Id, Name)
5050
#endif
5151

52+
/// \def REPRESSIBLE_PROTOCOL_WITH_NAME(id, name)
53+
/// \param id the internal "enum name" of this protocol
54+
/// \param name a string literal with the external name of this protocol
55+
#ifndef REPRESSIBLE_PROTOCOL_WITH_NAME
56+
#define REPRESSIBLE_PROTOCOL_WITH_NAME(Id, Name) \
57+
PROTOCOL_WITH_NAME(Id, Name)
58+
#endif
59+
60+
#define REPRESSIBLE_PROTOCOL(name) REPRESSIBLE_PROTOCOL_WITH_NAME(name, #name)
61+
#define REPRESSIBLE_PROTOCOL_(name) REPRESSIBLE_PROTOCOL_WITH_NAME(name, "_" #name)
5262

5363
#define PROTOCOL(name) PROTOCOL_WITH_NAME(name, #name)
5464
#define PROTOCOL_(name) PROTOCOL_WITH_NAME(name, "_" #name)
@@ -140,7 +150,7 @@ PROTOCOL(FloatingPoint)
140150
INVERTIBLE_PROTOCOL_WITH_NAME(Name, #Name)
141151
#include "swift/ABI/InvertibleProtocols.def"
142152

143-
PROTOCOL_(BitwiseCopyable)
153+
REPRESSIBLE_PROTOCOL_(BitwiseCopyable)
144154

145155
EXPRESSIBLE_BY_LITERAL_PROTOCOL(ExpressibleByArrayLiteral, "Array", false)
146156
EXPRESSIBLE_BY_LITERAL_PROTOCOL(ExpressibleByBooleanLiteral, "BooleanLiteralType", true)
@@ -169,6 +179,9 @@ BUILTIN_EXPRESSIBLE_BY_LITERAL_PROTOCOL_(ExpressibleByBuiltinUnicodeScalarLitera
169179
#undef EXPRESSIBLE_BY_LITERAL_PROTOCOL_WITH_NAME
170180
#undef BUILTIN_EXPRESSIBLE_BY_LITERAL_PROTOCOL_
171181
#undef BUILTIN_EXPRESSIBLE_BY_LITERAL_PROTOCOL_WITH_NAME
182+
#undef REPRESSIBLE_PROTOCOL_WITH_NAME
183+
#undef REPRESSIBLE_PROTOCOL
184+
#undef REPRESSIBLE_PROTOCOL_
172185
#undef INVERTIBLE_PROTOCOL_WITH_NAME
173186
#undef PROTOCOL
174187
#undef PROTOCOL_

include/swift/AST/KnownProtocols.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ enum class KnownProtocolKind : uint8_t {
2828
#include "swift/AST/KnownProtocols.def"
2929
};
3030

31+
enum class RepressibleProtocolKind : uint8_t {
32+
#define REPRESSIBLE_PROTOCOL_WITH_NAME(Id, Name) Id,
33+
#include "swift/AST/KnownProtocols.def"
34+
};
35+
3136
enum : uint8_t {
3237
// This uses a preprocessor trick to count all the protocols. The enum value
3338
// expression below expands to "+1+1+1...". (Note that the first plus
@@ -44,6 +49,14 @@ enum : unsigned { NumKnownProtocolKindBits =
4449
/// Retrieve the name of the given known protocol.
4550
llvm::StringRef getProtocolName(KnownProtocolKind kind);
4651

52+
std::optional<RepressibleProtocolKind>
53+
getRepressibleProtocolKind(KnownProtocolKind kp);
54+
55+
KnownProtocolKind getKnownProtocolKind(RepressibleProtocolKind ip);
56+
57+
void simple_display(llvm::raw_ostream &out,
58+
const RepressibleProtocolKind &value);
59+
4760
/// MARK: Invertible protocols
4861
///
4962
/// The invertible protocols are a subset of the known protocols.
@@ -71,4 +84,27 @@ void simple_display(llvm::raw_ostream &out,
7184

7285
} // end namespace swift
7386

87+
namespace llvm {
88+
template <typename T, typename Enable>
89+
struct DenseMapInfo;
90+
template <>
91+
struct DenseMapInfo<swift::RepressibleProtocolKind> {
92+
using RepressibleProtocolKind = swift::RepressibleProtocolKind;
93+
using Impl = DenseMapInfo<uint8_t>;
94+
static inline RepressibleProtocolKind getEmptyKey() {
95+
return (RepressibleProtocolKind)Impl::getEmptyKey();
96+
}
97+
static inline RepressibleProtocolKind getTombstoneKey() {
98+
return (RepressibleProtocolKind)Impl::getTombstoneKey();
99+
}
100+
static unsigned getHashValue(const RepressibleProtocolKind &Val) {
101+
return Impl::getHashValue((uint8_t)Val);
102+
}
103+
static bool isEqual(const RepressibleProtocolKind &LHS,
104+
const RepressibleProtocolKind &RHS) {
105+
return LHS == RHS;
106+
}
107+
};
108+
} // namespace llvm
109+
74110
#endif

include/swift/AST/NameLookup.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -589,12 +589,16 @@ struct InheritedNominalEntry : Located<NominalTypeDecl *> {
589589
/// The location of the "preconcurrency" attribute if present.
590590
SourceLoc preconcurrencyLoc;
591591

592+
/// Whether this inherited entry was suppressed via "~".
593+
bool isSuppressed;
594+
592595
InheritedNominalEntry() { }
593596

594597
InheritedNominalEntry(NominalTypeDecl *item, SourceLoc loc,
595-
SourceLoc uncheckedLoc, SourceLoc preconcurrencyLoc)
598+
SourceLoc uncheckedLoc, SourceLoc preconcurrencyLoc,
599+
bool isSuppressed)
596600
: Located(item, loc), uncheckedLoc(uncheckedLoc),
597-
preconcurrencyLoc(preconcurrencyLoc) {}
601+
preconcurrencyLoc(preconcurrencyLoc), isSuppressed(isSuppressed) {}
598602
};
599603

600604
/// Retrieve the set of nominal type declarations that are directly

include/swift/AST/PrintOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,9 @@ struct PrintOptions {
388388
/// Suppress printing of `borrowing` and `consuming`.
389389
bool SuppressNoncopyableOwnershipModifiers = false;
390390

391+
/// Suppress printing of '~Proto' for suppressible, non-invertible protocols.
392+
bool SuppressConformanceSuppression = false;
393+
391394
/// List of attribute kinds that should not be printed.
392395
std::vector<AnyAttrKind> ExcludeAttrList = {
393396
DeclAttrKind::Transparent, DeclAttrKind::Effects,

include/swift/AST/TypeCheckRequests.h

Lines changed: 93 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,25 @@
1616
#ifndef SWIFT_TYPE_CHECK_REQUESTS_H
1717
#define SWIFT_TYPE_CHECK_REQUESTS_H
1818

19-
#include "swift/AST/ActorIsolation.h"
20-
#include "swift/AST/AnyFunctionRef.h"
2119
#include "swift/AST/ASTNode.h"
2220
#include "swift/AST/ASTTypeIDs.h"
21+
#include "swift/AST/ActorIsolation.h"
22+
#include "swift/AST/AnyFunctionRef.h"
2323
#include "swift/AST/CatchNode.h"
2424
#include "swift/AST/Effects.h"
25+
#include "swift/AST/Evaluator.h"
2526
#include "swift/AST/GenericParamList.h"
2627
#include "swift/AST/GenericSignature.h"
27-
#include "swift/AST/Type.h"
28-
#include "swift/AST/Evaluator.h"
2928
#include "swift/AST/Pattern.h"
3029
#include "swift/AST/PluginRegistry.h"
3130
#include "swift/AST/ProtocolConformance.h"
3231
#include "swift/AST/SimpleRequest.h"
3332
#include "swift/AST/SourceFile.h"
33+
#include "swift/AST/Type.h"
3434
#include "swift/AST/TypeResolutionStage.h"
3535
#include "swift/Basic/Statistic.h"
36+
#include "swift/Basic/TaggedUnion.h"
37+
#include "swift/Basic/TypeID.h"
3638
#include "llvm/ADT/Hashing.h"
3739
#include "llvm/ADT/STLExtras.h"
3840
#include "llvm/ADT/TinyPtrVector.h"
@@ -51,6 +53,7 @@ class DoCatchStmt;
5153
struct ExternalMacroDefinition;
5254
class ClosureExpr;
5355
class GenericParamList;
56+
class InverseTypeRepr;
5457
class LabeledStmt;
5558
class MacroDefinition;
5659
class PrecedenceGroupDecl;
@@ -78,13 +81,75 @@ void simple_display(
7881

7982
void simple_display(llvm::raw_ostream &out, ASTContext *ctx);
8083

84+
/// Emulates the following enum with associated values:
85+
/// enum InheritedTypeResult {
86+
/// case inherited(Type)
87+
/// case suppressed(Type, InverseTypeRepr *)
88+
/// case `default`
89+
/// }
90+
class InheritedTypeResult {
91+
struct Inherited_ {
92+
Type ty;
93+
};
94+
struct Suppressed_ {
95+
// The type which is suppressed. Not the result of inverting a protocol.
96+
Type ty;
97+
InverseTypeRepr *repr;
98+
};
99+
struct Default_ {};
100+
using Payload = TaggedUnion<Inherited_, Suppressed_, Default_>;
101+
Payload payload;
102+
InheritedTypeResult(Payload payload) : payload(payload) {}
103+
104+
public:
105+
enum Kind { Inherited, Suppressed, Default };
106+
static InheritedTypeResult forInherited(Type ty) { return {Inherited_{ty}}; }
107+
static InheritedTypeResult forSuppressed(Type ty, InverseTypeRepr *repr) {
108+
return {Suppressed_{ty, repr}};
109+
}
110+
static InheritedTypeResult forDefault() { return {Default_{}}; }
111+
operator Kind() {
112+
if (payload.isa<Inherited_>()) {
113+
return Kind::Inherited;
114+
} else if (payload.isa<Suppressed_>()) {
115+
return Kind::Suppressed;
116+
}
117+
return Kind::Default;
118+
}
119+
explicit operator bool() { return !payload.isa<Default_>(); }
120+
Type getInheritedTypeOrNull(ASTContext &ctx) {
121+
switch (*this) {
122+
case Inherited:
123+
return getInheritedType();
124+
case Suppressed: {
125+
auto suppressed = getSuppressed();
126+
auto kp = suppressed.first->getKnownProtocol();
127+
if (!kp)
128+
return Type();
129+
auto ipk = getInvertibleProtocolKind(*kp);
130+
if (!ipk)
131+
return Type();
132+
return ProtocolCompositionType::getInverseOf(ctx, *ipk);
133+
}
134+
case Default:
135+
return Type();
136+
}
137+
}
138+
Type getInheritedType() { return payload.get<Inherited_>().ty; }
139+
std::pair<Type, InverseTypeRepr *> getSuppressed() {
140+
auto &suppressed = payload.get<Suppressed_>();
141+
return {suppressed.ty, suppressed.repr};
142+
}
143+
};
144+
81145
/// Request the type from the ith entry in the inheritance clause for the
82146
/// given declaration.
83147
class InheritedTypeRequest
84148
: public SimpleRequest<
85149
InheritedTypeRequest,
86-
Type(llvm::PointerUnion<const TypeDecl *, const ExtensionDecl *>,
87-
unsigned, TypeResolutionStage),
150+
InheritedTypeResult(
151+
llvm::PointerUnion<const TypeDecl *, const ExtensionDecl *>,
152+
unsigned, TypeResolutionStage),
88153
RequestFlags::SeparatelyCached> {
89154
public:
90155
using SimpleRequest::SimpleRequest;
@@ -93,21 +158,22 @@ class InheritedTypeRequest
93158
friend SimpleRequest;
94159

95160
// Evaluation.
96-
Type
161+
InheritedTypeResult
97162
evaluate(Evaluator &evaluator,
98163
llvm::PointerUnion<const TypeDecl *, const ExtensionDecl *> decl,
99164
unsigned index, TypeResolutionStage stage) const;
100165

101-
const TypeLoc &getTypeLoc() const;
166+
const InheritedEntry &getInheritedEntry() const;
167+
ASTContext &getASTContext() const;
102168

103169
public:
104170
// Source location
105171
SourceLoc getNearestLoc() const;
106172

107173
// Caching
108174
bool isCached() const;
109-
std::optional<Type> getCachedResult() const;
110-
void cacheResult(Type value) const;
175+
std::optional<InheritedTypeResult> getCachedResult() const;
176+
void cacheResult(InheritedTypeResult value) const;
111177
};
112178

113179
/// Request the superclass type for the given class.
@@ -4885,6 +4951,23 @@ class LifetimeDependenceInfoRequest
48854951
bool isCached() const { return true; }
48864952
};
48874953

4954+
class SuppressesConformanceRequest
4955+
: public SimpleRequest<SuppressesConformanceRequest,
4956+
bool(NominalTypeDecl *decl, KnownProtocolKind kp),
4957+
RequestFlags::Cached> {
4958+
public:
4959+
using SimpleRequest::SimpleRequest;
4960+
4961+
private:
4962+
friend SimpleRequest;
4963+
4964+
bool evaluate(Evaluator &evaluator, NominalTypeDecl *decl,
4965+
KnownProtocolKind kp) const;
4966+
4967+
public:
4968+
bool isCached() const { return true; }
4969+
};
4970+
48884971
#define SWIFT_TYPEID_ZONE TypeChecker
48894972
#define SWIFT_TYPEID_HEADER "swift/AST/TypeCheckerTypeIDZone.def"
48904973
#include "swift/Basic/DefineTypeIDZone.h"

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -568,3 +568,6 @@ SWIFT_REQUEST(TypeChecker, ImportDeclRequest,
568568
Cached, NoLocationInfo)
569569
SWIFT_REQUEST(TypeChecker, LifetimeDependenceInfoRequest,
570570
LifetimeDependenceInfo(AbstractFunctionDecl *), Cached, NoLocationInfo)
571+
SWIFT_REQUEST(TypeChecker, SuppressesConformanceRequest,
572+
bool(NominalTypeDecl *decl, KnownProtocolKind kp),
573+
SeparatelyCached, NoLocationInfo)

include/swift/Basic/Features.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,9 @@ EXPERIMENTAL_FEATURE(ExtractConstantsFromMembers, false)
346346
/// Enable bitwise-copyable feature.
347347
EXPERIMENTAL_FEATURE(BitwiseCopyable, true)
348348

349+
/// Enable the suppression of inferred, non-invertible, protocols via ~.
350+
SUPPRESSIBLE_EXPERIMENTAL_FEATURE(ConformanceSuppression, true)
351+
349352
/// Enables the FixedArray data type.
350353
EXPERIMENTAL_FEATURE(FixedArrays, true)
351354

include/swift/Parse/Parser.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,11 @@ class Parser {
163163
// to ensure there's no parsing performance regression.
164164
bool EnabledNoncopyableGenerics;
165165

166+
bool canSuppressConformancesWithTilde() const {
167+
return EnabledNoncopyableGenerics ||
168+
Context.LangOpts.hasFeature(Feature::ConformanceSuppression);
169+
}
170+
166171
/// Whether we should delay parsing nominal type, extension, and function
167172
/// bodies.
168173
bool isDelayedParsingEnabled() const;

0 commit comments

Comments
 (0)