Skip to content

Commit 6e45ef1

Browse files
committed
[CS] Add locator find[First/Last] members
These members provide a convenient way of getting the first or last occurrence of a given kind of element in a locator's path.
1 parent c225d52 commit 6e45ef1

File tree

3 files changed

+76
-44
lines changed

3 files changed

+76
-44
lines changed

lib/Sema/CSApply.cpp

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1545,15 +1545,6 @@ namespace {
15451545
LocatorPathElt::KeyPathDynamicMember(keyPathTy->getAnyNominal()));
15461546
auto overload = solution.getOverloadChoice(componentLoc);
15471547

1548-
auto getKeyPathComponentIndex =
1549-
[](ConstraintLocator *locator) -> unsigned {
1550-
for (const auto &elt : locator->getPath()) {
1551-
if (auto kpElt = elt.getAs<LocatorPathElt::KeyPathComponent>())
1552-
return kpElt->getIndex();
1553-
}
1554-
llvm_unreachable("no keypath component node");
1555-
};
1556-
15571548
// Looks like there is a chain of implicit `subscript(dynamicMember:)`
15581549
// calls necessary to resolve a member reference.
15591550
if (overload.choice.getKind() ==
@@ -1578,8 +1569,9 @@ namespace {
15781569
// of a keypath expression e.g. `\Lens<[Int]>.count` where
15791570
// `count` is referenced using dynamic lookup.
15801571
if (auto *KPE = dyn_cast<KeyPathExpr>(anchor)) {
1581-
auto componentIdx = getKeyPathComponentIndex(memberLoc);
1582-
auto &origComponent = KPE->getComponents()[componentIdx];
1572+
auto kpElt = memberLoc->findFirst<LocatorPathElt::KeyPathComponent>();
1573+
assert(kpElt && "no keypath component node");
1574+
auto &origComponent = KPE->getComponents()[kpElt->getIndex()];
15831575

15841576
using ComponentKind = KeyPathExpr::Component::Kind;
15851577
if (origComponent.getKind() == ComponentKind::UnresolvedProperty) {

lib/Sema/CSDiagnostics.cpp

Lines changed: 16 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -197,21 +197,18 @@ FailureDiagnostic::getFunctionArgApplyInfo(ConstraintLocator *locator) const {
197197
// have to look through other elements that are generated from an argument
198198
// conversion such as GenericArgument for an optional-to-optional conversion,
199199
// and OptionalPayload for a value-to-optional conversion.
200-
auto applyArgEltIter =
201-
std::find_if(path.rbegin(), path.rend(), [](LocatorPathElt elt) {
202-
return elt.is<LocatorPathElt::ApplyArgToParam>();
203-
});
204-
205-
if (applyArgEltIter == path.rend())
200+
auto iter = path.rbegin();
201+
auto applyArgElt = locator->findLast<LocatorPathElt::ApplyArgToParam>(iter);
202+
if (!applyArgElt)
206203
return None;
207204

208-
assert(std::find_if(applyArgEltIter + 1, path.rend(), [](LocatorPathElt elt) {
209-
return elt.getKind() == ConstraintLocator::ApplyArgToParam;
210-
}) == path.rend() && "Multiple ApplyArgToParam components?");
205+
auto nextIter = iter + 1;
206+
assert(!locator->findLast<LocatorPathElt::ApplyArgToParam>(nextIter) &&
207+
"Multiple ApplyArgToParam components?");
211208

212209
// Form a new locator that ends at the apply-arg-to-param element, and
213210
// simplify it to get the full argument expression.
214-
auto argPath = path.drop_back(applyArgEltIter - path.rbegin());
211+
auto argPath = path.drop_back(iter - path.rbegin());
215212
auto *argLocator = cs.getConstraintLocator(
216213
anchor, argPath, ConstraintLocator::getSummaryFlagsForPath(argPath));
217214

@@ -271,9 +268,8 @@ FailureDiagnostic::getFunctionArgApplyInfo(ConstraintLocator *locator) const {
271268
fnInterfaceType = resolveInterfaceType(rawFnType);
272269
}
273270

274-
auto applyArgElt = applyArgEltIter->castTo<LocatorPathElt::ApplyArgToParam>();
275-
auto argIdx = applyArgElt.getArgIdx();
276-
auto paramIdx = applyArgElt.getParamIdx();
271+
auto argIdx = applyArgElt->getArgIdx();
272+
auto paramIdx = applyArgElt->getParamIdx();
277273

278274
return FunctionArgApplyInfo(argExpr, argIdx, getType(argExpr), paramIdx,
279275
fnInterfaceType, fnType, callee);
@@ -409,12 +405,8 @@ GenericSignature *RequirementFailure::getSignature(ConstraintLocator *locator) {
409405
if (isConditional())
410406
return Conformance->getGenericSignature();
411407

412-
auto path = locator->getPath();
413-
for (auto iter = path.rbegin(); iter != path.rend(); ++iter) {
414-
const auto &elt = *iter;
415-
if (auto genericElt = elt.getAs<LocatorPathElt::OpenedGeneric>())
416-
return genericElt->getSignature();
417-
}
408+
if (auto genericElt = locator->findLast<LocatorPathElt::OpenedGeneric>())
409+
return genericElt->getSignature();
418410

419411
llvm_unreachable("Type requirement failure should always have signature");
420412
}
@@ -3563,12 +3555,8 @@ bool KeyPathSubscriptIndexHashableFailure::diagnoseAsError() {
35633555
auto loc = anchor->getLoc();
35643556
if (locator->isKeyPathSubscriptComponent()) {
35653557
auto *KPE = cast<KeyPathExpr>(anchor);
3566-
for (auto &elt : locator->getPath()) {
3567-
if (auto kpElt = elt.getAs<LocatorPathElt::KeyPathComponent>()) {
3568-
loc = KPE->getComponents()[kpElt->getIndex()].getLoc();
3569-
break;
3570-
}
3571-
}
3558+
if (auto kpElt = locator->findFirst<LocatorPathElt::KeyPathComponent>())
3559+
loc = KPE->getComponents()[kpElt->getIndex()].getLoc();
35723560
}
35733561

35743562
emitDiagnostic(loc, diag::expr_keypath_subscript_index_not_hashable,
@@ -3581,14 +3569,9 @@ SourceLoc InvalidMemberRefInKeyPath::getLoc() const {
35813569

35823570
if (auto *KPE = dyn_cast<KeyPathExpr>(anchor)) {
35833571
auto *locator = getLocator();
3584-
auto componentIter =
3585-
llvm::find_if(locator->getPath(), [](const LocatorPathElt &elt) {
3586-
return elt.isKeyPathComponent();
3587-
});
3588-
3589-
assert(componentIter != locator->getPath().end());
3590-
auto component = componentIter->castTo<LocatorPathElt::KeyPathComponent>();
3591-
return KPE->getComponents()[component.getIndex()].getLoc();
3572+
auto component = locator->findFirst<LocatorPathElt::KeyPathComponent>();
3573+
assert(component);
3574+
return KPE->getComponents()[component->getIndex()].getLoc();
35923575
}
35933576

35943577
return anchor->getLoc();

lib/Sema/ConstraintLocator.h

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,63 @@ class ConstraintLocator : public llvm::FoldingSetNode {
531531
return path.back().castTo<T>();
532532
}
533533

534+
using PathIterator = ArrayRef<PathElement>::iterator;
535+
using PathReverseIterator = ArrayRef<PathElement>::reverse_iterator;
536+
537+
/// Attempts to find the first element in the locator's path that is a
538+
/// specific \c LocatorPathElt subclass, returning \c None if no such element
539+
/// exists.
540+
///
541+
/// \param iter A reference to an iterator which will be used to iterate
542+
/// over the locator's path.
543+
template <class T>
544+
Optional<T> findFirst(PathIterator &iter) const {
545+
auto path = getPath();
546+
auto end = path.end();
547+
assert(iter >= path.begin() && iter <= end);
548+
549+
for (; iter != end; ++iter)
550+
if (auto elt = iter->getAs<T>())
551+
return elt;
552+
return None;
553+
}
554+
555+
/// Attempts to find the first element in the locator's path that is a
556+
/// specific \c LocatorPathElt subclass, returning \c None if no such element
557+
/// exists.
558+
template <class T>
559+
Optional<T> findFirst() const {
560+
auto iter = getPath().begin();
561+
return findFirst<T>(iter);
562+
}
563+
564+
/// Attempts to find the last element in the locator's path that is a
565+
/// specific \c LocatorPathElt subclass, returning \c None if no such element
566+
/// exists.
567+
///
568+
/// \param iter A reference to a reverse iterator which will be used to
569+
/// iterate over the locator's path.
570+
template <class T>
571+
Optional<T> findLast(PathReverseIterator &iter) const {
572+
auto path = getPath();
573+
auto end = path.rend();
574+
assert(iter >= path.rbegin() && iter <= end);
575+
576+
for (; iter != end; ++iter)
577+
if (auto elt = iter->getAs<T>())
578+
return elt;
579+
return None;
580+
}
581+
582+
/// Attempts to find the last element in the locator's path that is a
583+
/// specific \c LocatorPathElt subclass, returning \c None if no such element
584+
/// exists.
585+
template <class T>
586+
Optional<T> findLast() const {
587+
auto iter = getPath().rbegin();
588+
return findLast<T>(iter);
589+
}
590+
534591
/// If this locator points to generic parameter return its type.
535592
GenericTypeParamType *getGenericParameter() const;
536593

0 commit comments

Comments
 (0)