Skip to content

Commit d438bac

Browse files
committed
AST: Fix EnumDecl's hasPotentiallyUnavailableCaseValue() cache.
The cached values for `hasOnlyCasesWithoutAssociatedValues()` and `hasPotentiallyUnavailableCaseValue()` are computed in a single pass over the elements of an `EnumDecl`. However, the pass would return early after finding an element with an associated value, without checking whether any of the rest of the elements were potentially unavailable. This made `Comparable` synthesis succeed for any enum with potentially unavailable elements so long as the first element in the enum has an associated value.
1 parent 33eedc1 commit d438bac

File tree

2 files changed

+26
-12
lines changed

2 files changed

+26
-12
lines changed

lib/AST/Decl.cpp

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5968,25 +5968,29 @@ bool EnumDecl::hasOnlyCasesWithoutAssociatedValues() const {
59685968
case AssociatedValueCheck::HasAssociatedValues:
59695969
return false;
59705970
}
5971+
5972+
bool hasAnyUnavailableValues = false;
5973+
bool hasAssociatedValues = false;
5974+
59715975
for (auto elt : getAllElements()) {
59725976
for (auto Attr : elt->getAttrs()) {
59735977
if (auto AvAttr = dyn_cast<AvailableAttr>(Attr)) {
5974-
if (!AvAttr->isInvalid()) {
5975-
const_cast<EnumDecl*>(this)->Bits.EnumDecl.HasAnyUnavailableValues
5976-
= true;
5977-
}
5978+
if (!AvAttr->isInvalid())
5979+
hasAnyUnavailableValues = true;
59785980
}
59795981
}
59805982

5981-
if (elt->hasAssociatedValues()) {
5982-
const_cast<EnumDecl*>(this)->Bits.EnumDecl.HasAssociatedValues
5983-
= static_cast<unsigned>(AssociatedValueCheck::HasAssociatedValues);
5984-
return false;
5985-
}
5983+
if (elt->hasAssociatedValues())
5984+
hasAssociatedValues = true;
59865985
}
5987-
const_cast<EnumDecl*>(this)->Bits.EnumDecl.HasAssociatedValues
5988-
= static_cast<unsigned>(AssociatedValueCheck::NoAssociatedValues);
5989-
return true;
5986+
5987+
EnumDecl *enumDecl = const_cast<EnumDecl *>(this);
5988+
5989+
enumDecl->Bits.EnumDecl.HasAnyUnavailableValues = hasAnyUnavailableValues;
5990+
enumDecl->Bits.EnumDecl.HasAssociatedValues = static_cast<unsigned>(
5991+
hasAssociatedValues ? AssociatedValueCheck::HasAssociatedValues
5992+
: AssociatedValueCheck::NoAssociatedValues);
5993+
return !hasAssociatedValues;
59905994
}
59915995

59925996
bool EnumDecl::isFormallyExhaustive(const DeclContext *useDC) const {

test/decl/protocol/special/comparable/comparable_unsupported.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,16 @@ enum EnumWithUnavailableCaseAndAssociatedValue: Comparable {
4646
case some(SomeComparable)
4747
}
4848

49+
enum EnumWithUnavailableCaseAndAssociatedValue2: Comparable {
50+
// expected-error@-1 {{type 'EnumWithUnavailableCaseAndAssociatedValue2' does not conform to protocol 'Comparable'}}
51+
enum SomeComparable: Comparable {}
52+
53+
case this(SomeComparable)
54+
55+
@available(*, unavailable)
56+
case that(SomeComparable)
57+
}
58+
4959
// Automatic synthesis of Comparable requires associated values to be Comparable as well.
5060

5161
enum NotComparableEnumTwo: Comparable {

0 commit comments

Comments
 (0)