Skip to content

Commit fdc535a

Browse files
committed
[ConstraintSystem] Don't include self-recursive dynamic member results as "inaccessible"
Solver has to keep track of excluded dynamic member results while performing lookup because otherwise, in diagnostic modem it might include such results as inaccessible. Resolves: rdar://problem/61084565
1 parent 963c7fc commit fdc535a

File tree

2 files changed

+28
-1
lines changed

2 files changed

+28
-1
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5812,6 +5812,15 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
58125812
}
58135813
}
58145814

5815+
// Exclude some of the dynamic member choices from results
5816+
// because using such choices would result in a self-recursive reference.
5817+
//
5818+
// This is required because if there are no viable/unviable choices
5819+
// `performMemberLookup` is going to attempt to lookup inaccessible
5820+
// members and results would include dynamic member subscripts which
5821+
// have already been excluded.
5822+
llvm::SmallPtrSet<ValueDecl *, 2> excludedDynamicMembers;
5823+
58155824
// Local function that adds the given declaration if it is a
58165825
// reasonable choice.
58175826
auto addChoice = [&](OverloadChoice candidate) {
@@ -5988,8 +5997,10 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
59885997
if (auto kpElt = memberLocator->getLastElementAs<KPDynamicMemberElt>()) {
59895998
auto *keyPath = kpElt->getKeyPathDecl();
59905999
if (isSelfRecursiveKeyPathDynamicMemberLookup(*this, baseTy,
5991-
memberLocator))
6000+
memberLocator)) {
6001+
excludedDynamicMembers.insert(candidate.getDecl());
59926002
return;
6003+
}
59936004

59946005
if (auto *storage = dyn_cast<AbstractStorageDecl>(decl)) {
59956006
// If this is an attempt to access read-only member via
@@ -6225,6 +6236,9 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
62256236
return result;
62266237
}
62276238

6239+
if (excludedDynamicMembers.count(cand))
6240+
continue;
6241+
62286242
result.addUnviable(getOverloadChoice(cand, /*isBridged=*/false,
62296243
/*isUnwrappedOptional=*/false),
62306244
MemberLookupResult::UR_Inaccessible);

test/Constraints/subscript.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,3 +203,16 @@ func test_generic_subscript_requirements_mismatch_diagnostics() {
203203

204204
s[number: ["hello"]] // expected-error {{subscript 'subscript(number:)' requires that 'String' conform to 'BinaryInteger'}}
205205
}
206+
207+
// rdar://61084565 - infinite recursion in dynamic member lookup
208+
func rdar61084565() {
209+
@dynamicMemberLookup
210+
struct Foo {
211+
subscript(dynamicMember _: KeyPath<Foo, Int>) -> Int {
212+
return 42
213+
}
214+
}
215+
216+
let a = Foo()
217+
a[] // expected-error {{value of type 'Foo' has no subscripts}}
218+
}

0 commit comments

Comments
 (0)