Skip to content

Commit f1f74f0

Browse files
authored
Merge pull request #67663 from amritpan/kp-root-value-tv-inference
[ConstraintSystem] Allow inference to bind AnyKeyPath as a KeyPath
2 parents b8bbc8a + e8425bf commit f1f74f0

File tree

5 files changed

+39
-34
lines changed

5 files changed

+39
-34
lines changed

include/swift/Sema/ConstraintLocator.h

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1062,22 +1062,6 @@ class LocatorPathElt::ContextualType final : public StoredIntegerElement<1> {
10621062
}
10631063
};
10641064

1065-
class LocatorPathElt::KeyPathType final
1066-
: public StoredPointerElement<TypeBase> {
1067-
public:
1068-
KeyPathType(Type valueType)
1069-
: StoredPointerElement(PathElementKind::KeyPathType,
1070-
valueType.getPointer()) {
1071-
assert(valueType);
1072-
}
1073-
1074-
Type getValueType() const { return getStoredPointer(); }
1075-
1076-
static bool classof(const LocatorPathElt *elt) {
1077-
return elt->getKind() == PathElementKind::KeyPathType;
1078-
}
1079-
};
1080-
10811065
class LocatorPathElt::ConstructorMemberType final
10821066
: public StoredIntegerElement<1> {
10831067
public:

include/swift/Sema/ConstraintLocatorPathElts.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ CUSTOM_LOCATOR_PATH_ELT(KeyPathDynamicMember)
123123
SIMPLE_LOCATOR_PATH_ELT(KeyPathRoot)
124124

125125
/// The type of the key path expression.
126-
CUSTOM_LOCATOR_PATH_ELT(KeyPathType)
126+
SIMPLE_LOCATOR_PATH_ELT(KeyPathType)
127127

128128
/// The value of a key path.
129129
SIMPLE_LOCATOR_PATH_ELT(KeyPathValue)

include/swift/Sema/ConstraintSystem.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3031,6 +3031,20 @@ class ConstraintSystem {
30313031
return std::get<1>(result->second);
30323032
return nullptr;
30333033
}
3034+
3035+
TypeVariableType *getKeyPathRootType(const KeyPathExpr *keyPath) const {
3036+
auto result = getKeyPathRootTypeIfAvailable(keyPath);
3037+
assert(result);
3038+
return result;
3039+
}
3040+
3041+
TypeVariableType *
3042+
getKeyPathRootTypeIfAvailable(const KeyPathExpr *keyPath) const {
3043+
auto result = KeyPaths.find(keyPath);
3044+
if (result != KeyPaths.end())
3045+
return std::get<0>(result->second);
3046+
return nullptr;
3047+
}
30343048

30353049
TypeBase* getFavoredType(Expr *E) {
30363050
assert(E != nullptr);

lib/Sema/CSBindings.cpp

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1250,27 +1250,34 @@ PotentialBindings::inferFromRelational(Constraint *constraint) {
12501250
return llvm::None;
12511251

12521252
if (TypeVar->getImpl().isKeyPathType()) {
1253-
auto *BGT = type->lookThroughAllOptionalTypes()->getAs<BoundGenericType>();
1254-
if (!BGT || !isKnownKeyPathType(BGT))
1253+
auto objectTy = type->lookThroughAllOptionalTypes();
1254+
if (!isKnownKeyPathType(objectTy))
12551255
return llvm::None;
1256-
1257-
// `PartialKeyPath<T>` represents a type-erased version of `KeyPath<T, V>`.
1256+
1257+
auto &ctx = CS.getASTContext();
1258+
auto *keyPathTypeLoc = TypeVar->getImpl().getLocator();
1259+
auto *keyPath = castToExpr<KeyPathExpr>(keyPathTypeLoc->getAnchor());
1260+
// `AnyKeyPath` and `PartialKeyPath` represent type-erased versions of
1261+
// `KeyPath<T, V>`.
12581262
//
1259-
// In situations where partial key path cannot be used directly i.e.
1260-
// passing an argument to a parameter represented by a partial key path,
1261-
// let's attempt a `KeyPath` binding which would then be converted to a
1262-
// partial key path since there is a subtype relationship between them.
1263-
if (BGT->isPartialKeyPath() && kind == AllowedBindingKind::Subtypes) {
1264-
auto &ctx = CS.getASTContext();
1265-
auto *keyPathLoc = TypeVar->getImpl().getLocator();
1266-
1267-
auto rootTy = BGT->getGenericArgs()[0];
1263+
// In situations where `AnyKeyPath` or `PartialKeyPath` cannot be used
1264+
// directly i.e. passing an argument to a parameter represented by a
1265+
// `AnyKeyPath` or `PartialKeyPath`, let's attempt a `KeyPath` binding which
1266+
// would then be converted to a `AnyKeyPath` or `PartialKeyPath` since there
1267+
// is a subtype relationship between them.
1268+
if (objectTy->isAnyKeyPath()) {
1269+
auto root = CS.getKeyPathRootType(keyPath);
1270+
auto value = CS.getKeyPathValueType(keyPath);
1271+
1272+
type = BoundGenericType::get(ctx.getKeyPathDecl(), Type(),
1273+
{root, value});
1274+
} else if (objectTy->isPartialKeyPath() &&
1275+
kind == AllowedBindingKind::Subtypes) {
1276+
auto rootTy = objectTy->castTo<BoundGenericType>()->getGenericArgs()[0];
12681277
// Since partial key path is an erased version of `KeyPath`, the value
12691278
// type would never be used, which means that binding can use
12701279
// type variable generated for a result of key path expression.
1271-
auto valueTy =
1272-
keyPathLoc->castLastElementTo<LocatorPathElt::KeyPathType>()
1273-
.getValueType();
1280+
auto valueTy = CS.getKeyPathValueType(keyPath);
12741281

12751282
type = BoundGenericType::get(ctx.getKeyPathDecl(), Type(),
12761283
{rootTy, valueTy});

lib/Sema/CSGen.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3822,7 +3822,7 @@ namespace {
38223822
// The type of key path depends on the overloads chosen for the key
38233823
// path components.
38243824
auto typeLoc =
3825-
CS.getConstraintLocator(locator, LocatorPathElt::KeyPathType(value));
3825+
CS.getConstraintLocator(locator, LocatorPathElt::KeyPathType());
38263826

38273827
Type kpTy = CS.createTypeVariable(typeLoc, TVO_CanBindToNoEscape |
38283828
TVO_CanBindToHole);

0 commit comments

Comments
 (0)