@@ -1552,13 +1552,14 @@ deriveBodyDecodable_enum_init(AbstractFunctionDecl *initDecl, void *) {
15521552 //
15531553 // @derived init(from decoder: Decoder) throws {
15541554 // let container = try decoder.container(keyedBy: CodingKeys.self)
1555- // if container.allKeys.count != 1 {
1555+ // var allKeys = ArraySlice(container.allKeys)
1556+ // guard let onlyKey = allKeys.popFirst(), allKeys.isEmpty else {
15561557 // let context = DecodingError.Context(
15571558 // codingPath: container.codingPath,
15581559 // debugDescription: "Invalid number of keys found, expected one.")
15591560 // throw DecodingError.typeMismatch(Foo.self, context)
15601561 // }
1561- // switch container.allKeys.first {
1562+ // switch onlyKey {
15621563 // case .bar:
15631564 // let nestedContainer = try container.nestedContainer(
15641565 // keyedBy: BarCodingKeys.self, forKey: .bar)
@@ -1597,15 +1598,67 @@ deriveBodyDecodable_enum_init(AbstractFunctionDecl *initDecl, void *) {
15971598 initDecl->getParameters ()->get (0 ), codingKeysEnum, statements,
15981599 /* throws*/ true );
15991600
1601+ // generate: var allKeys = ArraySlice(container.allKeys);
1602+ auto *allKeysDecl =
1603+ new (C) VarDecl (/* IsStatic=*/ false , VarDecl::Introducer::Var,
1604+ SourceLoc (), C.Id_allKeys , funcDC);
1605+ allKeysDecl->setImplicit ();
1606+ allKeysDecl->setSynthesized ();
1607+ {
1608+ auto *arraySliceRef =
1609+ new (C) DeclRefExpr (ConcreteDeclRef (C.getArraySliceDecl ()),
1610+ DeclNameLoc (), /* Implicit=*/ true );
1611+ auto *containerAllKeys =
1612+ UnresolvedDotExpr::createImplicit (C, containerExpr, C.Id_allKeys );
1613+ auto *argList = ArgumentList::createImplicit (
1614+ C, {Argument::unlabeled (containerAllKeys)});
1615+ auto *init = CallExpr::createImplicit (C, arraySliceRef, argList);
1616+
1617+ auto *allKeysPattern = NamedPattern::createImplicit (C, allKeysDecl);
1618+ auto *allKeysBindingDecl = PatternBindingDecl::createImplicit (
1619+ C, StaticSpellingKind::None, allKeysPattern, init, funcDC);
1620+
1621+ statements.push_back (allKeysBindingDecl);
1622+ statements.push_back (allKeysDecl);
1623+ }
1624+
16001625 // generate:
1601- //
1602- // if container.allKeys.count != 1 {
1626+ // guard let onlyKey = allKeys.popFirst(), allKeys.isEmpty else {
16031627 // let context = DecodingError.Context(
16041628 // codingPath: container.codingPath,
16051629 // debugDescription: "Invalid number of keys found, expected
16061630 // one.")
16071631 // throw DecodingError.typeMismatch(Foo.self, context)
16081632 // }
1633+ auto *theKeyDecl =
1634+ new (C) VarDecl (/* IsStatic=*/ false , VarDecl::Introducer::Let,
1635+ SourceLoc (), C.getIdentifier (" onlyKey" ), funcDC);
1636+ theKeyDecl->setImplicit ();
1637+ theKeyDecl->setSynthesized ();
1638+
1639+ SmallVector<StmtConditionElement, 2 > guardElements;
1640+ {
1641+ auto *allKeysExpr =
1642+ new (C) DeclRefExpr (ConcreteDeclRef (allKeysDecl), DeclNameLoc (),
1643+ /* Implicit=*/ true );
1644+
1645+ // generate: let onlyKey = allKeys.popFirst;
1646+ auto *allKeysPopFisrtCallExpr = CallExpr::createImplicitEmpty (
1647+ C, UnresolvedDotExpr::createImplicit (C, allKeysExpr, C.Id_popFirst ));
1648+
1649+ auto *theKeyPattern = BindingPattern::createImplicit (
1650+ C, /* isLet=*/ true , NamedPattern::createImplicit (C, theKeyDecl));
1651+
1652+ guardElements.emplace_back (SourceLoc (), theKeyPattern,
1653+ allKeysPopFisrtCallExpr);
1654+
1655+ // generate: allKeys.isEmpty;
1656+ auto *allKeysIsEmptyExpr =
1657+ UnresolvedDotExpr::createImplicit (C, allKeysExpr, C.Id_isEmpty );
1658+
1659+ guardElements.emplace_back (allKeysIsEmptyExpr);
1660+ }
1661+
16091662 auto *targetType = TypeExpr::createImplicit (
16101663 funcDC->mapTypeIntoContext (targetEnum->getDeclaredInterfaceType ()), C);
16111664 auto *targetTypeExpr =
@@ -1615,44 +1668,21 @@ deriveBodyDecodable_enum_init(AbstractFunctionDecl *initDecl, void *) {
16151668 C, containerExpr, C.getDecodingErrorDecl (), C.Id_typeMismatch ,
16161669 targetTypeExpr, " Invalid number of keys found, expected one." );
16171670
1618- // container.allKeys
1619- auto *allKeysExpr =
1620- UnresolvedDotExpr::createImplicit (C, containerExpr, C.Id_allKeys );
1621-
1622- // container.allKeys.count
1623- auto *keysCountExpr =
1624- UnresolvedDotExpr::createImplicit (C, allKeysExpr, C.Id_count );
1625-
1626- // container.allKeys.count == 1
1627- auto *cmpFunc = C.getEqualIntDecl ();
1628- auto *fnType = cmpFunc->getInterfaceType ()->castTo <FunctionType>();
1629- auto *cmpFuncExpr = new (C)
1630- DeclRefExpr (cmpFunc, DeclNameLoc (),
1631- /* implicit*/ true , AccessSemantics::Ordinary, fnType);
1632- auto *oneExpr = IntegerLiteralExpr::createFromUnsigned (C, 1 );
1633-
1634- auto *cmpExpr = BinaryExpr::create (C, keysCountExpr, cmpFuncExpr, oneExpr,
1635- /* implicit*/ true );
1636- cmpExpr->setThrows (false );
1637-
16381671 auto *guardBody = BraceStmt::create (C, SourceLoc (), {throwStmt},
16391672 SourceLoc (), /* Implicit */ true );
16401673
1641- auto *guardStmt = new (C)
1642- GuardStmt (SourceLoc (), cmpExpr, guardBody, /* Implicit */ true , C);
1674+ auto *guardStmt =
1675+ new (C) GuardStmt (SourceLoc (), C.AllocateCopy (guardElements), guardBody,
1676+ /* Implicit */ true );
16431677
16441678 statements.push_back (guardStmt);
16451679
1646- // generate: switch container.allKeys.first { }
1647- auto *firstExpr =
1648- UnresolvedDotExpr::createImplicit (C, allKeysExpr, C.Id_first );
1649-
1650- // generate: switch container.allKeys.first.unsafelyUnwrapped { }
1651- auto *unwrapped =
1652- UnresolvedDotExpr::createImplicit (C, firstExpr, C.Id_unsafelyUnwrapped );
1680+ // generate: switch onlyKey { }
1681+ auto *theKeyExpr = new (C) DeclRefExpr (ConcreteDeclRef (theKeyDecl),
1682+ DeclNameLoc (), /* Implicit=*/ true );
16531683
16541684 auto switchStmt = createEnumSwitch (
1655- C, funcDC, unwrapped , targetEnum, codingKeysEnum,
1685+ C, funcDC, theKeyExpr , targetEnum, codingKeysEnum,
16561686 /* createSubpattern*/ false ,
16571687 [&](auto *elt, auto *codingKeyCase,
16581688 auto payloadVars) -> std::tuple<EnumElementDecl *, BraceStmt *> {
0 commit comments