Skip to content

Commit ec10c5d

Browse files
Merge pull request #34249 from AnthonyLatsis/selfrefkind-refactor
AST: Refactor SelfReferenceKind in preparation for #33767
2 parents 4512717 + 4ee517f commit ec10c5d

File tree

3 files changed

+186
-166
lines changed

3 files changed

+186
-166
lines changed

include/swift/AST/Decl.h

Lines changed: 62 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -3741,62 +3741,79 @@ class ClassDecl final : public NominalTypeDecl {
37413741
}
37423742
};
37433743

3744+
/// A convenience wrapper around the \c SelfReferencePosition::Kind enum.
3745+
struct SelfReferencePosition final {
3746+
enum Kind : uint8_t { None, Covariant, Contravariant, Invariant };
37443747

3745-
/// Describes whether a requirement refers to 'Self', for use in the
3746-
/// is-inheritable and is-available-existential checks.
3747-
struct SelfReferenceKind {
3748-
bool result;
3749-
bool parameter;
3750-
bool requirement;
3751-
bool other;
3748+
private:
3749+
Kind kind;
37523750

3753-
/// The type does not refer to 'Self' at all.
3754-
static SelfReferenceKind None() {
3755-
return SelfReferenceKind(false, false, false, false);
3751+
public:
3752+
SelfReferencePosition(Kind kind) : kind(kind) {}
3753+
3754+
SelfReferencePosition flipped() const {
3755+
switch (kind) {
3756+
case None:
3757+
case Invariant:
3758+
return *this;
3759+
case Covariant:
3760+
return Contravariant;
3761+
case Contravariant:
3762+
return Covariant;
3763+
}
37563764
}
37573765

3758-
/// The type refers to 'Self', but only as the type of a property or
3759-
/// the result type of a method/subscript.
3760-
static SelfReferenceKind Result() {
3761-
return SelfReferenceKind(true, false, false, false);
3762-
}
3766+
explicit operator bool() const { return kind > None; }
37633767

3764-
/// The type refers to 'Self', but only as the parameter type
3765-
/// of a method/subscript.
3766-
static SelfReferenceKind Parameter() {
3767-
return SelfReferenceKind(false, true, false, false);
3768-
}
3768+
operator Kind() const { return kind; }
3769+
};
37693770

3770-
/// The type refers to 'Self' within a same-type requiement.
3771-
static SelfReferenceKind Requirement() {
3772-
return SelfReferenceKind(false, false, true, false);
3773-
}
3771+
/// Describes the least favorable positions at which a requirement refers
3772+
/// to 'Self' in terms of variance, for use in the is-inheritable and
3773+
/// is-available-existential checks.
3774+
struct SelfReferenceInfo final {
3775+
using Position = SelfReferencePosition;
3776+
3777+
bool hasCovariantSelfResult;
3778+
Position selfRef;
3779+
Position assocTypeRef;
37743780

3775-
/// The type refers to 'Self' in a position that is invariant.
3776-
static SelfReferenceKind Other() {
3777-
return SelfReferenceKind(false, false, false, true);
3781+
/// A reference to 'Self'.
3782+
static SelfReferenceInfo forSelfRef(Position position) {
3783+
assert(position);
3784+
return SelfReferenceInfo(false, position, Position::None);
37783785
}
37793786

3780-
SelfReferenceKind flip() const {
3781-
return SelfReferenceKind(parameter, result, requirement, other);
3787+
/// A reference to 'Self' through an associated type.
3788+
static SelfReferenceInfo forAssocTypeRef(Position position) {
3789+
assert(position);
3790+
return SelfReferenceInfo(false, Position::None, position);
37823791
}
37833792

3784-
SelfReferenceKind operator|=(SelfReferenceKind kind) {
3785-
result |= kind.result;
3786-
requirement |= kind.requirement;
3787-
parameter |= kind.parameter;
3788-
other |= kind.other;
3793+
SelfReferenceInfo operator|=(const SelfReferenceInfo &pos) {
3794+
hasCovariantSelfResult |= pos.hasCovariantSelfResult;
3795+
if (pos.selfRef > selfRef) {
3796+
selfRef = pos.selfRef;
3797+
}
3798+
if (pos.assocTypeRef > assocTypeRef) {
3799+
assocTypeRef = pos.assocTypeRef;
3800+
}
37893801
return *this;
37903802
}
37913803

3792-
operator bool() const {
3793-
return result || parameter || requirement || other;
3804+
explicit operator bool() const {
3805+
return hasCovariantSelfResult || selfRef || assocTypeRef;
37943806
}
37953807

3808+
SelfReferenceInfo()
3809+
: hasCovariantSelfResult(false), selfRef(Position::None),
3810+
assocTypeRef(Position::None) {}
3811+
37963812
private:
3797-
SelfReferenceKind(bool result, bool parameter, bool requirement, bool other)
3798-
: result(result), parameter(parameter), requirement(requirement),
3799-
other(other) { }
3813+
SelfReferenceInfo(bool hasCovariantSelfResult, Position selfRef,
3814+
Position assocTypeRef)
3815+
: hasCovariantSelfResult(hasCovariantSelfResult), selfRef(selfRef),
3816+
assocTypeRef(assocTypeRef) {}
38003817
};
38013818

38023819
/// The set of known protocols for which derived conformances are supported.
@@ -3978,15 +3995,12 @@ class ProtocolDecl final : public NominalTypeDecl {
39783995

39793996
/// Find direct Self references within the given requirement.
39803997
///
3981-
/// \param allowCovariantParameters If true, 'Self' is assumed to be
3982-
/// covariant anywhere; otherwise, only in the return type of the top-level
3983-
/// function type.
3984-
///
3985-
/// \param skipAssocTypes If true, associated types of 'Self' are ignored;
3986-
/// otherwise, they count as an 'other' usage of 'Self'.
3987-
SelfReferenceKind findProtocolSelfReferences(const ValueDecl *decl,
3988-
bool allowCovariantParameters,
3989-
bool skipAssocTypes) const;
3998+
/// \param treatNonResultCovariantSelfAsInvariant If true, 'Self' is only
3999+
/// assumed to be covariant in a top-level non-function type, or in the
4000+
/// eventual result type of a top-level function type.
4001+
SelfReferenceInfo
4002+
findProtocolSelfReferences(const ValueDecl *decl,
4003+
bool treatNonResultCovariantSelfAsInvariant) const;
39904004

39914005
/// Determine whether we are allowed to refer to an existential type
39924006
/// conforming to this protocol. This is only permitted if the type of

0 commit comments

Comments
 (0)