Skip to content

Commit 3e6eb8f

Browse files
author
Itai Ferber
committed
Derive encoding an empty container by default
struct X : Codable {} should generate an encode(to:) which encodes an empty keyed container, not an encode(to:) which does nothing
1 parent 53d82b1 commit 3e6eb8f

File tree

1 file changed

+64
-64
lines changed

1 file changed

+64
-64
lines changed

lib/Sema/DerivedConformanceCodable.cpp

Lines changed: 64 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -441,71 +441,71 @@ static void deriveBodyEncodable_encode(AbstractFunctionDecl *encodeDecl) {
441441
DeclNameLoc(), /*Implicit=*/true,
442442
AccessSemantics::DirectToStorage);
443443

444-
auto enumElements = codingKeysEnum->getAllElements();
445-
if (!enumElements.empty()) {
446-
// Need to generate
447-
// `let container = encoder.container(keyedBy: CodingKeys.self)`
448-
// `let container` (containerExpr) is generated above.
449-
450-
// encoder
451-
auto encoderParam = encodeDecl->getParameterList(1)->get(0);
452-
auto *encoderExpr = new (C) DeclRefExpr(ConcreteDeclRef(encoderParam),
453-
DeclNameLoc(), /*Implicit=*/true);
454-
455-
// Bound encoder.container(keyedBy: CodingKeys.self) call
456-
auto containerType = containerDecl->getInterfaceType();
457-
auto *callExpr = createContainerKeyedByCall(C, funcDC, encoderExpr,
458-
containerType, codingKeysEnum);
459-
460-
// Full `let container = encoder.container(keyedBy: CodingKeys.self)`
461-
// binding.
462-
auto *containerPattern = new (C) NamedPattern(containerDecl,
463-
/*implicit=*/true);
464-
auto *bindingDecl = PatternBindingDecl::create(C, SourceLoc(),
465-
StaticSpellingKind::None,
466-
SourceLoc(),
467-
containerPattern, callExpr,
468-
funcDC);
469-
statements.push_back(bindingDecl);
470-
statements.push_back(containerDecl);
471-
472-
// Now need to generate `try container.encode(x, forKey: .x)` for all
473-
// existing properties.
474-
for (auto *elt : enumElements) {
475-
// Only ill-formed code would produce multiple results for this lookup.
476-
// This would get diagnosed later anyway, so we're free to only look at
477-
// the first result here.
478-
auto matchingVars = typeDecl->lookupDirect(DeclName(elt->getName()));
479-
480-
// self.x
481-
auto *selfRef = createSelfDeclRef(encodeDecl);
482-
auto *varExpr = new (C) MemberRefExpr(selfRef, SourceLoc(),
483-
ConcreteDeclRef(matchingVars[0]),
484-
DeclNameLoc(), /*Implicit=*/true);
485-
486-
// CodingKeys.x
487-
auto *eltRef = new (C) DeclRefExpr(elt, DeclNameLoc(), /*implicit=*/true);
488-
auto *metaTyRef = TypeExpr::createImplicit(codingKeysType, C);
489-
auto *keyExpr = new (C) DotSyntaxCallExpr(eltRef, SourceLoc(), metaTyRef);
490-
491-
// encode(_:forKey:)
492-
SmallVector<Identifier, 2> argNames{Identifier(), C.Id_forKey};
493-
DeclName name(C, C.Id_encode, argNames);
494-
auto *encodeCall = new (C) UnresolvedDotExpr(containerExpr, SourceLoc(),
495-
name, DeclNameLoc(),
496-
/*Implicit=*/true);
497-
498-
// container.encode(self.x, forKey: CodingKeys.x)
499-
Expr *args[2] = {varExpr, keyExpr};
500-
auto *callExpr = CallExpr::createImplicit(C, encodeCall,
501-
C.AllocateCopy(args),
502-
C.AllocateCopy(argNames));
444+
// Need to generate
445+
// `let container = encoder.container(keyedBy: CodingKeys.self)`
446+
// This is unconditional because a type with no properties should encode as an
447+
// empty container.
448+
//
449+
// `let container` (containerExpr) is generated above.
450+
451+
// encoder
452+
auto encoderParam = encodeDecl->getParameterList(1)->get(0);
453+
auto *encoderExpr = new (C) DeclRefExpr(ConcreteDeclRef(encoderParam),
454+
DeclNameLoc(), /*Implicit=*/true);
455+
456+
// Bound encoder.container(keyedBy: CodingKeys.self) call
457+
auto containerType = containerDecl->getInterfaceType();
458+
auto *callExpr = createContainerKeyedByCall(C, funcDC, encoderExpr,
459+
containerType, codingKeysEnum);
460+
461+
// Full `let container = encoder.container(keyedBy: CodingKeys.self)`
462+
// binding.
463+
auto *containerPattern = new (C) NamedPattern(containerDecl,
464+
/*implicit=*/true);
465+
auto *bindingDecl = PatternBindingDecl::create(C, SourceLoc(),
466+
StaticSpellingKind::None,
467+
SourceLoc(),
468+
containerPattern, callExpr,
469+
funcDC);
470+
statements.push_back(bindingDecl);
471+
statements.push_back(containerDecl);
472+
473+
// Now need to generate `try container.encode(x, forKey: .x)` for all
474+
// existing properties.
475+
for (auto *elt : codingKeysEnum->getAllElements()) {
476+
// Only ill-formed code would produce multiple results for this lookup.
477+
// This would get diagnosed later anyway, so we're free to only look at
478+
// the first result here.
479+
auto matchingVars = typeDecl->lookupDirect(DeclName(elt->getName()));
480+
481+
// self.x
482+
auto *selfRef = createSelfDeclRef(encodeDecl);
483+
auto *varExpr = new (C) MemberRefExpr(selfRef, SourceLoc(),
484+
ConcreteDeclRef(matchingVars[0]),
485+
DeclNameLoc(), /*Implicit=*/true);
486+
487+
// CodingKeys.x
488+
auto *eltRef = new (C) DeclRefExpr(elt, DeclNameLoc(), /*implicit=*/true);
489+
auto *metaTyRef = TypeExpr::createImplicit(codingKeysType, C);
490+
auto *keyExpr = new (C) DotSyntaxCallExpr(eltRef, SourceLoc(), metaTyRef);
491+
492+
// encode(_:forKey:)
493+
SmallVector<Identifier, 2> argNames{Identifier(), C.Id_forKey};
494+
DeclName name(C, C.Id_encode, argNames);
495+
auto *encodeCall = new (C) UnresolvedDotExpr(containerExpr, SourceLoc(),
496+
name, DeclNameLoc(),
497+
/*Implicit=*/true);
498+
499+
// container.encode(self.x, forKey: CodingKeys.x)
500+
Expr *args[2] = {varExpr, keyExpr};
501+
auto *callExpr = CallExpr::createImplicit(C, encodeCall,
502+
C.AllocateCopy(args),
503+
C.AllocateCopy(argNames));
503504

504-
// try container.encode(self.x, forKey: CodingKeys.x)
505-
auto *tryExpr = new (C) TryExpr(SourceLoc(), callExpr, Type(),
506-
/*Implicit=*/true);
507-
statements.push_back(tryExpr);
508-
}
505+
// try container.encode(self.x, forKey: CodingKeys.x)
506+
auto *tryExpr = new (C) TryExpr(SourceLoc(), callExpr, Type(),
507+
/*Implicit=*/true);
508+
statements.push_back(tryExpr);
509509
}
510510

511511
// Classes which inherit from something Codable should encode super as well.

0 commit comments

Comments
 (0)