diff --git a/lib/Sema/TypeCheckNameLookup.cpp b/lib/Sema/TypeCheckNameLookup.cpp index 7ba8ba3d4ac7f..5eb91532f8815 100644 --- a/lib/Sema/TypeCheckNameLookup.cpp +++ b/lib/Sema/TypeCheckNameLookup.cpp @@ -252,27 +252,36 @@ convertToUnqualifiedLookupOptions(NameLookupOptions options) { return newOptions; } +/// HACK: Qualified lookup cannot be allowed to synthesize CodingKeys because +/// it would lead to a number of egregious cycles through QualifiedLookupRequest +/// when we resolve the protocol conformance. Codable's magic has pushed its way +/// so deeply into the compiler, when doing unqualified lookup we have to +/// pessimistically force every nominal context above this one to synthesize it +/// in the event the user needs it from e.g. a non-primary input. +/// +/// We can undo this if Codable's semantic content is divorced from its +/// syntactic content - so we synthesize just enough to allow lookups to +/// succeed, but don't force protocol conformances while we're doing it. +static void synthesizeCodingKeysIfNeededForUnqualifiedLookup(ASTContext &ctx, + DeclContext *dc, + DeclNameRef name) { + if (name.getBaseIdentifier() != ctx.Id_CodingKeys) + return; + + for (auto typeCtx = dc->getInnermostTypeContext(); typeCtx != nullptr; + typeCtx = typeCtx->getParent()->getInnermostTypeContext()) { + if (auto *nominal = typeCtx->getSelfNominalTypeDecl()) + nominal->synthesizeSemanticMembersIfNeeded(name.getFullName()); + } +} + LookupResult TypeChecker::lookupUnqualified(DeclContext *dc, DeclNameRef name, SourceLoc loc, NameLookupOptions options) { auto &ctx = dc->getASTContext(); - // HACK: Qualified lookup cannot be allowed to synthesize CodingKeys because - // it would lead to a number of egregious cycles through - // QualifiedLookupRequest when we resolve the protocol conformance. Codable's - // magic has pushed its way so deeply into the compiler, we have to - // pessimistically force every nominal context above this one to synthesize - // it in the event the user needs it from e.g. a non-primary input. - // We can undo this if Codable's semantic content is divorced from its - // syntactic content - so we synthesize just enough to allow lookups to - // succeed, but don't force protocol conformances while we're doing it. - if (name.getBaseIdentifier() == ctx.Id_CodingKeys) { - for (auto typeCtx = dc->getInnermostTypeContext(); typeCtx != nullptr; - typeCtx = typeCtx->getParent()->getInnermostTypeContext()) { - if (auto *nominal = typeCtx->getSelfNominalTypeDecl()) { - nominal->synthesizeSemanticMembersIfNeeded(name.getFullName()); - } - } - } + + // HACK: Synthesize CodingKeys if needed. + synthesizeCodingKeysIfNeededForUnqualifiedLookup(ctx, dc, name); auto ulOptions = convertToUnqualifiedLookupOptions(options); auto descriptor = UnqualifiedLookupDescriptor(name, dc, loc, ulOptions); @@ -314,6 +323,10 @@ TypeChecker::lookupUnqualifiedType(DeclContext *dc, DeclNameRef name, SourceLoc loc, NameLookupOptions options) { auto &ctx = dc->getASTContext(); + + // HACK: Synthesize CodingKeys if needed. + synthesizeCodingKeysIfNeededForUnqualifiedLookup(ctx, dc, name); + auto ulOptions = convertToUnqualifiedLookupOptions(options) | UnqualifiedLookupFlags::TypeLookup; { diff --git a/test/IDE/complete_rdar146055457.swift b/test/IDE/complete_rdar146055457.swift new file mode 100644 index 0000000000000..c86a485e4da76 --- /dev/null +++ b/test/IDE/complete_rdar146055457.swift @@ -0,0 +1,14 @@ +// RUN: %batch-code-completion + +// rdar://146055457 - Make sure we synthesize CodingKeys + +struct S: Encodable { + var a: String + var b: String + + private var foo: CodingKeys { + .#^COMPLETE^# + // COMPLETE-DAG: Decl[EnumElement]/CurrNominal/Flair[ExprSpecific]/TypeRelation[Convertible]: a[#CodingKeys#]; name=a + // COMPLETE-DAG: Decl[EnumElement]/CurrNominal/Flair[ExprSpecific]/TypeRelation[Convertible]: b[#CodingKeys#]; name=b + } +}