Skip to content

Commit 01c899b

Browse files
committed
SelfReferenceInfo: Collect references at all kinds of variance positions
1 parent 26e888e commit 01c899b

File tree

5 files changed

+93
-58
lines changed

5 files changed

+93
-58
lines changed

include/swift/AST/Type.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,13 @@ enum class ForeignRepresentableKind : uint8_t {
190190
/// therefore, the result type is in covariant position relative to the function
191191
/// type.
192192
struct TypePosition final {
193-
enum : uint8_t { Covariant, Contravariant, Invariant, Shape };
193+
enum : uint8_t {
194+
Covariant = 1 << 0,
195+
Contravariant = 1 << 1,
196+
Invariant = 1 << 2,
197+
Shape = 1 << 3,
198+
Last_Position = Shape,
199+
};
194200

195201
private:
196202
decltype(Covariant) kind;
@@ -213,6 +219,10 @@ struct TypePosition final {
213219

214220
operator decltype(kind)() const { return kind; }
215221
};
222+
enum : unsigned {
223+
NumTypePositions =
224+
countBitsUsed(static_cast<unsigned>(TypePosition::Last_Position))
225+
};
216226

217227
/// Type - This is a simple value object that contains a pointer to a type
218228
/// class. This is potentially sugared. We use this throughout the codebase

lib/Sema/OpenedExistentials.cpp

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,10 @@ using namespace swift;
2929

3030
GenericParameterReferenceInfo &
3131
GenericParameterReferenceInfo::operator|=(const GenericParameterReferenceInfo &other) {
32-
hasCovariantSelfResult |= other.hasCovariantSelfResult;
33-
if (other.selfRef > selfRef) {
34-
selfRef = other.selfRef;
35-
}
36-
if (other.assocTypeRef > assocTypeRef) {
37-
assocTypeRef = other.assocTypeRef;
38-
}
32+
DirectRefs |= other.DirectRefs;
33+
DepMemberTyRefs |= other.DepMemberTyRefs;
34+
HasCovariantGenericParamResult |= other.HasCovariantGenericParamResult;
35+
3936
return *this;
4037
}
4138

@@ -296,9 +293,9 @@ findGenericParameterReferencesRec(CanGenericSignature genericSig,
296293
// A direct reference to 'Self'.
297294
if (type->is<GenericTypeParamType>()) {
298295
if (position == TypePosition::Covariant && canBeCovariantResult)
299-
return GenericParameterReferenceInfo::forCovariantResult();
296+
return GenericParameterReferenceInfo::forCovariantGenericParamResult();
300297

301-
return GenericParameterReferenceInfo::forSelfRef(position);
298+
return GenericParameterReferenceInfo::forDirectRef(position);
302299
}
303300

304301
if (origParam != openedParam) {
@@ -332,7 +329,7 @@ findGenericParameterReferencesRec(CanGenericSignature genericSig,
332329
}
333330

334331
// A reference to an associated type rooted on 'Self'.
335-
return GenericParameterReferenceInfo::forAssocTypeRef(position);
332+
return GenericParameterReferenceInfo::forDependentMemberTypeRef(position);
336333
}
337334

338335
GenericParameterReferenceInfo
@@ -393,7 +390,7 @@ bool HasSelfOrAssociatedTypeRequirementsRequest::evaluate(
393390
// For value members, look at their type signatures.
394391
if (auto valueMember = dyn_cast<ValueDecl>(member)) {
395392
const auto info = findExistentialSelfReferences(valueMember);
396-
if (info.selfRef > TypePosition::Covariant || info.assocTypeRef) {
393+
if (info.hasNonCovariantRef() || info.hasDependentMemberTypeRef()) {
397394
return true;
398395
}
399396
}
@@ -532,14 +529,14 @@ bool swift::isMemberAvailableOnExistential(
532529
member, existentialSig.OpenedSig, origParam, openedParam,
533530
std::nullopt);
534531

535-
if (info.selfRef > TypePosition::Covariant ||
536-
info.assocTypeRef > TypePosition::Covariant) {
532+
if (info.hasNonCovariantRef()) {
537533
return false;
538534
}
539535

540536
// FIXME: Appropriately diagnose assignments instead.
541537
if (auto *const storageDecl = dyn_cast<AbstractStorageDecl>(member)) {
542-
if (info.hasCovariantSelfResult && storageDecl->supportsMutation())
538+
if (info.hasCovariantGenericParamResult() &&
539+
storageDecl->supportsMutation())
543540
return false;
544541
}
545542

@@ -686,8 +683,7 @@ swift::canOpenExistentialCallArgument(ValueDecl *callee, unsigned paramIdx,
686683
callee, existentialSig.OpenedSig, genericParam,
687684
existentialSig.SelfType->castTo<GenericTypeParamType>(),
688685
/*skipParamIdx=*/paramIdx);
689-
if (referenceInfo.selfRef > TypePosition::Covariant ||
690-
referenceInfo.assocTypeRef > TypePosition::Covariant)
686+
if (referenceInfo.hasNonCovariantRef())
691687
return std::nullopt;
692688

693689
return std::make_tuple(genericParam, paramTypeVar, argTy, adjustments);
@@ -898,4 +894,4 @@ Type swift::typeEraseOpenedArchetypesFromEnvironment(
898894

899895
return Type();
900896
});
901-
}
897+
}

lib/Sema/OpenedExistentials.h

Lines changed: 61 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -22,52 +22,80 @@ namespace swift {
2222
class CanGenericSignature;
2323
class GenericTypeParamType;
2424

25-
/// Describes the least favorable positions at which a requirement refers
26-
/// to a given generic parameter in terms of variance, for use in the
27-
/// is-inheritable and is-available-existential checks.
25+
/// Stores the variance positions at which a type references a specific
26+
/// generic parameter.
2827
class GenericParameterReferenceInfo final {
29-
using OptionalTypePosition = OptionalEnum<decltype(TypePosition::Covariant)>;
28+
static constexpr unsigned NumTypePositionBits = 4;
29+
static_assert(NumTypePositions <= NumTypePositionBits,
30+
"Not enough bits to store all cases");
31+
32+
uint8_t DirectRefs : NumTypePositionBits;
33+
uint8_t DepMemberTyRefs : NumTypePositionBits;
34+
35+
/// Whether there is a reference to the generic parameter at hand in covariant
36+
/// result type position. This position is the uncurried interface type of a
37+
/// declaration, stipped of any optionality. For example, this is true for
38+
/// 'Self' in 'func foo(Int) -> () -> Self?'.
39+
bool HasCovariantGenericParamResult;
40+
41+
GenericParameterReferenceInfo(uint8_t DirectRefs, uint8_t DepMemberTyRefs,
42+
bool HasCovariantGenericParamResult)
43+
: DirectRefs(DirectRefs), DepMemberTyRefs(DepMemberTyRefs),
44+
HasCovariantGenericParamResult(HasCovariantGenericParamResult) {}
3045

3146
public:
32-
/// Whether the uncurried interface type of the declaration, stripped of any
33-
/// optionality, is a direct reference to the generic parameter at hand. For
34-
/// example, "func foo(x: Int) -> () -> Self?" has a covariant 'Self' result.
35-
bool hasCovariantSelfResult;
47+
GenericParameterReferenceInfo()
48+
: GenericParameterReferenceInfo(0, 0, false) {}
3649

37-
OptionalTypePosition selfRef;
38-
OptionalTypePosition assocTypeRef;
50+
/// A direct reference to the generic parameter.
51+
static GenericParameterReferenceInfo forDirectRef(TypePosition pos) {
52+
return GenericParameterReferenceInfo(pos, 0, false);
53+
}
3954

40-
/// A reference to 'Self'.
41-
static GenericParameterReferenceInfo forSelfRef(TypePosition position) {
42-
return GenericParameterReferenceInfo(false, position, std::nullopt);
55+
/// A direct reference to the generic parameter in covariant result type
56+
/// position.
57+
static GenericParameterReferenceInfo forCovariantGenericParamResult() {
58+
return GenericParameterReferenceInfo(TypePosition::Covariant, 0, true);
4359
}
4460

45-
/// A reference to the generic parameter in covariant result position.
46-
static GenericParameterReferenceInfo forCovariantResult() {
47-
return GenericParameterReferenceInfo(true, TypePosition::Covariant,
48-
std::nullopt);
61+
/// A reference to a dependent member type rooted on the generic parameter.
62+
static GenericParameterReferenceInfo
63+
forDependentMemberTypeRef(TypePosition pos) {
64+
return GenericParameterReferenceInfo(0, pos, false);
4965
}
5066

51-
/// A reference to 'Self' through an associated type.
52-
static GenericParameterReferenceInfo forAssocTypeRef(TypePosition position) {
53-
return GenericParameterReferenceInfo(false, std::nullopt, position);
67+
bool hasDirectRef(std::optional<TypePosition> pos = std::nullopt) const {
68+
if (!pos) {
69+
return DirectRefs;
70+
}
71+
72+
return DirectRefs & pos.value();
5473
}
5574

56-
GenericParameterReferenceInfo &operator|=(const GenericParameterReferenceInfo &other);
75+
bool hasDependentMemberTypeRef(
76+
std::optional<TypePosition> pos = std::nullopt) const {
77+
if (!pos) {
78+
return DepMemberTyRefs;
79+
}
5780

58-
explicit operator bool() const {
59-
return hasCovariantSelfResult || selfRef || assocTypeRef;
81+
return DepMemberTyRefs & pos.value();
6082
}
6183

62-
GenericParameterReferenceInfo()
63-
: hasCovariantSelfResult(false), selfRef(std::nullopt),
64-
assocTypeRef(std::nullopt) {}
65-
66-
private:
67-
GenericParameterReferenceInfo(bool hasCovariantSelfResult, OptionalTypePosition selfRef,
68-
OptionalTypePosition assocTypeRef)
69-
: hasCovariantSelfResult(hasCovariantSelfResult), selfRef(selfRef),
70-
assocTypeRef(assocTypeRef) {}
84+
bool hasNonCovariantRef() const {
85+
const uint8_t notCovariant = ~TypePosition::Covariant;
86+
return (DirectRefs & notCovariant) || (DepMemberTyRefs & notCovariant);
87+
}
88+
89+
bool hasCovariantGenericParamResult() const {
90+
return HasCovariantGenericParamResult;
91+
}
92+
93+
GenericParameterReferenceInfo &
94+
operator|=(const GenericParameterReferenceInfo &other);
95+
96+
explicit operator bool() const {
97+
return hasDirectRef() || hasDependentMemberTypeRef();
98+
}
7199
};
72100

73101
/// Find references to the given generic parameter in the type signature of the
@@ -138,4 +166,4 @@ Type typeEraseOpenedArchetypesFromEnvironment(Type type,
138166

139167
} // end namespace swift
140168

141-
#endif
169+
#endif

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1168,7 +1168,7 @@ swift::matchWitness(WitnessChecker::RequirementEnvironmentCache &reqEnvCache,
11681168
// the default witness for 'Collection.Iterator', which is defined
11691169
// as 'IndexingIterator<Self>'.
11701170
const auto selfRefInfo = findExistentialSelfReferences(req);
1171-
if (!selfRefInfo.assocTypeRef) {
1171+
if (!selfRefInfo.hasDependentMemberTypeRef()) {
11721172
covariantSelf = classDecl;
11731173
}
11741174
}
@@ -4074,9 +4074,9 @@ void ConformanceChecker::checkNonFinalClassWitness(ValueDecl *requirement,
40744074
// prevent conformance from succeeding.
40754075
const auto selfRefInfo = findExistentialSelfReferences(requirement);
40764076

4077-
if (selfRefInfo.selfRef == TypePosition::Invariant ||
4078-
(selfRefInfo.selfRef == TypePosition::Covariant &&
4079-
!selfRefInfo.hasCovariantSelfResult)) {
4077+
if (selfRefInfo.hasDirectRef(TypePosition::Invariant) ||
4078+
(selfRefInfo.hasDirectRef(TypePosition::Covariant) &&
4079+
!selfRefInfo.hasCovariantGenericParamResult())) {
40804080
// References to Self in a position where subclasses cannot do
40814081
// the right thing. Complain if the adoptee is a non-final
40824082
// class.
@@ -4090,7 +4090,7 @@ void ConformanceChecker::checkNonFinalClassWitness(ValueDecl *requirement,
40904090
conformance->getType());
40914091
emitDeclaredHereIfNeeded(diags, diagLoc, witness);
40924092
});
4093-
} else if (selfRefInfo.hasCovariantSelfResult) {
4093+
} else if (selfRefInfo.hasCovariantGenericParamResult()) {
40944094
// The reference to Self occurs in the result type of a method/subscript
40954095
// or the type of a property. A non-final class can satisfy this requirement
40964096
// by holding onto Self accordingly.
@@ -4156,7 +4156,8 @@ void ConformanceChecker::checkNonFinalClassWitness(ValueDecl *requirement,
41564156
// associated types.
41574157
if (isa<FuncDecl>(witness) || isa<SubscriptDecl>(witness)) {
41584158
if (witness->getDeclContext()->getExtendedProtocolDecl()) {
4159-
if (selfRefInfo.hasCovariantSelfResult && selfRefInfo.assocTypeRef) {
4159+
if (selfRefInfo.hasCovariantGenericParamResult() &&
4160+
selfRefInfo.hasDependentMemberTypeRef()) {
41604161
getASTContext().addDelayedConformanceDiag(Conformance, false,
41614162
[witness, requirement](NormalProtocolConformance *conformance) {
41624163
auto proto = conformance->getProtocol();

lib/Sema/TypeOfReference.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2646,4 +2646,4 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator,
26462646
if (choice.isFallbackMemberOnUnwrappedBase()) {
26472647
increaseScore(SK_UnresolvedMemberViaOptional, locator);
26482648
}
2649-
}
2649+
}

0 commit comments

Comments
 (0)