Skip to content

Commit 09d540a

Browse files
committed
Look Through Class-Bound Archetypes When Installing Semantic Members
Before lookup was requestified, the entire lookup stack would install semantic members. As this caused cycles in the lookup path, it was refactored to instead only occur at the TypeChecker::lookup* entrypoints. Unfortunately, these entrypoints were not kept in sync with the stack building code in qualified lookup, so a case was missed: class-bound archetypes. We need to synthesize semantic members for them as well or we'll non-deterministically fail to find synthesizable members in incremental mode. rdar://74174749
1 parent e148032 commit 09d540a

File tree

4 files changed

+43
-6
lines changed

4 files changed

+43
-6
lines changed

include/swift/AST/Decl.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3202,6 +3202,17 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
32023202
/// declaration, or \c nullptr if it doesn't have one.
32033203
ConstructorDecl *getDefaultInitializer() const;
32043204

3205+
/// Force the synthesis of all members named \c member requiring semantic
3206+
/// analysis and install them in the member list of this nominal type.
3207+
///
3208+
/// \Note The use of this method in the compiler signals an architectural
3209+
/// problem with the caller. Use \c TypeChecker::lookup* instead of
3210+
/// introducing new usages.
3211+
///
3212+
/// FIXME: This method presents a problem with respect to the consistency
3213+
/// and idempotency of lookups in the compiler. If we instead had a model
3214+
/// where lookup requests would explicitly return semantic members or parsed
3215+
/// members this function could disappear.
32053216
void synthesizeSemanticMembersIfNeeded(DeclName member);
32063217

32073218
/// Retrieves the static 'shared' property of a global actor type, which

lib/Sema/TypeCheckNameLookup.cpp

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,25 @@ LookupResult TypeChecker::lookupUnqualified(DeclContext *dc, DeclNameRef name,
273273
return result;
274274
}
275275

276+
// An unfortunate hack to kick the decl checker into adding semantic members to
277+
// the current type before we attempt a semantic lookup. The places this method
278+
// looks needs to be in sync with \c extractDirectlyReferencedNominalTypes.
279+
// See the note in \c synthesizeSemanticMembersIfNeeded about a better, more
280+
// just, and peaceful world.
281+
static void installSemanticMembersIfNeeded(Type type, DeclNameRef name) {
282+
// Look-through class-bound archetypes to ensure we synthesize e.g.
283+
// inherited constructors.
284+
if (auto archetypeTy = type->getAs<ArchetypeType>()) {
285+
if (auto super = archetypeTy->getSuperclass()) {
286+
type = super;
287+
}
288+
}
289+
290+
if (auto *current = type->getAnyNominal()) {
291+
current->synthesizeSemanticMembersIfNeeded(name.getFullName());
292+
}
293+
}
294+
276295
LookupResult
277296
TypeChecker::lookupUnqualifiedType(DeclContext *dc, DeclNameRef name,
278297
SourceLoc loc,
@@ -320,9 +339,7 @@ LookupResult TypeChecker::lookupMember(DeclContext *dc,
320339
subOptions &= ~NL_RemoveNonVisible;
321340

322341
// Make sure we've resolved implicit members, if we need them.
323-
if (auto *current = type->getAnyNominal()) {
324-
current->synthesizeSemanticMembersIfNeeded(name.getFullName());
325-
}
342+
installSemanticMembersIfNeeded(type, name);
326343

327344
LookupResultBuilder builder(result, dc, options);
328345
SmallVector<ValueDecl *, 4> lookupResults;
@@ -392,9 +409,7 @@ LookupTypeResult TypeChecker::lookupMemberType(DeclContext *dc,
392409
subOptions |= NL_IncludeUsableFromInline;
393410

394411
// Make sure we've resolved implicit members, if we need them.
395-
if (auto *current = type->getAnyNominal()) {
396-
current->synthesizeSemanticMembersIfNeeded(name.getFullName());
397-
}
412+
installSemanticMembersIfNeeded(type, name);
398413

399414
if (!dc->lookupQualified(type, name, subOptions, decls))
400415
return result;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
class A {
2+
required init(_ x: Int) {}
3+
}
4+
5+
class B : A { }
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// RUN: %target-swift-frontend -typecheck -verify -primary-file %s %S/Inputs/inherited-init-multifile-other.swift
2+
// RUN: %target-swift-frontend -typecheck -verify %s -primary-file %S/Inputs/inherited-init-multifile-other.swift
3+
4+
func make<Result: B>(ofClass cls: Result.Type) -> Result {
5+
return cls.init(1)
6+
}

0 commit comments

Comments
 (0)