Add Missing Definitions of canDerive{En,De}codable

This commit is contained in:
Robert Widmann
2021-02-19 16:03:32 -08:00
parent 55fd87900a
commit 6df3fcf3ad
3 changed files with 45 additions and 25 deletions

View File

@@ -1071,10 +1071,35 @@ static bool canSynthesize(DerivedConformance &derived, ValueDecl *requirement) {
LLVM_FALLTHROUGH; LLVM_FALLTHROUGH;
case CodingKeysClassification::Valid: case CodingKeysClassification::Valid:
return true; return true;
static bool canDeriveCodable(NominalTypeDecl *NTD,
KnownProtocolKind Kind) {
assert(Kind == KnownProtocolKind::Encodable ||
Kind == KnownProtocolKind::Decodable);
// Structs and classes can explicitly derive Encodable and Decodable
// conformance (explicitly meaning we can synthesize an implementation if
// a type conforms manually).
// FIXME: Enums too!
if (!isa<StructDecl>(NTD) && !isa<ClassDecl>(NTD)) {
return false;
} }
auto *PD = NTD->getASTContext().getProtocol(Kind);
if (!PD) {
return false;
}
return true; return true;
} }
bool DerivedConformance::canDeriveDecodable(NominalTypeDecl *NTD) {
return canDeriveCodable(NTD, KnownProtocolKind::Decodable);
}
bool DerivedConformance::canDeriveEncodable(NominalTypeDecl *NTD) {
return canDeriveCodable(NTD, KnownProtocolKind::Encodable);
}
ValueDecl *DerivedConformance::deriveEncodable(ValueDecl *requirement) { ValueDecl *DerivedConformance::deriveEncodable(ValueDecl *requirement) {
// We can only synthesize Encodable for structs and classes. // We can only synthesize Encodable for structs and classes.
if (!isa<StructDecl>(Nominal) && !isa<ClassDecl>(Nominal)) if (!isa<StructDecl>(Nominal) && !isa<ClassDecl>(Nominal))

View File

@@ -88,6 +88,14 @@ bool DerivedConformance::derivesProtocolConformance(DeclContext *DC,
if (*derivableKind == KnownDerivableProtocolKind::Differentiable) if (*derivableKind == KnownDerivableProtocolKind::Differentiable)
return true; return true;
if (*derivableKind == KnownDerivableProtocolKind::Encodable) {
return canDeriveEncodable(Nominal);
}
if (*derivableKind == KnownDerivableProtocolKind::Decodable) {
return canDeriveDecodable(Nominal);
}
if (auto *enumDecl = dyn_cast<EnumDecl>(Nominal)) { if (auto *enumDecl = dyn_cast<EnumDecl>(Nominal)) {
switch (*derivableKind) { switch (*derivableKind) {
// The presence of a raw type is an explicit declaration that // The presence of a raw type is an explicit declaration that
@@ -137,31 +145,13 @@ bool DerivedConformance::derivesProtocolConformance(DeclContext *DC,
default: default:
return false; return false;
} }
} else if (isa<StructDecl>(Nominal) || isa<ClassDecl>(Nominal)) { } else if (isa<StructDecl>(Nominal)) {
// Structs and classes can explicitly derive Encodable and Decodable switch (*derivableKind) {
// conformance (explicitly meaning we can synthesize an implementation if case KnownDerivableProtocolKind::Equatable:
// a type conforms manually). // Structs can explicitly derive Equatable conformance.
if (*derivableKind == KnownDerivableProtocolKind::Encodable || return canDeriveEquatable(DC, Nominal);
*derivableKind == KnownDerivableProtocolKind::Decodable) { default:
// FIXME: This is not actually correct. We cannot promise to always return false;
// provide a witness here for all structs and classes. Unfortunately,
// figuring out whether this is actually possible requires much more
// context -- a TypeChecker and the parent decl context at least -- and is
// tightly coupled to the logic within DerivedConformance.
// This unfortunately means that we expect a witness even if one will not
// be produced, which requires DerivedConformance::deriveCodable to output
// its own diagnostics.
return true;
}
// Structs can explicitly derive Equatable conformance.
if (isa<StructDecl>(Nominal)) {
switch (*derivableKind) {
case KnownDerivableProtocolKind::Equatable:
return canDeriveEquatable(DC, Nominal);
default:
return false;
}
} }
} }
return false; return false;

View File

@@ -278,6 +278,11 @@ public:
/// \returns the derived member, which will also be added to the type. /// \returns the derived member, which will also be added to the type.
ValueDecl *deriveBridgedNSError(ValueDecl *requirement); ValueDecl *deriveBridgedNSError(ValueDecl *requirement);
/// Determine if \c Encodable can be derived for the given type.
static bool canDeriveEncodable(NominalTypeDecl *NTD);
/// Determine if \c Decodable can be derived for the given type.
static bool canDeriveDecodable(NominalTypeDecl *NTD);
/// Derive a CodingKey requirement for an enum type. /// Derive a CodingKey requirement for an enum type.
/// ///
/// \returns the derived member, which will also be added to the type. /// \returns the derived member, which will also be added to the type.