@@ -232,8 +232,26 @@ convertToUnqualifiedLookupOptions(NameLookupOptions options) {
232
232
LookupResult TypeChecker::lookupUnqualified (DeclContext *dc, DeclNameRef name,
233
233
SourceLoc loc,
234
234
NameLookupOptions options) {
235
- auto ulOptions = convertToUnqualifiedLookupOptions (options);
236
235
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);
237
255
auto descriptor = UnqualifiedLookupDescriptor (name, dc, loc, ulOptions);
238
256
auto lookup = evaluateOrDefault (ctx.evaluator ,
239
257
UnqualifiedLookupRequest{descriptor}, {});
0 commit comments