Skip to content

Commit dd984b1

Browse files
Merge pull request #35860 from AnthonyLatsis/enum-witness-no-accessor-req
Sema: Fix enum case witness crash when the requirement does not specify accessors
2 parents 613116f + 35a829a commit dd984b1

File tree

4 files changed

+52
-6
lines changed

4 files changed

+52
-6
lines changed

lib/AST/Decl.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5673,6 +5673,11 @@ bool VarDecl::isSettable(const DeclContext *UseDC,
56735673
if (!isLet())
56745674
return supportsMutation();
56755675

5676+
// Static 'let's are always immutable.
5677+
if (isStatic()) {
5678+
return false;
5679+
}
5680+
56765681
//
56775682
// All the remaining logic handles the special cases where you can
56785683
// assign a 'let'.

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -648,17 +648,23 @@ swift::matchWitness(
648648
} else if (isa<ConstructorDecl>(witness)) {
649649
decomposeFunctionType = true;
650650
ignoreReturnType = true;
651-
} else if (isa<EnumElementDecl>(witness)) {
652-
auto enumCase = cast<EnumElementDecl>(witness);
651+
} else if (auto *enumCase = dyn_cast<EnumElementDecl>(witness)) {
652+
// An enum case with associated values can satisfy only a
653+
// method requirement.
653654
if (enumCase->hasAssociatedValues() && isa<VarDecl>(req))
654655
return RequirementMatch(witness, MatchKind::EnumCaseWithAssociatedValues);
655-
auto isValid = isa<VarDecl>(req) || isa<FuncDecl>(req);
656-
if (!isValid)
656+
657+
// An enum case can satisfy only a method or property requirement.
658+
if (!isa<VarDecl>(req) && !isa<FuncDecl>(req))
657659
return RequirementMatch(witness, MatchKind::KindConflict);
658-
if (!cast<ValueDecl>(req)->isStatic())
660+
661+
// An enum case can satisfy only a static requirement.
662+
if (!req->isStatic())
659663
return RequirementMatch(witness, MatchKind::StaticNonStaticConflict);
664+
665+
// An enum case cannot satisfy a settable property requirement.
660666
if (isa<VarDecl>(req) &&
661-
cast<VarDecl>(req)->getParsedAccessor(AccessorKind::Set))
667+
cast<VarDecl>(req)->isSettable(req->getDeclContext()))
662668
return RequirementMatch(witness, MatchKind::SettableConflict);
663669

664670
decomposeFunctionType = enumCase->hasAssociatedValues();

lib/Sema/TypeCheckStorage.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3252,6 +3252,27 @@ StorageImplInfoRequest::evaluate(Evaluator &evaluator,
32523252
}
32533253
}
32543254

3255+
// Handle protocol requirements specially.
3256+
if (isa<ProtocolDecl>(storage->getDeclContext())) {
3257+
ReadImplKind readImpl = ReadImplKind::Stored;
3258+
// By default, treat the requirement as not having a setter.
3259+
WriteImplKind writeImpl = WriteImplKind::Immutable;
3260+
ReadWriteImplKind readWriteImpl = ReadWriteImplKind::Immutable;
3261+
3262+
if (storage->getParsedAccessor(AccessorKind::Set)) {
3263+
readImpl = ReadImplKind::Get;
3264+
writeImpl = WriteImplKind::Set;
3265+
readWriteImpl = ReadWriteImplKind::MaterializeToTemporary;
3266+
} else if (storage->getParsedAccessor(AccessorKind::Get)) {
3267+
readImpl = ReadImplKind::Get;
3268+
}
3269+
3270+
StorageImplInfo info(readImpl, writeImpl, readWriteImpl);
3271+
finishStorageImplInfo(storage, info);
3272+
3273+
return info;
3274+
}
3275+
32553276
bool hasWillSet = storage->getParsedAccessor(AccessorKind::WillSet);
32563277
bool hasDidSet = storage->getParsedAccessor(AccessorKind::DidSet);
32573278
bool hasSetter = storage->getParsedAccessor(AccessorKind::Set);

test/decl/protocol/protocol_enum_witness.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,3 +139,17 @@ protocol ThrowingFactory {
139139
enum HorseFactory : ThrowingFactory {
140140
case horse(Int)
141141
}
142+
143+
protocol MissingAccessorsVar {
144+
static var bar: Self // expected-error {{property in protocol must have explicit { get } or { get set } specifier}}
145+
}
146+
enum Bar14: MissingAccessorsVar { // OK
147+
case bar
148+
}
149+
150+
protocol MissingAccessorsLet {
151+
static let bar: Self // expected-error {{protocols cannot require properties to be immutable; declare read-only properties by using 'var' with a '{ get }' specifier}}
152+
}
153+
enum Bar15: MissingAccessorsLet { // OK
154+
case bar
155+
}

0 commit comments

Comments
 (0)