Skip to content

Commit 53a38f9

Browse files
committed
Patch A Regression in Lookup for CodingKeys
Codable's magic previously relied on the subject of every qualified lookup in an unqualified lookup stack to force the synthesis of this member. This allowed users to reference CodingKeys transitively through a non-primary input without qualification. As part of the requestification of name lookup, this synthesis was moved out of the normal qualified lookup path and into the Type Checker's semantic lookup entrypoints in order to prevent wild cycles caused by protocol conformance resolution. In the process, we forget to restore the synthesis check at this entrypoint. To patch up the source break this caused, we need to walk the context stack again and force synthesis. Unfortunately, we're stuck with a hack like this until we bring Codable's implementation back out of the realm of magic once more. A future implementation of synthesizeSemanticMembersIfNeeded should aim to just craft the AST for CodingKeys, but not actually run any of the semantic checks until we check the conformance to CodingKey. rdar://65088901, SR-13137
1 parent ed51731 commit 53a38f9

File tree

3 files changed

+35
-1
lines changed

3 files changed

+35
-1
lines changed

lib/Sema/TypeCheckNameLookup.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,8 +232,26 @@ convertToUnqualifiedLookupOptions(NameLookupOptions options) {
232232
LookupResult TypeChecker::lookupUnqualified(DeclContext *dc, DeclNameRef name,
233233
SourceLoc loc,
234234
NameLookupOptions options) {
235-
auto ulOptions = convertToUnqualifiedLookupOptions(options);
236235
auto &ctx = dc->getASTContext();
236+
// HACK: Qualified lookup cannot be allowed to synthesize CodingKeys because
237+
// it would lead to a number of egregious cycles through
238+
// QualifiedLookupRequest when we resolve the protocol conformance. Codable's
239+
// magic has pushed its way so deeply into the compiler, we have to
240+
// pessimistically force every nominal context above this one to synthesize
241+
// it in the event the user needs it from e.g. a non-primary input.
242+
// We can undo this if Codable's semantic content is divorced from its
243+
// syntactic content - so we synthesize just enough to allow lookups to
244+
// succeed, but don't force protocol conformances while we're doing it.
245+
if (name.getBaseIdentifier() == ctx.Id_CodingKeys) {
246+
for (auto typeCtx = dc->getInnermostTypeContext(); typeCtx != nullptr;
247+
typeCtx = typeCtx->getParent()->getInnermostTypeContext()) {
248+
if (auto *nominal = typeCtx->getSelfNominalTypeDecl()) {
249+
nominal->synthesizeSemanticMembersIfNeeded(name.getFullName());
250+
}
251+
}
252+
}
253+
254+
auto ulOptions = convertToUnqualifiedLookupOptions(options);
237255
auto descriptor = UnqualifiedLookupDescriptor(name, dc, loc, ulOptions);
238256
auto lookup = evaluateOrDefault(ctx.evaluator,
239257
UnqualifiedLookupRequest{descriptor}, {});

test/decl/protocol/special/coding/Inputs/struct_codable_simple_multi1.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,11 @@ struct SimpleStruct : Codable {
2121
let _ = SimpleStruct.CodingKeys.z // expected-error {{type 'SimpleStruct.CodingKeys' has no member 'z'}}
2222
}
2323
}
24+
25+
// SR-13137 Ensure unqualified lookup installs CodingKeys regardless of the
26+
// order of primaries.
27+
struct A: Codable {
28+
var property: String
29+
static let propertyName = CodingKeys.property.stringValue
30+
}
31+

test/decl/protocol/special/coding/Inputs/struct_codable_simple_multi2.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,11 @@ func foo() {
88
// struct.
99
let _ = SimpleStruct.CodingKeys.self // expected-error {{'CodingKeys' is inaccessible due to 'private' protection level}}
1010
}
11+
12+
struct B {
13+
static let propertyName = A.propertyName
14+
15+
struct Nest {
16+
static let propertyName = A.propertyName
17+
}
18+
}

0 commit comments

Comments
 (0)