Skip to content

Commit 2e8d163

Browse files
committed
[ConstraintSystem] Special case keypath dynamic member lookup in disjunction filtering
Since filtering currently runs as part of the `applicable function` constraint processing, "keypath dynamic member lookup" choice can't be attempted in-place because that would also try to operate on that constraint, so instead let's keep the disjunction, but disable all unviable choices. Resolves: rdar://problem/49533404
1 parent e3ad92f commit 2e8d163

File tree

2 files changed

+41
-6
lines changed

2 files changed

+41
-6
lines changed

lib/Sema/CSSolver.cpp

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1348,12 +1348,26 @@ ConstraintSystem::filterDisjunction(
13481348

13491349
// This can only happen when subscript syntax is used to lookup
13501350
// something which doesn't exist in type marked with
1351-
// `@dynamicMemberLookup`. Early simplification of the key path
1352-
// dynamic member lookup choice is impossible because it requires
1353-
// constraints associated with subscript index expression to be present.
1354-
if (!solverState && choice->getOverloadChoice().getKind() ==
1355-
OverloadChoiceKind::KeyPathDynamicMemberLookup)
1356-
return SolutionKind::Unsolved;
1351+
// `@dynamicMemberLookup`.
1352+
// Since filtering currently runs as part of the `applicable function`
1353+
// constraint processing, "keypath dynamic member lookup" choice can't
1354+
// be attempted in-place because that would also try to operate on that
1355+
// constraint, so instead let's keep the disjunction, but disable all
1356+
// unviable choices.
1357+
if (choice->getOverloadChoice().getKind() ==
1358+
OverloadChoiceKind::KeyPathDynamicMemberLookup) {
1359+
// Early simplification of the "keypath dynamic member lookup" choice
1360+
// is impossible because it requires constraints associated with
1361+
// subscript index expression to be present.
1362+
if (!solverState)
1363+
return SolutionKind::Unsolved;
1364+
1365+
for (auto *currentChoice : disjunction->getNestedConstraints()) {
1366+
if (currentChoice != choice)
1367+
solverState->disableContraint(currentChoice);
1368+
}
1369+
return SolutionKind::Solved;
1370+
}
13571371

13581372
// Retire the disjunction. It's been solved.
13591373
retireConstraint(disjunction);

test/attr/attr_dynamic_member_lookup.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -633,3 +633,24 @@ func keypath_to_subscript_to_property(_ lens: inout Lens<Array<Rectangle>>) {
633633
_ = lens[0].topLeft.y = Lens(1)
634634
// expected-error@-1 {{cannot assign to property: 'y' is a 'let' constant}}
635635
}
636+
637+
@dynamicMemberLookup
638+
struct SingleChoiceLens<T> {
639+
var obj: T
640+
641+
init(_ obj: T) {
642+
self.obj = obj
643+
}
644+
645+
subscript<U>(dynamicMember member: WritableKeyPath<T, U>) -> U {
646+
get { return obj[keyPath: member] }
647+
set { obj[keyPath: member] = newValue }
648+
}
649+
}
650+
651+
// Make sure that disjunction filtering optimization doesn't
652+
// impede keypath dynamic member lookup by eagerly trying to
653+
// simplify disjunctions with a single viable choice.
654+
func test_lens_with_a_single_choice(a: inout SingleChoiceLens<[Int]>) {
655+
a[0] = 1 // Ok
656+
}

0 commit comments

Comments
 (0)