Skip to content

Commit 50803b8

Browse files
[CSBindings] Emit specific key path root arg if generic param type var being bound to hole has a key path root representatee
1 parent e2da5c5 commit 50803b8

File tree

2 files changed

+45
-6
lines changed

2 files changed

+45
-6
lines changed

lib/Sema/CSBindings.cpp

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1089,12 +1089,22 @@ bool TypeVariableBinding::attempt(ConstraintSystem &cs) const {
10891089

10901090
ConstraintFix *fix = nullptr;
10911091
if (auto *GP = TypeVar->getImpl().getGenericParameter()) {
1092-
auto path = dstLocator->getPath();
1093-
// Drop `generic parameter` locator element so that all missing
1094-
// generic parameters related to the same path can be coalesced later.
1095-
fix = DefaultGenericArgument::create(
1096-
cs, GP,
1097-
cs.getConstraintLocator(dstLocator->getAnchor(), path.drop_back()));
1092+
// If it is represetative for a key path root, let's emit a more
1093+
// specific diagnostic.
1094+
auto *keyPathRoot =
1095+
cs.isRepresentativeFor(TypeVar, ConstraintLocator::KeyPathRoot);
1096+
if (keyPathRoot) {
1097+
fix = SpecifyKeyPathRootType::create(
1098+
cs, keyPathRoot->getImpl().getLocator());
1099+
} else {
1100+
auto path = dstLocator->getPath();
1101+
// Drop `generic parameter` locator element so that all missing
1102+
// generic parameters related to the same path can be coalesced later.
1103+
fix = DefaultGenericArgument::create(
1104+
cs, GP,
1105+
cs.getConstraintLocator(dstLocator->getAnchor(),
1106+
path.drop_back()));
1107+
}
10981108
} else if (TypeVar->getImpl().isClosureParameterType()) {
10991109
fix = SpecifyClosureParameterType::create(cs, dstLocator);
11001110
} else if (TypeVar->getImpl().isClosureResultType()) {

lib/Sema/ConstraintSystem.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3071,6 +3071,35 @@ class ConstraintSystem {
30713071
return typeVar->getImpl().getRepresentative(getSavedBindings());
30723072
}
30733073

3074+
/// Finds if the given type variable is representative for a type
3075+
/// variable which last locator path element is of the specified kind.
3076+
/// If true returns the type variable which it is the representative for.
3077+
TypeVariableType *
3078+
isRepresentativeFor(TypeVariableType *typeVar,
3079+
ConstraintLocator::PathElementKind kind) const {
3080+
// We only attempt to look for this if type variable is
3081+
// a representative.
3082+
if (getRepresentative(typeVar) != typeVar)
3083+
return nullptr;
3084+
3085+
auto &CG = getConstraintGraph();
3086+
auto result = CG.lookupNode(typeVar);
3087+
auto equivalence = result.first.getEquivalenceClass();
3088+
auto member = llvm::find_if(equivalence, [=](TypeVariableType *eq) {
3089+
auto *loc = eq->getImpl().getLocator();
3090+
if (!loc)
3091+
return false;
3092+
3093+
auto path = loc->getPath();
3094+
return !path.empty() && path.back().getKind() == kind;
3095+
});
3096+
3097+
if (member == equivalence.end())
3098+
return nullptr;
3099+
3100+
return *member;
3101+
}
3102+
30743103
/// Gets the VarDecl associateed with resolvedOverload, and the type of the
30753104
/// storage wrapper if the decl has an associated storage wrapper.
30763105
Optional<std::pair<VarDecl *, Type>>

0 commit comments

Comments
 (0)