Skip to content

Commit ebdbe6e

Browse files
committed
Code to derive Codable was assuming any decl of the desired key would be a
VarDecl, now does the right thing in the presence of identically named other declarations (like nested types).
1 parent bb6f27d commit ebdbe6e

File tree

2 files changed

+15
-11
lines changed

2 files changed

+15
-11
lines changed

lib/Sema/DerivedConformanceCodable.cpp

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -598,15 +598,15 @@ static void deriveBodyEncodable_encode(AbstractFunctionDecl *encodeDecl) {
598598
// Now need to generate `try container.encode(x, forKey: .x)` for all
599599
// existing properties. Optional properties get `encodeIfPresent`.
600600
for (auto *elt : codingKeysEnum->getAllElements()) {
601-
// Only ill-formed code would produce multiple results for this lookup.
602-
// This would get diagnosed later anyway, so we're free to only look at
603-
// the first result here.
604-
auto matchingVars = targetDecl->lookupDirect(DeclName(elt->getName()));
601+
VarDecl *varDecl;
602+
for (auto decl : targetDecl->lookupDirect(DeclName(elt->getName())))
603+
if ((varDecl = dyn_cast<VarDecl>(decl)))
604+
break;
605605

606606
// self.x
607607
auto *selfRef = createSelfDeclRef(encodeDecl);
608608
auto *varExpr = new (C) MemberRefExpr(selfRef, SourceLoc(),
609-
ConcreteDeclRef(matchingVars[0]),
609+
ConcreteDeclRef(varDecl),
610610
DeclNameLoc(), /*Implicit=*/true);
611611

612612
// CodingKeys.x
@@ -616,7 +616,7 @@ static void deriveBodyEncodable_encode(AbstractFunctionDecl *encodeDecl) {
616616

617617
// encode(_:forKey:)/encodeIfPresent(_:forKey:)
618618
auto methodName = C.Id_encode;
619-
auto varType = cast<VarDecl>(matchingVars[0])->getType();
619+
auto varType = varDecl->getType();
620620
if (auto referenceType = varType->getAs<ReferenceStorageType>()) {
621621
// This is a weak/unowned/unmanaged var. Get the inner type before
622622
// checking optionality.
@@ -866,11 +866,10 @@ static void deriveBodyDecodable_init(AbstractFunctionDecl *initDecl) {
866866
// Now need to generate `x = try container.decode(Type.self, forKey: .x)`
867867
// for all existing properties. Optional properties get `decodeIfPresent`.
868868
for (auto *elt : enumElements) {
869-
// Only ill-formed code would produce multiple results for this lookup.
870-
// This would get diagnosed later anyway, so we're free to only look at
871-
// the first result here.
872-
auto matchingVars = targetDecl->lookupDirect(DeclName(elt->getName()));
873-
auto *varDecl = cast<VarDecl>(matchingVars[0]);
869+
VarDecl *varDecl;
870+
for (auto decl : targetDecl->lookupDirect(DeclName(elt->getName())))
871+
if ((varDecl = dyn_cast<VarDecl>(decl)))
872+
break;
874873

875874
// Don't output a decode statement for a var let with a default value.
876875
if (varDecl->isLet() && varDecl->getParentInitializer() != nullptr)

test/decl/protocol/special/coding/struct_codable_member_type_lookup.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,3 +649,8 @@ extension C.Inner {
649649
struct GenericCodableStruct<T : Codable> : Codable {}
650650

651651
func foo(_: GenericCodableStruct<Int>.CodingKeys) // expected-error {{'CodingKeys' is inaccessible due to 'private' protection level}}
652+
653+
struct sr6886 {
654+
struct Nested : Codable {}
655+
let Nested: Nested // Don't crash with a coding key that is the same as a nested type name
656+
}

0 commit comments

Comments
 (0)