Skip to content

Commit 13cf37a

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 443e091 commit 13cf37a

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
@@ -220,8 +220,26 @@ convertToUnqualifiedLookupOptions(NameLookupOptions options) {
220220
LookupResult TypeChecker::lookupUnqualified(DeclContext *dc, DeclNameRef name,
221221
SourceLoc loc,
222222
NameLookupOptions options) {
223-
auto ulOptions = convertToUnqualifiedLookupOptions(options);
224223
auto &ctx = dc->getASTContext();
224+
// HACK: Qualified lookup cannot be allowed to synthesize CodingKeys because
225+
// it would lead to a number of egregious cycles through
226+
// QualifiedLookupRequest when we resolve the protocol conformance. Codable's
227+
// magic has pushed its way so deeply into the compiler, we have to
228+
// pessimistically force every nominal context above this one to synthesize
229+
// it in the event the user needs it from e.g. a non-primary input.
230+
// We can undo this if Codable's semantic content is divorced from its
231+
// syntactic content - so we synthesize just enough to allow lookups to
232+
// succeed, but don't force protocol conformances while we're doing it.
233+
if (name.getBaseIdentifier() == ctx.Id_CodingKeys) {
234+
for (auto typeCtx = dc->getInnermostTypeContext(); typeCtx != nullptr;
235+
typeCtx = typeCtx->getParent()->getInnermostTypeContext()) {
236+
if (auto *nominal = typeCtx->getSelfNominalTypeDecl()) {
237+
nominal->synthesizeSemanticMembersIfNeeded(name.getFullName());
238+
}
239+
}
240+
}
241+
242+
auto ulOptions = convertToUnqualifiedLookupOptions(options);
225243
auto descriptor = UnqualifiedLookupDescriptor(name, dc, loc, ulOptions);
226244
auto lookup = evaluateOrDefault(ctx.evaluator,
227245
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)