mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[CS] Don't leave key path with holes unsolved
We currently leave a key path constraint unsolved if one of its components hasn't yet had its overload resolved. However, for e.g a missing member component, the overload type variable will be bound to a hole and an overload will never be resolved. Tweak the logic to consider the key path constraint trivially solved if one of its components has been marked as a hole, which will allow the key path type itself to be marked as a hole. Resolves SR-12437 & SR-12823. Resolves rdar://62201037.
This commit is contained in:
@@ -7683,10 +7683,30 @@ ConstraintSystem::simplifyKeyPathConstraint(
|
||||
return true;
|
||||
};
|
||||
|
||||
// We have a hole, the solver can't infer the key path type. So let's
|
||||
// just assume this is solved.
|
||||
if (shouldAttemptFixes() && keyPathTy->isHole()) {
|
||||
return SolutionKind::Solved;
|
||||
// If we have a hole somewhere in the key path, the solver won't be able to
|
||||
// infer the key path type. So let's just assume this is solved.
|
||||
if (shouldAttemptFixes()) {
|
||||
if (keyPathTy->isHole())
|
||||
return SolutionKind::Solved;
|
||||
|
||||
// If the root type has been bound to a hole, we cannot infer it.
|
||||
if (getFixedTypeRecursive(rootTy, /*wantRValue*/ true)->isHole())
|
||||
return SolutionKind::Solved;
|
||||
|
||||
// If we have e.g a missing member somewhere, a component type variable
|
||||
// will have been marked as a potential hole.
|
||||
// FIXME: This relies on the fact that we only mark an overload type
|
||||
// variable as a potential hole once we've added a corresponding fix. We
|
||||
// can't use 'isHole' instead, as that doesn't handle cases where the
|
||||
// overload type variable gets bound to another type from the context rather
|
||||
// than a hole. We need to come up with a better way of handling the
|
||||
// relationship between key paths and overloads.
|
||||
if (llvm::any_of(componentTypeVars, [&](TypeVariableType *tv) {
|
||||
return tv->getImpl().getLocator()->isForKeyPathComponent() &&
|
||||
tv->getImpl().canBindToHole();
|
||||
})) {
|
||||
return SolutionKind::Solved;
|
||||
}
|
||||
}
|
||||
|
||||
// If we're fixed to a bound generic type, trying harvesting context from it.
|
||||
@@ -7737,34 +7757,11 @@ ConstraintSystem::simplifyKeyPathConstraint(
|
||||
// to determine whether the result will be a function type vs BGT KeyPath
|
||||
// type, so continue through components to create new constraint at the
|
||||
// end.
|
||||
if (!overload || anyComponentsUnresolved) {
|
||||
if (!overload) {
|
||||
if (flags.contains(TMF_GenerateConstraints)) {
|
||||
anyComponentsUnresolved = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (shouldAttemptFixes()) {
|
||||
auto typeVar =
|
||||
llvm::find_if(componentTypeVars, [&](TypeVariableType *typeVar) {
|
||||
auto *locator = typeVar->getImpl().getLocator();
|
||||
auto elt = locator->findLast<LocatorPathElt::KeyPathComponent>();
|
||||
return elt && elt->getIndex() == i;
|
||||
});
|
||||
|
||||
// If one of the components haven't been resolved, let's check
|
||||
// whether it has been determined to be a "hole" and if so,
|
||||
// let's allow component validation to contiunue.
|
||||
//
|
||||
// This helps to, for example, diagnose problems with missing
|
||||
// members used as part of a key path.
|
||||
if (typeVar != componentTypeVars.end() &&
|
||||
(*typeVar)->getImpl().canBindToHole()) {
|
||||
anyComponentsUnresolved = true;
|
||||
capability = ReadOnly;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return SolutionKind::Unsolved;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user