[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
This commit is contained in:
Pavel Yaskevich
2019-04-03 12:23:23 -07:00
parent e3ad92fbfb
commit 2e8d163655
2 changed files with 41 additions and 6 deletions

View File

@@ -1348,12 +1348,26 @@ ConstraintSystem::filterDisjunction(
// This can only happen when subscript syntax is used to lookup
// something which doesn't exist in type marked with
// `@dynamicMemberLookup`. Early simplification of the key path
// dynamic member lookup choice is impossible because it requires
// constraints associated with subscript index expression to be present.
if (!solverState && choice->getOverloadChoice().getKind() ==
OverloadChoiceKind::KeyPathDynamicMemberLookup)
return SolutionKind::Unsolved;
// `@dynamicMemberLookup`.
// 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.
if (choice->getOverloadChoice().getKind() ==
OverloadChoiceKind::KeyPathDynamicMemberLookup) {
// Early simplification of the "keypath dynamic member lookup" choice
// is impossible because it requires constraints associated with
// subscript index expression to be present.
if (!solverState)
return SolutionKind::Unsolved;
for (auto *currentChoice : disjunction->getNestedConstraints()) {
if (currentChoice != choice)
solverState->disableContraint(currentChoice);
}
return SolutionKind::Solved;
}
// Retire the disjunction. It's been solved.
retireConstraint(disjunction);

View File

@@ -633,3 +633,24 @@ func keypath_to_subscript_to_property(_ lens: inout Lens<Array<Rectangle>>) {
_ = lens[0].topLeft.y = Lens(1)
// expected-error@-1 {{cannot assign to property: 'y' is a 'let' constant}}
}
@dynamicMemberLookup
struct SingleChoiceLens<T> {
var obj: T
init(_ obj: T) {
self.obj = obj
}
subscript<U>(dynamicMember member: WritableKeyPath<T, U>) -> U {
get { return obj[keyPath: member] }
set { obj[keyPath: member] = newValue }
}
}
// Make sure that disjunction filtering optimization doesn't
// impede keypath dynamic member lookup by eagerly trying to
// simplify disjunctions with a single viable choice.
func test_lens_with_a_single_choice(a: inout SingleChoiceLens<[Int]>) {
a[0] = 1 // Ok
}