Skip to content

Commit c225d52

Browse files
committed
[CS] Add locator last element casting members
These members provide a convenient way of casting the last element of a locator to a given path element type.
1 parent a0919f7 commit c225d52

File tree

6 files changed

+67
-63
lines changed

6 files changed

+67
-63
lines changed

lib/Sema/CSDiag.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -870,11 +870,9 @@ diagnoseUnresolvedDotExprTypeRequirementFailure(ConstraintSystem &cs,
870870
if (!locator)
871871
return false;
872872

873-
auto path = locator->getPath();
874-
if (path.empty())
875-
return false;
876873

877-
auto reqElt = path.back().getAs<LocatorPathElt::TypeParameterRequirement>();
874+
auto reqElt =
875+
locator->getLastElementAs<LocatorPathElt::TypeParameterRequirement>();
878876
if (!reqElt)
879877
return false;
880878

lib/Sema/CSDiagnostics.cpp

Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -330,13 +330,11 @@ const Requirement &RequirementFailure::getRequirement() const {
330330
ProtocolConformance *RequirementFailure::getConformanceForConditionalReq(
331331
ConstraintLocator *locator) {
332332
auto &cs = getConstraintSystem();
333-
auto path = locator->getPath();
334-
assert(!path.empty());
335-
assert(path.back().is<LocatorPathElt::AnyRequirement>());
336-
337-
if (!path.back().isConditionalRequirement())
333+
auto reqElt = locator->castLastElementTo<LocatorPathElt::AnyRequirement>();
334+
if (!reqElt.isConditionalRequirement())
338335
return nullptr;
339336

337+
auto path = locator->getPath();
340338
auto *typeReqLoc = getConstraintLocator(getRawAnchor(), path.drop_back());
341339

342340
auto result = llvm::find_if(
@@ -780,14 +778,9 @@ bool NoEscapeFuncToTypeConversionFailure::diagnoseAsError() {
780778
return true;
781779
}
782780

783-
GenericTypeParamType *paramTy = nullptr;
784-
785-
auto path = getLocator()->getPath();
786-
if (!path.empty())
787-
if (auto gpElt = path.back().getAs<LocatorPathElt::GenericParameter>())
788-
paramTy = gpElt->getType();
789-
790-
if (paramTy) {
781+
auto *loc = getLocator();
782+
if (auto gpElt = loc->getLastElementAs<LocatorPathElt::GenericParameter>()) {
783+
auto *paramTy = gpElt->getType();
791784
emitDiagnostic(anchor->getLoc(), diag::converting_noescape_to_type,
792785
paramTy);
793786
} else {
@@ -1254,8 +1247,8 @@ bool RValueTreatedAsLValueFailure::diagnoseAsError() {
12541247
auto argTuple = dyn_cast<TupleExpr>(argExpr);
12551248
diagExpr = argTuple->getElement(0);
12561249
} else if (getLocator()->getPath().size() > 0) {
1257-
auto lastPathElement = getLocator()->getPath().back();
1258-
auto argElt = lastPathElement.castTo<LocatorPathElt::ApplyArgToParam>();
1250+
auto argElt =
1251+
getLocator()->castLastElementTo<LocatorPathElt::ApplyArgToParam>();
12591252

12601253
subElementDiagID = diag::cannot_pass_rvalue_inout_subelement;
12611254
rvalueDiagID = diag::cannot_pass_rvalue_inout;
@@ -2406,10 +2399,8 @@ bool TupleContextualFailure::diagnoseAsError() {
24062399
}
24072400

24082401
bool AutoClosureForwardingFailure::diagnoseAsError() {
2409-
auto path = getLocator()->getPath();
2410-
assert(!path.empty());
2411-
2412-
auto last = path.back().castTo<LocatorPathElt::ApplyArgToParam>();
2402+
auto *loc = getLocator();
2403+
auto last = loc->castLastElementTo<LocatorPathElt::ApplyArgToParam>();
24132404

24142405
// We need a raw anchor here because `getAnchor()` is simplified
24152406
// to the argument expression.
@@ -3684,10 +3675,7 @@ bool CollectionElementContextualFailure::diagnoseAsError() {
36843675
}
36853676

36863677
if (isa<DictionaryExpr>(getRawAnchor())) {
3687-
auto path = locator->getPath();
3688-
assert(!path.empty());
3689-
auto eltLoc = path.back().castTo<LocatorPathElt::TupleElement>();
3690-
3678+
auto eltLoc = locator->castLastElementTo<LocatorPathElt::TupleElement>();
36913679
switch (eltLoc.getIndex()) {
36923680
case 0: // key
36933681
diagnostic.emplace(emitDiagnostic(anchor->getLoc(),

lib/Sema/CSDiagnostics.h

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -237,11 +237,8 @@ class RequirementFailure : public FailureDiagnostic {
237237
assert(isConditional() || Signature);
238238
assert(AffectedDecl);
239239

240-
auto path = locator->getPath();
241-
assert(!path.empty());
242-
243-
auto last = path.back().castTo<LocatorPathElt::AnyRequirement>();
244-
assert(last.getRequirementKind() == kind);
240+
auto reqElt = locator->castLastElementTo<LocatorPathElt::AnyRequirement>();
241+
assert(reqElt.getRequirementKind() == kind);
245242

246243
// It's possible sometimes not to have no base expression.
247244
if (!expr)
@@ -252,8 +249,8 @@ class RequirementFailure : public FailureDiagnostic {
252249
}
253250

254251
unsigned getRequirementIndex() const {
255-
auto path = getLocator()->getPath();
256-
auto reqElt = path.back().castTo<LocatorPathElt::AnyRequirement>();
252+
auto reqElt =
253+
getLocator()->castLastElementTo<LocatorPathElt::AnyRequirement>();
257254
return reqElt.getIndex();
258255
}
259256

lib/Sema/CSSimplify.cpp

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4518,32 +4518,33 @@ performMemberLookup(ConstraintKind constraintKind, DeclName memberName,
45184518
// based dynamic member lookup. Since it's unknown upfront
45194519
// what kind of declaration lookup is going to find, let's
45204520
// double check here that given keypath is appropriate for it.
4521-
if (memberLocator && memberLocator->isForKeyPathDynamicMemberLookup()) {
4522-
auto path = memberLocator->getPath();
4523-
auto kpElt = path.back().castTo<LocatorPathElt::KeyPathDynamicMember>();
4524-
auto *keyPath = kpElt.getKeyPathDecl();
4525-
if (auto *storage = dyn_cast<AbstractStorageDecl>(decl)) {
4526-
// If this is an attempt to access read-only member via
4527-
// writable key path, let's fail this choice early.
4528-
auto &ctx = getASTContext();
4529-
if (isReadOnlyKeyPathComponent(storage) &&
4530-
(keyPath == ctx.getWritableKeyPathDecl() ||
4531-
keyPath == ctx.getReferenceWritableKeyPathDecl())) {
4532-
result.addUnviable(
4533-
candidate,
4534-
MemberLookupResult::UR_WritableKeyPathOnReadOnlyMember);
4535-
return;
4536-
}
4521+
if (memberLocator) {
4522+
using KPDynamicMemberElt = LocatorPathElt::KeyPathDynamicMember;
4523+
if (auto kpElt = memberLocator->getLastElementAs<KPDynamicMemberElt>()) {
4524+
auto *keyPath = kpElt->getKeyPathDecl();
4525+
if (auto *storage = dyn_cast<AbstractStorageDecl>(decl)) {
4526+
// If this is an attempt to access read-only member via
4527+
// writable key path, let's fail this choice early.
4528+
auto &ctx = getASTContext();
4529+
if (isReadOnlyKeyPathComponent(storage) &&
4530+
(keyPath == ctx.getWritableKeyPathDecl() ||
4531+
keyPath == ctx.getReferenceWritableKeyPathDecl())) {
4532+
result.addUnviable(
4533+
candidate,
4534+
MemberLookupResult::UR_WritableKeyPathOnReadOnlyMember);
4535+
return;
4536+
}
45374537

4538-
// A nonmutating setter indicates a reference-writable base,
4539-
// on the other hand if setter is mutating there is no point
4540-
// of attempting `ReferenceWritableKeyPath` overload.
4541-
if (storage->isSetterMutating() &&
4542-
keyPath == ctx.getReferenceWritableKeyPathDecl()) {
4543-
result.addUnviable(
4544-
candidate,
4545-
MemberLookupResult::UR_ReferenceWritableKeyPathOnMutatingMember);
4546-
return;
4538+
// A nonmutating setter indicates a reference-writable base,
4539+
// on the other hand if setter is mutating there is no point
4540+
// of attempting `ReferenceWritableKeyPath` overload.
4541+
if (storage->isSetterMutating() &&
4542+
keyPath == ctx.getReferenceWritableKeyPathDecl()) {
4543+
result.addUnviable(candidate,
4544+
MemberLookupResult::
4545+
UR_ReferenceWritableKeyPathOnMutatingMember);
4546+
return;
4547+
}
45474548
}
45484549
}
45494550
}

lib/Sema/ConstraintLocator.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -195,9 +195,7 @@ bool ConstraintLocator::isForContextualType() const {
195195
}
196196

197197
GenericTypeParamType *ConstraintLocator::getGenericParameter() const {
198-
auto path = getPath();
199-
assert(!path.empty());
200-
return path.back().castTo<LocatorPathElt::GenericParameter>().getType();
198+
return castLastElementTo<LocatorPathElt::GenericParameter>().getType();
201199
}
202200

203201
void ConstraintLocator::dump(SourceManager *sm) {

lib/Sema/ConstraintLocator.h

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,27 @@ class ConstraintLocator : public llvm::FoldingSetNode {
510510
/// is of a given kind.
511511
bool isLastElement(ConstraintLocator::PathElementKind kind) const;
512512

513+
/// Attempts to cast the last path element of the locator to a specific
514+
/// \c LocatorPathElt subclass, returning \c None if either unsuccessful or
515+
/// the locator has no path elements.
516+
template <class T>
517+
Optional<T> getLastElementAs() const {
518+
auto path = getPath();
519+
if (path.empty())
520+
return None;
521+
522+
return path.back().getAs<T>();
523+
}
524+
525+
/// Casts the last path element of the locator to a specific \c LocatorPathElt
526+
/// subclass, asserting that it has at least one element.
527+
template <class T>
528+
T castLastElementTo() const {
529+
auto path = getPath();
530+
assert(!path.empty() && "Expected at least one path element!");
531+
return path.back().castTo<T>();
532+
}
533+
513534
/// If this locator points to generic parameter return its type.
514535
GenericTypeParamType *getGenericParameter() const;
515536

@@ -578,7 +599,8 @@ using LocatorPathElt = ConstraintLocator::PathElement;
578599

579600
// Disallow direct uses of isa/cast/dyn_cast on LocatorPathElt in favor of using
580601
// is/castTo/getAs. This allows us to work with Optional<T> rather than pointers
581-
// for getAs.
602+
// for getAs, and maintains consistency with ConstraintLocator's
603+
// isLastElement/castLastElementTo/getLastElementAs members.
582604
template <class X>
583605
inline bool
584606
isa(const LocatorPathElt &) = delete; // Use LocatorPathElt::is instead.

0 commit comments

Comments
 (0)