Skip to content

Commit cb3d6e2

Browse files
authored
Merge pull request #17094 from mdiep/SR-7380
Add root type constraint between KeyPath expressions and applications
2 parents 4b48f4d + 456f69e commit cb3d6e2

File tree

3 files changed

+78
-0
lines changed

3 files changed

+78
-0
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4955,11 +4955,50 @@ ConstraintSystem::addConstraintImpl(ConstraintKind kind, Type first,
49554955
llvm_unreachable("Unhandled ConstraintKind in switch.");
49564956
}
49574957

4958+
void
4959+
ConstraintSystem::addKeyPathApplicationRootConstraint(Type root, ConstraintLocatorBuilder locator) {
4960+
// If this is a subscript with a KeyPath expression, add a constraint that
4961+
// connects the subscript's root type to the root type of the KeyPath.
4962+
SmallVector<LocatorPathElt, 4> path;
4963+
Expr *anchor = locator.getLocatorParts(path);
4964+
4965+
auto subscript = dyn_cast_or_null<SubscriptExpr>(anchor);
4966+
if (!subscript)
4967+
return;
4968+
4969+
assert(path.size() == 1 && path[0].getKind() == ConstraintLocator::SubscriptMember);
4970+
auto indexTuple = dyn_cast<TupleExpr>(subscript->getIndex());
4971+
if (!indexTuple || indexTuple->getNumElements() != 1)
4972+
return;
4973+
4974+
auto keyPathExpr = dyn_cast<KeyPathExpr>(indexTuple->getElement(0));
4975+
if (!keyPathExpr)
4976+
return;
4977+
4978+
auto typeVar = getType(keyPathExpr)->getAs<TypeVariableType>();
4979+
if (!typeVar)
4980+
return;
4981+
4982+
SmallVector<Constraint *, 4> constraints;
4983+
CG.gatherConstraints(typeVar, constraints,
4984+
ConstraintGraph::GatheringKind::EquivalenceClass);
4985+
4986+
for (auto constraint : constraints) {
4987+
if (constraint->getKind() == ConstraintKind::KeyPath &&
4988+
constraint->getLocator()->getAnchor() == keyPathExpr) {
4989+
auto keyPathRootTy = constraint->getSecondType();
4990+
addConstraint(ConstraintKind::Subtype, root->getWithoutSpecifierType(), keyPathRootTy, locator);
4991+
}
4992+
}
4993+
}
4994+
49584995
void
49594996
ConstraintSystem::addKeyPathApplicationConstraint(Type keypath,
49604997
Type root, Type value,
49614998
ConstraintLocatorBuilder locator,
49624999
bool isFavored) {
5000+
addKeyPathApplicationRootConstraint(root, locator);
5001+
49635002
switch (simplifyKeyPathApplicationConstraint(keypath, root, value,
49645003
TMF_GenerateConstraints,
49655004
locator)) {

lib/Sema/ConstraintSystem.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1553,6 +1553,10 @@ class ConstraintSystem {
15531553

15541554
/// Add a new type variable that was already created.
15551555
void addTypeVariable(TypeVariableType *typeVar);
1556+
1557+
/// \brief Add a constraint from the subscript base to the root of the key
1558+
/// path literal to the constraint system.
1559+
void addKeyPathApplicationRootConstraint(Type root, ConstraintLocatorBuilder locator);
15561560

15571561
public:
15581562
/// \brief Lookup for a member with the given name in the given base type.

test/expr/unary/keypath/keypath.swift

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,41 @@ func sr6744() {
499499
_ = get(for: \.value)
500500
}
501501

502+
func sr7380() {
503+
_ = ""[keyPath: \.count]
504+
_ = ""[keyPath: \String.count]
505+
506+
let arr1 = [1]
507+
_ = arr1[keyPath: \.[0]]
508+
_ = arr1[keyPath: \[Int].[0]]
509+
510+
let dic1 = [1:"s"]
511+
_ = dic1[keyPath: \.[1]]
512+
_ = dic1[keyPath: \[Int: String].[1]]
513+
514+
var arr2 = [1]
515+
arr2[keyPath: \.[0]] = 2
516+
arr2[keyPath: \[Int].[0]] = 2
517+
518+
var dic2 = [1:"s"]
519+
dic2[keyPath: \.[1]] = ""
520+
dic2[keyPath: \[Int: String].[1]] = ""
521+
522+
_ = [""][keyPath: \.[0]]
523+
_ = [""][keyPath: \[String].[0]]
524+
525+
_ = ["": ""][keyPath: \.["foo"]]
526+
_ = ["": ""][keyPath: \[String: String].["foo"]]
527+
528+
class A {
529+
var a: String = ""
530+
}
531+
_ = A()[keyPath: \.a]
532+
_ = A()[keyPath: \A.a]
533+
A()[keyPath: \.a] = ""
534+
A()[keyPath: \A.a] = ""
535+
}
536+
502537
struct VisibilityTesting {
503538
private(set) var x: Int
504539
fileprivate(set) var y: Int

0 commit comments

Comments
 (0)