Skip to content

Commit b2fe028

Browse files
committed
[NFC] Turn SelfReferenceKind into a standalone utility type
1 parent 427190d commit b2fe028

File tree

7 files changed

+107
-80
lines changed

7 files changed

+107
-80
lines changed

include/swift/AST/Decl.h

Lines changed: 17 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -2157,78 +2157,41 @@ class PoundDiagnosticDecl : public Decl {
21572157

21582158
class OpaqueTypeDecl;
21592159

2160-
/// A convenience wrapper around the \c SelfReferencePosition::Kind enum.
2161-
struct SelfReferencePosition final {
2162-
enum Kind : uint8_t { None, Covariant, Contravariant, Invariant };
2163-
2164-
private:
2165-
Kind kind;
2160+
/// Describes the least favorable positions at which a requirement refers
2161+
/// to 'Self' in terms of variance, for use in the is-inheritable and
2162+
/// is-available-existential checks.
2163+
class SelfReferenceInfo final {
2164+
using OptionalTypePosition = OptionalEnum<decltype(TypePosition::Covariant)>;
21662165

21672166
public:
2168-
SelfReferencePosition(Kind kind) : kind(kind) {}
2169-
2170-
SelfReferencePosition flipped() const {
2171-
switch (kind) {
2172-
case None:
2173-
case Invariant:
2174-
return *this;
2175-
case Covariant:
2176-
return Contravariant;
2177-
case Contravariant:
2178-
return Covariant;
2179-
}
2180-
llvm_unreachable("unhandled self reference position!");
2181-
}
2182-
2183-
explicit operator bool() const { return kind > None; }
2184-
2185-
operator Kind() const { return kind; }
2186-
};
2187-
2188-
/// Describes the least favorable positions at which a protocol member refers
2189-
/// to 'Self' in terms of variance. Used in the is-inheritable and
2190-
/// is-available-in-existential checks.
2191-
struct SelfReferenceInfo final {
2192-
using Position = SelfReferencePosition;
2193-
21942167
bool hasCovariantSelfResult;
2195-
Position selfRef;
2196-
Position assocTypeRef;
2168+
2169+
OptionalTypePosition selfRef;
2170+
OptionalTypePosition assocTypeRef;
21972171

21982172
/// A reference to 'Self'.
2199-
static SelfReferenceInfo forSelfRef(Position position) {
2200-
assert(position);
2201-
return SelfReferenceInfo(false, position, Position::None);
2173+
static SelfReferenceInfo forSelfRef(TypePosition position) {
2174+
return SelfReferenceInfo(false, position, llvm::None);
22022175
}
22032176

22042177
/// A reference to 'Self' through an associated type.
2205-
static SelfReferenceInfo forAssocTypeRef(Position position) {
2206-
assert(position);
2207-
return SelfReferenceInfo(false, Position::None, position);
2178+
static SelfReferenceInfo forAssocTypeRef(TypePosition position) {
2179+
return SelfReferenceInfo(false, llvm::None, position);
22082180
}
22092181

2210-
SelfReferenceInfo operator|=(const SelfReferenceInfo &pos) {
2211-
hasCovariantSelfResult |= pos.hasCovariantSelfResult;
2212-
if (pos.selfRef > selfRef) {
2213-
selfRef = pos.selfRef;
2214-
}
2215-
if (pos.assocTypeRef > assocTypeRef) {
2216-
assocTypeRef = pos.assocTypeRef;
2217-
}
2218-
return *this;
2219-
}
2182+
SelfReferenceInfo &operator|=(const SelfReferenceInfo &other);
22202183

22212184
explicit operator bool() const {
22222185
return hasCovariantSelfResult || selfRef || assocTypeRef;
22232186
}
22242187

22252188
SelfReferenceInfo()
2226-
: hasCovariantSelfResult(false), selfRef(Position::None),
2227-
assocTypeRef(Position::None) {}
2189+
: hasCovariantSelfResult(false), selfRef(llvm::None),
2190+
assocTypeRef(llvm::None) {}
22282191

22292192
private:
2230-
SelfReferenceInfo(bool hasCovariantSelfResult, Position selfRef,
2231-
Position assocTypeRef)
2193+
SelfReferenceInfo(bool hasCovariantSelfResult, OptionalTypePosition selfRef,
2194+
OptionalTypePosition assocTypeRef)
22322195
: hasCovariantSelfResult(hasCovariantSelfResult), selfRef(selfRef),
22332196
assocTypeRef(assocTypeRef) {}
22342197
};

include/swift/AST/Type.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,34 @@ enum class ForeignRepresentableKind : uint8_t {
203203
StaticBridged,
204204
};
205205

206+
/// An enum wrapper used to describe the variance position of a type within
207+
/// another type. For example, a function type is covariant in its result type;
208+
/// therefore, the result type is in covariant position relative to the function
209+
/// type.
210+
struct TypePosition final {
211+
enum : uint8_t { Covariant, Contravariant, Invariant };
212+
213+
private:
214+
decltype(Covariant) kind;
215+
216+
public:
217+
TypePosition(decltype(kind) kind) : kind(kind) {}
218+
219+
TypePosition flipped() const {
220+
switch (kind) {
221+
case Invariant:
222+
return *this;
223+
case Covariant:
224+
return Contravariant;
225+
case Contravariant:
226+
return Covariant;
227+
}
228+
llvm_unreachable("Unhandled type position!");
229+
}
230+
231+
operator decltype(kind)() const { return kind; }
232+
};
233+
206234
/// Type - This is a simple value object that contains a pointer to a type
207235
/// class. This is potentially sugared. We use this throughout the codebase
208236
/// instead of a raw "TypeBase*" to disable equality comparison, which is unsafe

include/swift/Basic/OptionalEnum.h

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ namespace swift {
4242
template<typename U>
4343
/*implicit*/ OptionalEnum(
4444
U &&value,
45-
typename std::enable_if<!std::is_integral<U>::value>::type * = {})
45+
typename std::enable_if<std::is_convertible<U, T>::value>::type * = {})
4646
: Storage(static_cast<storage_type>(T{std::forward<U>(value)}) + 1) {
4747
assert(hasValue() && "cannot store this value");
4848
}
@@ -82,6 +82,32 @@ namespace swift {
8282
assert(Storage == (storage_type)(intptr_t)Storage);
8383
return (intptr_t)Storage;
8484
}
85+
86+
// Provide comparison operators for the optional value.
87+
88+
friend bool operator==(const OptionalEnum &lhs, const OptionalEnum &rhs) {
89+
return (!lhs && !rhs) || (lhs && rhs && lhs.getValue() == rhs.getValue());
90+
}
91+
92+
friend bool operator!=(const OptionalEnum &lhs, const OptionalEnum &rhs) {
93+
return !(lhs == rhs);
94+
}
95+
96+
friend bool operator<(const OptionalEnum &lhs, const OptionalEnum &rhs) {
97+
return rhs && (!lhs || lhs.getValue() < rhs.getValue());
98+
}
99+
100+
friend bool operator>(const OptionalEnum &lhs, const OptionalEnum &rhs) {
101+
return rhs < lhs;
102+
}
103+
104+
friend bool operator<=(const OptionalEnum &lhs, const OptionalEnum &rhs) {
105+
return !(rhs < lhs);
106+
}
107+
108+
friend bool operator>=(const OptionalEnum &lhs, const OptionalEnum &rhs) {
109+
return !(lhs < rhs);
110+
}
85111
};
86112
} // end namespace swift
87113

lib/AST/Decl.cpp

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3727,12 +3727,24 @@ void ValueDecl::copyFormalAccessFrom(const ValueDecl *source,
37273727
}
37283728
}
37293729

3730+
SelfReferenceInfo &
3731+
SelfReferenceInfo::operator|=(const SelfReferenceInfo &other) {
3732+
hasCovariantSelfResult |= other.hasCovariantSelfResult;
3733+
if (other.selfRef > selfRef) {
3734+
selfRef = other.selfRef;
3735+
}
3736+
if (other.assocTypeRef > assocTypeRef) {
3737+
assocTypeRef = other.assocTypeRef;
3738+
}
3739+
return *this;
3740+
}
3741+
37303742
/// Report references to 'Self' within the given type.
37313743
///
37323744
/// \param position The current position in terms of variance.
3733-
static SelfReferenceInfo
3734-
findProtocolSelfReferences(const ProtocolDecl *proto, Type type,
3735-
SelfReferencePosition position) {
3745+
static SelfReferenceInfo findProtocolSelfReferences(const ProtocolDecl *proto,
3746+
Type type,
3747+
TypePosition position) {
37363748
// If there are no type parameters, we're done.
37373749
if (!type->hasTypeParameter())
37383750
return SelfReferenceInfo();
@@ -3757,8 +3769,8 @@ findProtocolSelfReferences(const ProtocolDecl *proto, Type type,
37573769
for (auto param : funcTy->getParams()) {
37583770
// inout parameters are invariant.
37593771
if (param.isInOut()) {
3760-
inputInfo |= findProtocolSelfReferences(
3761-
proto, param.getPlainType(), SelfReferencePosition::Invariant);
3772+
inputInfo |= findProtocolSelfReferences(proto, param.getPlainType(),
3773+
TypePosition::Invariant);
37623774
continue;
37633775
}
37643776
inputInfo |= findProtocolSelfReferences(proto, param.getParameterType(),
@@ -3770,7 +3782,7 @@ findProtocolSelfReferences(const ProtocolDecl *proto, Type type,
37703782

37713783
auto resultInfo =
37723784
findProtocolSelfReferences(proto, funcTy->getResult(), position);
3773-
if (resultInfo.selfRef == SelfReferencePosition::Covariant) {
3785+
if (resultInfo.selfRef == TypePosition::Covariant) {
37743786
resultInfo.hasCovariantSelfResult = true;
37753787
}
37763788
return inputInfo |= resultInfo;
@@ -3811,13 +3823,13 @@ findProtocolSelfReferences(const ProtocolDecl *proto, Type type,
38113823
} else if (bgt->isDictionary()) {
38123824
// Swift.Dictionary preserves variance in its Element type.
38133825
info |= findProtocolSelfReferences(proto, bgt->getGenericArgs().front(),
3814-
SelfReferencePosition::Invariant);
3826+
TypePosition::Invariant);
38153827
info |= findProtocolSelfReferences(proto, bgt->getGenericArgs().back(),
38163828
position);
38173829
} else {
38183830
for (auto paramType : bgt->getGenericArgs()) {
38193831
info |= findProtocolSelfReferences(proto, paramType,
3820-
SelfReferencePosition::Invariant);
3832+
TypePosition::Invariant);
38213833
}
38223834
}
38233835
}
@@ -3828,7 +3840,7 @@ findProtocolSelfReferences(const ProtocolDecl *proto, Type type,
38283840
// Opaque result types of protocol extension members contain an invariant
38293841
// reference to 'Self'.
38303842
if (type->is<OpaqueTypeArchetypeType>())
3831-
return SelfReferenceInfo::forSelfRef(SelfReferencePosition::Invariant);
3843+
return SelfReferenceInfo::forSelfRef(TypePosition::Invariant);
38323844

38333845
// Protocol compositions preserve variance.
38343846
auto constraint = type;
@@ -3879,13 +3891,12 @@ SelfReferenceInfo ValueDecl::findProtocolSelfReferences(
38793891
for (auto param : type->castTo<AnyFunctionType>()->getParams()) {
38803892
// inout parameters are invariant.
38813893
if (param.isInOut()) {
3882-
inputInfo |= ::findProtocolSelfReferences(
3883-
proto, param.getPlainType(), SelfReferencePosition::Invariant);
3894+
inputInfo |= ::findProtocolSelfReferences(proto, param.getPlainType(),
3895+
TypePosition::Invariant);
38843896
continue;
38853897
}
3886-
inputInfo |=
3887-
::findProtocolSelfReferences(proto, param.getParameterType(),
3888-
SelfReferencePosition::Contravariant);
3898+
inputInfo |= ::findProtocolSelfReferences(proto, param.getParameterType(),
3899+
TypePosition::Contravariant);
38893900
}
38903901

38913902
// A covariant Self result inside a parameter will not be bona fide.
@@ -3898,24 +3909,24 @@ SelfReferenceInfo ValueDecl::findProtocolSelfReferences(
38983909
// Methods of non-final classes can only contain a covariant 'Self'
38993910
// as their result type.
39003911
if (treatNonResultCovariantSelfAsInvariant &&
3901-
inputInfo.selfRef == SelfReferencePosition::Covariant) {
3902-
inputInfo.selfRef = SelfReferencePosition::Invariant;
3912+
inputInfo.selfRef == TypePosition::Covariant) {
3913+
inputInfo.selfRef = TypePosition::Invariant;
39033914
}
39043915

39053916
auto resultInfo = ::findProtocolSelfReferences(
39063917
proto, type->castTo<AnyFunctionType>()->getResult(),
3907-
SelfReferencePosition::Covariant);
3908-
if (resultInfo.selfRef == SelfReferencePosition::Covariant) {
3918+
TypePosition::Covariant);
3919+
if (resultInfo.selfRef == TypePosition::Covariant) {
39093920
resultInfo.hasCovariantSelfResult = true;
39103921
}
39113922

39123923
return inputInfo |= resultInfo;
39133924
} else {
39143925
assert(isa<VarDecl>(this));
39153926

3916-
auto info = ::findProtocolSelfReferences(proto, type,
3917-
SelfReferencePosition::Covariant);
3918-
if (info.selfRef == SelfReferencePosition::Covariant) {
3927+
auto info =
3928+
::findProtocolSelfReferences(proto, type, TypePosition::Covariant);
3929+
if (info.selfRef == TypePosition::Covariant) {
39193930
info.hasCovariantSelfResult = true;
39203931
}
39213932

lib/Sema/ConstraintSystem.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5857,7 +5857,7 @@ bool ConstraintSystem::isAvailableInExistential(const ProtocolDecl *proto,
58575857
// an associated type in any position, we cannot make use of the member.
58585858
const auto info = member->findProtocolSelfReferences(
58595859
proto, /*treatNonResultCovariantSelfAsInvariant=*/false);
5860-
if (info.selfRef > SelfReferencePosition::Covariant || info.assocTypeRef) {
5860+
if (info.selfRef > TypePosition::Covariant || info.assocTypeRef) {
58615861
return false;
58625862
}
58635863

lib/Sema/TypeCheckDecl.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -682,8 +682,7 @@ ExistentialRequiresAnyRequest::evaluate(Evaluator &evaluator,
682682
if (auto valueMember = dyn_cast<ValueDecl>(member)) {
683683
const auto info = valueMember->findProtocolSelfReferences(
684684
decl, /*treatNonResultCovariantSelfAsInvariant=*/false);
685-
if (info.selfRef > SelfReferencePosition::Covariant ||
686-
info.assocTypeRef) {
685+
if (info.selfRef > TypePosition::Covariant || info.assocTypeRef) {
687686
return true;
688687
}
689688
}

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4058,7 +4058,7 @@ void ConformanceChecker::checkNonFinalClassWitness(ValueDecl *requirement,
40584058
const auto selfRefInfo = requirement->findProtocolSelfReferences(
40594059
Proto, /*treatNonResultCovariantSelfAsInvariant=*/true);
40604060

4061-
if (selfRefInfo.selfRef == SelfReferencePosition::Invariant) {
4061+
if (selfRefInfo.selfRef == TypePosition::Invariant) {
40624062
// References to Self in a position where subclasses cannot do
40634063
// the right thing. Complain if the adoptee is a non-final
40644064
// class.

0 commit comments

Comments
 (0)