Skip to content

Commit 7475607

Browse files
authored
Merge pull request swiftlang#38037 from drexin/wip-fix-optional-enum-codable
[5.5][Sema] Use decodeIfPresent for optional enum params in Codable synthesis
2 parents 01d349c + 45dc6c9 commit 7475607

File tree

2 files changed

+48
-3
lines changed

2 files changed

+48
-3
lines changed

lib/Sema/DerivedConformanceCodable.cpp

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1674,8 +1674,16 @@ deriveBodyDecodable_enum_init(AbstractFunctionDecl *initDecl, void *) {
16741674
}
16751675

16761676
// Type.self
1677-
auto *parameterTypeExpr = TypeExpr::createImplicit(
1678-
funcDC->mapTypeIntoContext(paramDecl->getInterfaceType()), C);
1677+
auto varType = funcDC->mapTypeIntoContext(
1678+
paramDecl->getValueInterfaceType());
1679+
1680+
bool useIfPresentVariant = false;
1681+
if (auto objType = varType->getOptionalObjectType()) {
1682+
varType = objType;
1683+
useIfPresentVariant = true;
1684+
}
1685+
1686+
auto *parameterTypeExpr = TypeExpr::createImplicit(varType, C);
16791687
auto *parameterMetaTypeExpr =
16801688
new (C) DotSelfExpr(parameterTypeExpr, SourceLoc(), SourceLoc());
16811689
// BarCodingKeys.x
@@ -1688,9 +1696,12 @@ deriveBodyDecodable_enum_init(AbstractFunctionDecl *initDecl, void *) {
16881696
auto *nestedContainerExpr = new (C)
16891697
DeclRefExpr(ConcreteDeclRef(nestedContainerDecl), DeclNameLoc(),
16901698
/*Implicit=*/true, AccessSemantics::DirectToStorage);
1699+
16911700
// decode(_:, forKey:)
1701+
auto methodName = useIfPresentVariant ? C.Id_decodeIfPresent
1702+
: C.Id_decode;
16921703
auto *decodeCall = UnresolvedDotExpr::createImplicit(
1693-
C, nestedContainerExpr, C.Id_decode, {Identifier(), C.Id_forKey});
1704+
C, nestedContainerExpr, methodName, {Identifier(), C.Id_forKey});
16941705

16951706
// nestedContainer.decode(Type.self, forKey: BarCodingKeys.x)
16961707
auto *callExpr = CallExpr::createImplicit(

test/stdlib/CodableTests.swift

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,39 @@ class TestCodable : TestCodableSuper {
597597
}
598598
}
599599

600+
// MARK: - Optional
601+
func test_Optional_enum_JSON() {
602+
enum A: Codable, Equatable {
603+
case a(Int?)
604+
}
605+
606+
enum B: Codable, Equatable {
607+
case b(Int? = nil)
608+
}
609+
610+
enum C: Codable, Equatable {
611+
case c(x: Int?)
612+
}
613+
614+
enum D: Codable, Equatable {
615+
case d(x: Int? = nil)
616+
}
617+
618+
expectRoundTripEqualityThroughJSON(for: A.a(1), lineNumber: #line)
619+
expectRoundTripEqualityThroughJSON(for: A.a(nil), lineNumber: #line)
620+
621+
expectRoundTripEqualityThroughJSON(for: B.b(2), lineNumber: #line)
622+
expectRoundTripEqualityThroughJSON(for: B.b(nil), lineNumber: #line)
623+
expectRoundTripEqualityThroughJSON(for: B.b(), lineNumber: #line)
624+
625+
expectRoundTripEqualityThroughJSON(for: C.c(x: 3), lineNumber: #line)
626+
expectRoundTripEqualityThroughJSON(for: C.c(x: nil), lineNumber: #line)
627+
628+
expectRoundTripEqualityThroughJSON(for: D.d(x: 4), lineNumber: #line)
629+
expectRoundTripEqualityThroughJSON(for: D.d(x: nil), lineNumber: #line)
630+
expectRoundTripEqualityThroughJSON(for: D.d(), lineNumber: #line)
631+
}
632+
600633
// MARK: - PartialRangeFrom
601634
func test_PartialRangeFrom_JSON() {
602635
let value = 0...
@@ -899,6 +932,7 @@ var tests = [
899932
"test_Locale_Plist" : TestCodable.test_Locale_Plist,
900933
"test_NSRange_JSON" : TestCodable.test_NSRange_JSON,
901934
"test_NSRange_Plist" : TestCodable.test_NSRange_Plist,
935+
"test_Optional_enum_JSON" : TestCodable.test_Optional_enum_JSON,
902936
"test_PartialRangeFrom_JSON" : TestCodable.test_PartialRangeFrom_JSON,
903937
"test_PartialRangeFrom_Plist" : TestCodable.test_PartialRangeFrom_Plist,
904938
"test_PartialRangeThrough_JSON" : TestCodable.test_PartialRangeThrough_JSON,

0 commit comments

Comments
 (0)