Skip to content

Commit 05f418a

Browse files
committed
Remove CodableConformanceType
This complexity is due to the implementation constraints of Codable synthesis at a time when the type checker could return partially-validated results. This is no longer the case, so all of this code is just technical debt.
1 parent c077455 commit 05f418a

File tree

1 file changed

+31
-119
lines changed

1 file changed

+31
-119
lines changed

lib/Sema/DerivedConformanceCodable.cpp

Lines changed: 31 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -61,59 +61,6 @@ static bool superclassIsDecodable(ClassDecl *target) {
6161
C.getProtocol(KnownProtocolKind::Decodable));
6262
}
6363

64-
/// Represents the possible outcomes of checking whether a decl conforms to
65-
/// Encodable or Decodable.
66-
enum CodableConformanceType {
67-
TypeNotValidated,
68-
DoesNotConform,
69-
Conforms
70-
};
71-
72-
/// Returns whether the given type conforms to the given {En,De}codable
73-
/// protocol.
74-
///
75-
/// \param context The \c DeclContext the var declarations belong to.
76-
///
77-
/// \param target The \c Type to validate.
78-
///
79-
/// \param proto The \c ProtocolDecl to check conformance to.
80-
static CodableConformanceType typeConformsToCodable(DeclContext *context,
81-
Type target, bool isIUO,
82-
ProtocolDecl *proto) {
83-
target = context->mapTypeIntoContext(target);
84-
85-
if (isIUO)
86-
target = target->lookThroughSingleOptionalType();
87-
88-
auto conf = TypeChecker::conformsToProtocol(target, proto, context);
89-
return conf.isInvalid() ? DoesNotConform : Conforms;
90-
}
91-
92-
/// Returns whether the given variable conforms to the given {En,De}codable
93-
/// protocol.
94-
///
95-
/// \param DC The \c DeclContext in which to check conformance.
96-
///
97-
/// \param varDecl The \c VarDecl to validate.
98-
///
99-
/// \param proto The \c ProtocolDecl to check conformance to.
100-
static CodableConformanceType
101-
varConformsToCodable(DeclContext *DC, VarDecl *varDecl, ProtocolDecl *proto) {
102-
// If the decl doesn't yet have a type, we may be seeing it before the type
103-
// checker has gotten around to evaluating its type. For example:
104-
//
105-
// func foo() {
106-
// let b = Bar(from: decoder) // <- evaluates Bar conformance to Codable,
107-
// // forcing derivation
108-
// }
109-
//
110-
// struct Bar : Codable {
111-
// var x: Int // <- we get to valuate x's var decl here, but its type
112-
// // hasn't yet been evaluated
113-
// }
114-
bool isIUO = varDecl->isImplicitlyUnwrappedOptional();
115-
return typeConformsToCodable(DC, varDecl->getValueInterfaceType(), isIUO,
116-
proto);
11764
}
11865

11966
/// Retrieve the variable name for the purposes of encoding/decoding.
@@ -164,34 +111,20 @@ static bool validateCodingKeysEnum(DerivedConformance &derived,
164111
}
165112

166113
// We have a property to map to. Ensure it's {En,De}codable.
167-
auto conformance =
168-
varConformsToCodable(conformanceDC, it->second, derived.Protocol);
169-
switch (conformance) {
170-
case Conforms:
171-
// The property was valid. Remove it from the list.
172-
properties.erase(it);
173-
break;
174-
175-
case DoesNotConform: {
176-
// We use a TypeLoc here so diagnostics can show the type
177-
// as written by the user in source if possible. This is useful
178-
// when the user has written an IUO type for example, since
179-
// diagnostics would show the type as 'T?' instead of 'T!' if
180-
// we use a Type instead.
181-
TypeLoc typeLoc = {
182-
it->second->getTypeReprOrParentPatternTypeRepr(),
183-
it->second->getType(),
184-
};
185-
it->second->diagnose(diag::codable_non_conforming_property_here,
186-
derived.getProtocolType(), typeLoc);
187-
LLVM_FALLTHROUGH;
188-
}
189-
190-
case TypeNotValidated:
191-
// We don't produce a diagnostic for a type which failed to validate.
192-
// This will produce a diagnostic elsewhere anyway.
193-
propertiesAreValid = false;
194-
continue;
114+
auto target =
115+
conformanceDC->mapTypeIntoContext(it->second->getValueInterfaceType());
116+
if (TypeChecker::conformsToProtocol(target, derived.Protocol, conformanceDC)
117+
.isInvalid()) {
118+
TypeLoc typeLoc = {
119+
it->second->getTypeReprOrParentPatternTypeRepr(),
120+
it->second->getType(),
121+
};
122+
it->second->diagnose(diag::codable_non_conforming_property_here,
123+
derived.getProtocolType(), typeLoc);
124+
propertiesAreValid = false;
125+
} else {
126+
// The property was valid. Remove it from the list.
127+
properties.erase(it);
195128
}
196129
}
197130

@@ -344,44 +277,23 @@ static EnumDecl *synthesizeCodingKeysEnum(DerivedConformance &derived) {
344277
if (!varDecl->isUserAccessible())
345278
continue;
346279

347-
// Despite creating the enum in the context of the type, we're
348-
// concurrently checking the variables for the current protocol
349-
// conformance being synthesized, for which we use the conformance
350-
// context, not the type.
351-
auto conformance = varConformsToCodable(derived.getConformanceContext(),
352-
varDecl, derived.Protocol);
353-
switch (conformance) {
354-
case Conforms:
355-
{
356-
auto *elt = new (C) EnumElementDecl(SourceLoc(),
357-
getVarNameForCoding(varDecl),
358-
nullptr, SourceLoc(), nullptr,
359-
enumDecl);
360-
elt->setImplicit();
361-
enumDecl->addMember(elt);
362-
break;
363-
}
364-
365-
case DoesNotConform: {
366-
// We use a TypeLoc here so diagnostics can show the type
367-
// as written by the user in source if possible. This is useful
368-
// when the user has written an IUO type for example, since
369-
// diagnostics would show the type as 'T?' instead of 'T!' if
370-
// we use a Type instead.
371-
TypeLoc typeLoc = {
372-
varDecl->getTypeReprOrParentPatternTypeRepr(),
373-
varDecl->getType(),
374-
};
375-
varDecl->diagnose(diag::codable_non_conforming_property_here,
376-
derived.getProtocolType(), typeLoc);
377-
LLVM_FALLTHROUGH;
378-
}
379-
380-
case TypeNotValidated:
381-
// We don't produce a diagnostic for a type which failed to validate.
382-
// This will produce a diagnostic elsewhere anyway.
383-
allConform = false;
384-
continue;
280+
auto target =
281+
conformanceDC->mapTypeIntoContext(varDecl->getValueInterfaceType());
282+
if (TypeChecker::conformsToProtocol(target, derived.Protocol, conformanceDC)
283+
.isInvalid()) {
284+
TypeLoc typeLoc = {
285+
varDecl->getTypeReprOrParentPatternTypeRepr(),
286+
varDecl->getType(),
287+
};
288+
varDecl->diagnose(diag::codable_non_conforming_property_here,
289+
derived.getProtocolType(), typeLoc);
290+
allConform = false;
291+
} else {
292+
auto *elt =
293+
new (C) EnumElementDecl(SourceLoc(), getVarNameForCoding(varDecl),
294+
nullptr, SourceLoc(), nullptr, enumDecl);
295+
elt->setImplicit();
296+
enumDecl->addMember(elt);
385297
}
386298
}
387299

0 commit comments

Comments
 (0)