Skip to content

Commit 29acda5

Browse files
authored
Merge pull request #69406 from kavon/noncopyable-generics-pt2
[NoncopyableGenerics] handle `~Copyable` in `where`, `some`, and compositions.
2 parents 9133f02 + 4334279 commit 29acda5

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+845
-216
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2447,10 +2447,6 @@ ERROR(inferred_opaque_type,none,
24472447
// Inverse Constraints
24482448
ERROR(inverse_type_not_invertible,none,
24492449
"type %0 is not invertible", (Type))
2450-
ERROR(inverse_duplicate,none,
2451-
"duplicate inverse constraint", ())
2452-
NOTE(inverse_duplicate_previous,none,
2453-
"previous inverse constraint here", ())
24542450

24552451
// Extensions
24562452
ERROR(non_nominal_extension,none,
@@ -3132,6 +3128,15 @@ ERROR(requires_not_suitable_archetype,none,
31323128
"generic parameter or associated type",
31333129
(Type))
31343130

3131+
ERROR(requires_not_suitable_inverse_subject,none,
3132+
"cannot apply inverse %1 to type %0 in conformance requirement",
3133+
(Type, Type))
3134+
3135+
ERROR(requires_not_suitable_inverse_outer_subject,none,
3136+
"cannot add inverse constraint '%0: %1' "
3137+
"on generic parameter '%0' defined in outer scope",
3138+
(StringRef, StringRef))
3139+
31353140
ERROR(invalid_shape_requirement,none,
31363141
"invalid same-shape requirement between %0 and %1",
31373142
(Type, Type))
@@ -7558,7 +7563,7 @@ ERROR(noncopyable_cannot_conform_to_type, none,
75587563
"noncopyable %kind0 cannot conform to %1",
75597564
(const ValueDecl *, Type))
75607565
ERROR(noncopyable_parameter_requires_ownership, none,
7561-
"noncopyable parameter must specify its ownership", ())
7566+
"parameter of noncopyable type %0 must specify ownership", (Type))
75627567
ERROR(noncopyable_parameter_subscript_unsupported, none,
75637568
"subscripts cannot have noncopyable parameters yet", ())
75647569
NOTE(noncopyable_parameter_ownership_suggestion, none,

include/swift/AST/ExistentialLayout.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,13 @@ struct ExistentialLayout {
3131

3232
ExistentialLayout() {
3333
hasExplicitAnyObject = false;
34+
hasInverseCopyable = false;
3435
containsNonObjCProtocol = false;
3536
containsParameterized = false;
3637
}
3738

3839
ExistentialLayout(CanProtocolType type);
40+
ExistentialLayout(CanInverseType type);
3941
ExistentialLayout(CanProtocolCompositionType type);
4042
ExistentialLayout(CanParameterizedProtocolType type);
4143

@@ -45,6 +47,9 @@ struct ExistentialLayout {
4547
/// Whether the existential contains an explicit '& AnyObject' constraint.
4648
bool hasExplicitAnyObject : 1;
4749

50+
/// Whether the existential contains an explicit '& ~Copyable' constraint.
51+
bool hasInverseCopyable : 1;
52+
4853
/// Whether any protocol members are non-@objc.
4954
bool containsNonObjCProtocol : 1;
5055

include/swift/AST/KnownProtocols.def

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,14 @@
4141
PROTOCOL_WITH_NAME(Id, Name)
4242
#endif
4343

44+
/// \def INVERTIBLE_PROTOCOL_WITH_NAME(id, name)
45+
/// \param Name a string literal with the external name of this protocol
46+
/// \param Id the internal "enum name" of this protocol.
47+
#ifndef INVERTIBLE_PROTOCOL_WITH_NAME
48+
#define INVERTIBLE_PROTOCOL_WITH_NAME(Id, Name) \
49+
PROTOCOL_WITH_NAME(Id, Name)
50+
#endif
51+
4452

4553
#define PROTOCOL(name) PROTOCOL_WITH_NAME(name, #name)
4654
#define PROTOCOL_(name) PROTOCOL_WITH_NAME(name, "_" #name)
@@ -127,7 +135,7 @@ PROTOCOL(AsyncIteratorProtocol)
127135

128136
PROTOCOL(FloatingPoint)
129137

130-
PROTOCOL(Copyable)
138+
INVERTIBLE_PROTOCOL_WITH_NAME(Copyable, "Copyable")
131139

132140
EXPRESSIBLE_BY_LITERAL_PROTOCOL(ExpressibleByArrayLiteral, "Array", false)
133141
EXPRESSIBLE_BY_LITERAL_PROTOCOL(ExpressibleByBooleanLiteral, "BooleanLiteralType", true)
@@ -156,6 +164,7 @@ BUILTIN_EXPRESSIBLE_BY_LITERAL_PROTOCOL_(ExpressibleByBuiltinUnicodeScalarLitera
156164
#undef EXPRESSIBLE_BY_LITERAL_PROTOCOL_WITH_NAME
157165
#undef BUILTIN_EXPRESSIBLE_BY_LITERAL_PROTOCOL_
158166
#undef BUILTIN_EXPRESSIBLE_BY_LITERAL_PROTOCOL_WITH_NAME
167+
#undef INVERTIBLE_PROTOCOL_WITH_NAME
159168
#undef PROTOCOL
160169
#undef PROTOCOL_
161170
#undef PROTOCOL_WITH_NAME

include/swift/AST/KnownProtocols.h

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,37 @@ enum : uint8_t {
4242
enum : unsigned { NumKnownProtocolKindBits =
4343
countBitsUsed(static_cast<unsigned>(NumKnownProtocols - 1)) };
4444

45-
using KnownProtocolSet = FixedBitSet<NumKnownProtocols, KnownProtocolKind>;
46-
47-
/// Produces a set of all protocols that have an inverse, i.e., for every
48-
/// known protocol KP in the set, ~KP exists.
49-
KnownProtocolSet getInvertibleProtocols();
50-
5145
/// Retrieve the name of the given known protocol.
5246
llvm::StringRef getProtocolName(KnownProtocolKind kind);
5347

48+
/// MARK: Invertible protocols
49+
///
50+
/// The invertible protocols are a subset of the known protocols.
51+
52+
enum : uint8_t {
53+
// Use preprocessor trick to count all the invertible protocols.
54+
#define INVERTIBLE_PROTOCOL_WITH_NAME(Id, Name) +1
55+
/// The number of invertible protocols.
56+
NumInvertibleProtocols =
57+
#include "swift/AST/KnownProtocols.def"
58+
};
59+
60+
enum class InvertibleProtocolKind : uint8_t {
61+
#define INVERTIBLE_PROTOCOL_WITH_NAME(Id, Name) Id,
62+
#include "swift/AST/KnownProtocols.def"
63+
};
64+
65+
using InvertibleProtocolSet = FixedBitSet<NumInvertibleProtocols,
66+
InvertibleProtocolKind>;
67+
68+
/// Maps a KnownProtocol to the set of InvertibleProtocols, if a mapping exists.
69+
/// \returns None if the known protocol is not invertible.
70+
llvm::Optional<InvertibleProtocolKind>
71+
getInvertibleProtocolKind(KnownProtocolKind kp);
72+
73+
/// Returns the KnownProtocolKind corresponding to an InvertibleProtocolKind.
74+
KnownProtocolKind getKnownProtocolKind(InvertibleProtocolKind ip);
75+
5476
} // end namespace swift
5577

5678
#endif

include/swift/AST/TypeMatcher.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,14 @@ class TypeMatcher {
495495
sugaredFirstType);
496496
}
497497

498+
bool visitInverseType(CanInverseType firstInverse,
499+
Type secondType,
500+
Type sugaredFirstType) {
501+
// NOTE: If this visitor is reached, determine whether it should've been
502+
// before implementing this.
503+
llvm_unreachable("Yahaha! You found me!");
504+
}
505+
498506
bool visitLValueType(CanLValueType firstLValue, Type secondType,
499507
Type sugaredFirstType) {
500508
if (auto secondLValue = secondType->getAs<LValueType>()) {

include/swift/AST/TypeNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ ARTIFICIAL_TYPE(SILMoveOnlyWrapped, Type)
180180
ALWAYS_CANONICAL_ARTIFICIAL_TYPE(SILPack, Type)
181181
ARTIFICIAL_TYPE(SILToken, Type)
182182
TYPE(ProtocolComposition, Type)
183+
UNCHECKED_TYPE(Inverse, Type)
183184
TYPE(ParameterizedProtocol, Type)
184185
TYPE(Existential, Type)
185186
TYPE(LValue, Type)

include/swift/AST/Types.h

Lines changed: 79 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "swift/AST/ExtInfo.h"
2525
#include "swift/AST/GenericParamKey.h"
2626
#include "swift/AST/Identifier.h"
27+
#include "swift/AST/KnownProtocols.h"
2728
#include "swift/AST/Ownership.h"
2829
#include "swift/AST/ProtocolConformanceRef.h"
2930
#include "swift/AST/Requirement.h"
@@ -100,7 +101,6 @@ class ProtocolConformance;
100101
enum PointerTypeKind : unsigned;
101102
struct ValueOwnershipKind;
102103
class ErrorExpr;
103-
enum class KnownProtocolKind : uint8_t;
104104

105105
typedef CanTypeWrapper<SILFunctionType> CanSILFunctionType;
106106

@@ -1534,6 +1534,48 @@ class NominalOrBoundGenericNominalType : public AnyGenericType {
15341534
};
15351535
DEFINE_EMPTY_CAN_TYPE_WRAPPER(NominalOrBoundGenericNominalType, AnyGenericType)
15361536

1537+
/// InverseType represents the "inverse" of a ProtocolType as a constraint.
1538+
/// An inverse represents the _absence_ of an implicit constraint to the given
1539+
/// protocol.
1540+
///
1541+
/// Otherwise, an inverse is not a real type! It's an annotation for other types
1542+
/// to signal whether an implicit requirement on that type should be omitted.
1543+
/// Because that annotation is expressed in the surface language as if it _were_
1544+
/// a type (that is, as a type constraint) we still model it as a Type through
1545+
/// typechecking.
1546+
class InverseType final : public TypeBase {
1547+
Type protocol;
1548+
1549+
InverseType(Type type,
1550+
const ASTContext *canonicalContext,
1551+
RecursiveTypeProperties properties)
1552+
: TypeBase(TypeKind::Inverse, canonicalContext, properties),
1553+
protocol(type) {
1554+
assert(protocol->is<ProtocolType>());
1555+
}
1556+
1557+
public:
1558+
/// Produce an inverse constraint type for the given protocol type.
1559+
static Type get(Type protocolType);
1560+
1561+
1562+
/// Obtain the underlying \c ProtocolType that was inverted.
1563+
Type getInvertedProtocol() const {
1564+
return protocol;
1565+
}
1566+
1567+
/// Get known kind of inverse this type represents.
1568+
InvertibleProtocolKind getInverseKind() const;
1569+
1570+
// Implement isa/cast/dyncast/etc.
1571+
static bool classof(const TypeBase *T) {
1572+
return T->getKind() == TypeKind::Inverse;
1573+
}
1574+
};
1575+
BEGIN_CAN_TYPE_WRAPPER(InverseType, Type)
1576+
PROXY_CAN_TYPE_SIMPLE_GETTER(getInvertedProtocol)
1577+
END_CAN_TYPE_WRAPPER(InverseType, Type)
1578+
15371579
/// ErrorType - Represents the type of an erroneously constructed declaration,
15381580
/// expression, or type. When creating ErrorTypes, an associated error
15391581
/// diagnostic should always be emitted. That way when later stages of
@@ -5739,13 +5781,37 @@ class ProtocolCompositionType final : public TypeBase,
57395781
public llvm::FoldingSetNode,
57405782
private llvm::TrailingObjects<ProtocolCompositionType, Type> {
57415783
friend TrailingObjects;
5784+
5785+
// TODO(kavon): this could probably be folded into the existing Bits field
5786+
// or we could just store the InverseType's in the Members array.
5787+
InvertibleProtocolSet Inverses;
57425788

57435789
public:
57445790
/// Retrieve an instance of a protocol composition type with the
5745-
/// given set of members.
5791+
/// given set of members. A "hidden member" is an implicit constraint that
5792+
/// is present for all protocol compositions.
5793+
///
5794+
/// \param Members the regular members of this composition.
5795+
/// \param Inverses the set of inverses that are a member of the composition,
5796+
/// i.e., if \c IP is in this set, then \c ~IP is a member of
5797+
/// this composition.
5798+
/// \param HasExplicitAnyObject indicates whether this composition should be
5799+
/// treated as if \c AnyObject was a member.
57465800
static Type get(const ASTContext &C, ArrayRef<Type> Members,
5801+
InvertibleProtocolSet Inverses,
57475802
bool HasExplicitAnyObject);
57485803

5804+
/// Retrieve an instance of a protocol composition type with the
5805+
/// given set of members. Assumes no inverses are present in \c Members.
5806+
static Type get(const ASTContext &C, ArrayRef<Type> Members,
5807+
bool HasExplicitAnyObject);
5808+
5809+
/// Constructs a protocol composition corresponding to the `Any` type.
5810+
static Type theAnyType(const ASTContext &C);
5811+
5812+
/// Constructs a protocol composition corresponding to the `AnyObject` type.
5813+
static Type theAnyObjectType(const ASTContext &C);
5814+
57495815
/// Canonical protocol composition types are minimized only to a certain
57505816
/// degree to preserve ABI compatibility. This routine enables performing
57515817
/// slower, but stricter minimization at need (e.g. redeclaration checking).
@@ -5768,11 +5834,14 @@ class ProtocolCompositionType final : public TypeBase,
57685834
return {getTrailingObjects<Type>(), Bits.ProtocolCompositionType.Count};
57695835
}
57705836

5837+
InvertibleProtocolSet getInverses() const { return Inverses; }
5838+
57715839
void Profile(llvm::FoldingSetNodeID &ID) {
5772-
Profile(ID, getMembers(), hasExplicitAnyObject());
5840+
Profile(ID, getMembers(), getInverses(), hasExplicitAnyObject());
57735841
}
57745842
static void Profile(llvm::FoldingSetNodeID &ID,
57755843
ArrayRef<Type> Members,
5844+
InvertibleProtocolSet Inverses,
57765845
bool HasExplicitAnyObject);
57775846

57785847
/// True if the composition requires the concrete conforming type to
@@ -5793,12 +5862,15 @@ class ProtocolCompositionType final : public TypeBase,
57935862
private:
57945863
static ProtocolCompositionType *build(const ASTContext &C,
57955864
ArrayRef<Type> Members,
5865+
InvertibleProtocolSet Inverses,
57965866
bool HasExplicitAnyObject);
57975867

57985868
ProtocolCompositionType(const ASTContext *ctx, ArrayRef<Type> members,
5869+
InvertibleProtocolSet inverses,
57995870
bool hasExplicitAnyObject,
58005871
RecursiveTypeProperties properties)
5801-
: TypeBase(TypeKind::ProtocolComposition, /*Context=*/ctx, properties) {
5872+
: TypeBase(TypeKind::ProtocolComposition, /*Context=*/ctx, properties),
5873+
Inverses(inverses) {
58025874
Bits.ProtocolCompositionType.HasExplicitAnyObject = hasExplicitAnyObject;
58035875
Bits.ProtocolCompositionType.Count = members.size();
58045876
std::uninitialized_copy(members.begin(), members.end(),
@@ -7223,7 +7295,8 @@ inline bool TypeBase::isConstraintType() const {
72237295
inline bool CanType::isConstraintTypeImpl(CanType type) {
72247296
return (isa<ProtocolType>(type) ||
72257297
isa<ProtocolCompositionType>(type) ||
7226-
isa<ParameterizedProtocolType>(type));
7298+
isa<ParameterizedProtocolType>(type) ||
7299+
isa<InverseType>(type));
72277300
}
72287301

72297302
inline bool TypeBase::isExistentialType() {
@@ -7239,6 +7312,7 @@ inline bool CanType::isExistentialTypeImpl(CanType type) {
72397312
isa<ProtocolCompositionType>(type) ||
72407313
isa<ExistentialType>(type) ||
72417314
isa<ParameterizedProtocolType>(type);
7315+
// TODO(kavon): treat InverseType as an existential, etc?
72427316
}
72437317

72447318
inline bool CanType::isAnyExistentialTypeImpl(CanType type) {

include/swift/Basic/FixedBitSet.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,14 +84,21 @@ class FixedBitSet {
8484

8585
public:
8686
/// Build an empty set.
87-
FixedBitSet() {}
87+
constexpr FixedBitSet() {}
8888

8989
/// Build a set containing the given elements.
9090
FixedBitSet(std::initializer_list<ValueType> elements) {
9191
for (const auto &elt : elements)
9292
insert(elt);
9393
}
9494

95+
/// Build a set filled with all possible elements, i.e., a "full" set.
96+
static FixedBitSet full() {
97+
FixedBitSet set;
98+
set.insertAll();
99+
return set;
100+
}
101+
95102
/// Return true if the set is empty.
96103
bool empty() const {
97104
for (auto chunk : chunks)

0 commit comments

Comments
 (0)