Skip to content

Commit 43a3ab7

Browse files
authored
Merge pull request #28665 from CodaFi/the-phantom-menace
Explicitly State CodingKeys as a Codable Requirement
2 parents 4f39d9c + 3bda241 commit 43a3ab7

23 files changed

+221
-156
lines changed

include/swift/AST/Attr.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,12 @@ DECL_ATTR(derivative, Derivative,
534534
ABIStableToAdd | ABIBreakingToRemove | APIStableToAdd | APIBreakingToRemove,
535535
97)
536536

537+
DECL_ATTR(_implicitly_synthesizes_nested_requirement, ImplicitlySynthesizesNestedRequirement,
538+
OnProtocol |
539+
UserInaccessible |
540+
ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
541+
98)
542+
537543
#undef TYPE_ATTR
538544
#undef DECL_ATTR_ALIAS
539545
#undef CONTEXTUAL_DECL_ATTR_ALIAS

include/swift/AST/Attr.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,23 @@ class SwiftNativeObjCRuntimeBaseAttr : public DeclAttribute {
687687
}
688688
};
689689

690+
/// Defines the @_implicitly_synthesizes_nested_requirement attribute.
691+
class ImplicitlySynthesizesNestedRequirementAttr : public DeclAttribute {
692+
public:
693+
ImplicitlySynthesizesNestedRequirementAttr(StringRef Value, SourceLoc AtLoc,
694+
SourceRange Range)
695+
: DeclAttribute(DAK_ImplicitlySynthesizesNestedRequirement,
696+
AtLoc, Range, /*Implicit*/false),
697+
Value(Value) {}
698+
699+
/// The name of the phantom requirement.
700+
const StringRef Value;
701+
702+
static bool classof(const DeclAttribute *DA) {
703+
return DA->getKind() == DAK_ImplicitlySynthesizesNestedRequirement;
704+
}
705+
};
706+
690707
/// Determine the result of comparing an availability attribute to a specific
691708
/// platform or language version.
692709
enum class AvailableVersionComparison {

include/swift/AST/Decl.h

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -467,11 +467,15 @@ class alignas(1 << DeclAlignInBits) Decl {
467467
IsDebuggerAlias : 1
468468
);
469469

470-
SWIFT_INLINE_BITFIELD(NominalTypeDecl, GenericTypeDecl, 1+1+1,
470+
SWIFT_INLINE_BITFIELD(NominalTypeDecl, GenericTypeDecl, 1+1+1+1,
471471
/// Whether we have already added implicitly-defined initializers
472472
/// to this declaration.
473473
AddedImplicitInitializers : 1,
474474

475+
/// Whether we have already added the phantom CodingKeys
476+
/// nested requirement to this declaration.
477+
AddedPhantomCodingKeys : 1,
478+
475479
/// Whether there is are lazily-loaded conformances for this nominal type.
476480
HasLazyConformances : 1,
477481

@@ -3323,6 +3327,7 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
33233327
IterableDeclContext(IterableDeclContextKind::NominalTypeDecl)
33243328
{
33253329
Bits.NominalTypeDecl.AddedImplicitInitializers = false;
3330+
Bits.NominalTypeDecl.AddedPhantomCodingKeys = false;
33263331
ExtensionGeneration = 0;
33273332
Bits.NominalTypeDecl.HasLazyConformances = false;
33283333
Bits.NominalTypeDecl.IsComputingSemanticMembers = false;
@@ -3363,6 +3368,18 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
33633368
Bits.NominalTypeDecl.AddedImplicitInitializers = true;
33643369
}
33653370

3371+
/// Determine whether we have already attempted to add the
3372+
/// phantom CodingKeys type to this declaration.
3373+
bool addedPhantomCodingKeys() const {
3374+
return Bits.NominalTypeDecl.AddedPhantomCodingKeys;
3375+
}
3376+
3377+
/// Note that we have attempted to add the phantom CodingKeys type
3378+
/// to this declaration.
3379+
void setAddedPhantomCodingKeys() {
3380+
Bits.NominalTypeDecl.AddedPhantomCodingKeys = true;
3381+
}
3382+
33663383
/// getDeclaredType - Retrieve the type declared by this entity, without
33673384
/// any generic parameters bound if this is a generic type.
33683385
Type getDeclaredType() const;

include/swift/AST/PrintOptions.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,8 @@ struct PrintOptions {
296296
/// List of attribute kinds that should not be printed.
297297
std::vector<AnyAttrKind> ExcludeAttrList = {DAK_Transparent, DAK_Effects,
298298
DAK_FixedLayout,
299-
DAK_ShowInInterface};
299+
DAK_ShowInInterface,
300+
DAK_ImplicitlySynthesizesNestedRequirement};
300301

301302
/// List of attribute kinds that should be printed exclusively.
302303
/// Empty means allow all.

include/swift/AST/TypeCheckRequests.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1679,8 +1679,6 @@ class InheritsSuperclassInitializersRequest
16791679
enum class ImplicitMemberAction : uint8_t {
16801680
ResolveImplicitInit,
16811681
ResolveCodingKeys,
1682-
ResolveEncodable,
1683-
ResolveDecodable,
16841682
};
16851683

16861684
class ResolveImplicitMemberRequest

lib/AST/Attr.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -897,6 +897,11 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options,
897897
break;
898898
}
899899

900+
case DAK_ImplicitlySynthesizesNestedRequirement:
901+
Printer.printAttrName("@_implicitly_synthesizes_nested_requirement");
902+
Printer << "(\"" << cast<ImplicitlySynthesizesNestedRequirementAttr>(this)->Value << "\")";
903+
break;
904+
900905
case DAK_Count:
901906
llvm_unreachable("exceed declaration attribute kinds");
902907

@@ -958,6 +963,8 @@ StringRef DeclAttribute::getAttrName() const {
958963
return "_swift_native_objc_runtime_base";
959964
case DAK_Semantics:
960965
return "_semantics";
966+
case DAK_ImplicitlySynthesizesNestedRequirement:
967+
return "_implicitly_synthesizes_nested_requirement";
961968
case DAK_Available:
962969
return "availability";
963970
case DAK_ObjC:

lib/AST/Decl.cpp

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3995,19 +3995,6 @@ void NominalTypeDecl::synthesizeSemanticMembersIfNeeded(DeclName member) {
39953995
if (baseName.getIdentifier() == getASTContext().Id_CodingKeys) {
39963996
action.emplace(ImplicitMemberAction::ResolveCodingKeys);
39973997
}
3998-
} else {
3999-
auto argumentNames = member.getArgumentNames();
4000-
if (!member.isCompoundName() || argumentNames.size() == 1) {
4001-
if (baseName == DeclBaseName::createConstructor() &&
4002-
(member.isSimpleName() || argumentNames.front() == Context.Id_from)) {
4003-
action.emplace(ImplicitMemberAction::ResolveDecodable);
4004-
} else if (!baseName.isSpecial() &&
4005-
baseName.getIdentifier() == Context.Id_encode &&
4006-
(member.isSimpleName() ||
4007-
argumentNames.front() == Context.Id_to)) {
4008-
action.emplace(ImplicitMemberAction::ResolveEncodable);
4009-
}
4010-
}
40113998
}
40123999

40134000
if (auto actionToTake = action) {

lib/AST/TypeCheckRequests.cpp

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1074,12 +1074,6 @@ void swift::simple_display(llvm::raw_ostream &out,
10741074
case ImplicitMemberAction::ResolveCodingKeys:
10751075
out << "resolve CodingKeys";
10761076
break;
1077-
case ImplicitMemberAction::ResolveEncodable:
1078-
out << "resolve Encodable.encode(to:)";
1079-
break;
1080-
case ImplicitMemberAction::ResolveDecodable:
1081-
out << "resolve Decodable.init(from:)";
1082-
break;
10831077
}
10841078
}
10851079

lib/Parse/ParseDecl.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1736,6 +1736,43 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
17361736
}
17371737
break;
17381738
}
1739+
1740+
case DAK_ImplicitlySynthesizesNestedRequirement: {
1741+
if (!consumeIf(tok::l_paren)) {
1742+
diagnose(Loc, diag::attr_expected_lparen, AttrName,
1743+
DeclAttribute::isDeclModifier(DK));
1744+
return false;
1745+
}
1746+
1747+
if (Tok.isNot(tok::string_literal)) {
1748+
diagnose(Loc, diag::attr_expected_string_literal, AttrName);
1749+
return false;
1750+
}
1751+
1752+
auto Value = getStringLiteralIfNotInterpolated(
1753+
Loc, ("'" + AttrName + "'").str());
1754+
1755+
consumeToken(tok::string_literal);
1756+
1757+
if (Value.hasValue())
1758+
AttrRange = SourceRange(Loc, Tok.getRange().getStart());
1759+
else
1760+
DiscardAttribute = true;
1761+
1762+
if (!consumeIf(tok::r_paren)) {
1763+
diagnose(Loc, diag::attr_expected_rparen, AttrName,
1764+
DeclAttribute::isDeclModifier(DK));
1765+
return false;
1766+
}
1767+
1768+
if (!DiscardAttribute) {
1769+
Attributes.add(new (Context)
1770+
ImplicitlySynthesizesNestedRequirementAttr(Value.getValue(), AtLoc,
1771+
AttrRange));
1772+
}
1773+
break;
1774+
}
1775+
17391776
case DAK_Available: {
17401777
if (!consumeIf(tok::l_paren)) {
17411778
diagnose(Loc, diag::attr_expected_lparen, AttrName,

lib/Sema/CodeSynthesis.cpp

Lines changed: 4 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1070,11 +1070,8 @@ ResolveImplicitMemberRequest::evaluate(Evaluator &evaluator,
10701070
// FIXME: This entire request is a layering violation made of smaller,
10711071
// finickier layering violations. See rdar://56844567
10721072

1073-
// Checks whether the target conforms to the given protocol. If the
1074-
// conformance is incomplete, force the conformance.
1075-
//
1076-
// Returns whether the target conforms to the protocol.
1077-
auto evaluateTargetConformanceTo = [&](ProtocolDecl *protocol) {
1073+
auto &Context = target->getASTContext();
1074+
auto tryToInstallCodingKeys = [&](ProtocolDecl *protocol) {
10781075
if (!protocol)
10791076
return false;
10801077

@@ -1097,7 +1094,6 @@ ResolveImplicitMemberRequest::evaluate(Evaluator &evaluator,
10971094
return true;
10981095
};
10991096

1100-
auto &Context = target->getASTContext();
11011097
switch (action) {
11021098
case ImplicitMemberAction::ResolveImplicitInit:
11031099
TypeChecker::addImplicitConstructors(target);
@@ -1115,30 +1111,11 @@ ResolveImplicitMemberRequest::evaluate(Evaluator &evaluator,
11151111
// synthesized, it will be synthesized.
11161112
auto *decodableProto = Context.getProtocol(KnownProtocolKind::Decodable);
11171113
auto *encodableProto = Context.getProtocol(KnownProtocolKind::Encodable);
1118-
if (!evaluateTargetConformanceTo(decodableProto)) {
1119-
(void)evaluateTargetConformanceTo(encodableProto);
1114+
if (!tryToInstallCodingKeys(decodableProto)) {
1115+
(void)tryToInstallCodingKeys(encodableProto);
11201116
}
11211117
}
11221118
break;
1123-
case ImplicitMemberAction::ResolveEncodable: {
1124-
// encode(to:) may be synthesized as part of derived conformance to the
1125-
// Encodable protocol.
1126-
// If the target should conform to the Encodable protocol, check the
1127-
// conformance here to attempt synthesis.
1128-
auto *encodableProto = Context.getProtocol(KnownProtocolKind::Encodable);
1129-
(void)evaluateTargetConformanceTo(encodableProto);
1130-
}
1131-
break;
1132-
case ImplicitMemberAction::ResolveDecodable: {
1133-
// init(from:) may be synthesized as part of derived conformance to the
1134-
// Decodable protocol.
1135-
// If the target should conform to the Decodable protocol, check the
1136-
// conformance here to attempt synthesis.
1137-
TypeChecker::addImplicitConstructors(target);
1138-
auto *decodableProto = Context.getProtocol(KnownProtocolKind::Decodable);
1139-
(void)evaluateTargetConformanceTo(decodableProto);
1140-
}
1141-
break;
11421119
}
11431120
return true;
11441121
}

0 commit comments

Comments
 (0)