@@ -220,8 +220,26 @@ convertToUnqualifiedLookupOptions(NameLookupOptions options) {
220
220
LookupResult TypeChecker::lookupUnqualified (DeclContext *dc, DeclNameRef name,
221
221
SourceLoc loc,
222
222
NameLookupOptions options) {
223
- auto ulOptions = convertToUnqualifiedLookupOptions (options);
224
223
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);
225
243
auto descriptor = UnqualifiedLookupDescriptor (name, dc, loc, ulOptions);
226
244
auto lookup = evaluateOrDefault (ctx.evaluator ,
227
245
UnqualifiedLookupRequest{descriptor}, {});
0 commit comments