Skip to content

Commit 04ae94f

Browse files
authored
[CS] Resolve callees for key path components (#27087)
[CS] Resolve callees for key path components
2 parents c949261 + c745c17 commit 04ae94f

File tree

8 files changed

+136
-43
lines changed

8 files changed

+136
-43
lines changed

lib/Sema/CSApply.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4243,11 +4243,11 @@ namespace {
42434243

42444244
auto locator = cs.getConstraintLocator(
42454245
E, LocatorPathElt::KeyPathComponent(i));
4246-
if (kind == KeyPathExpr::Component::Kind::UnresolvedSubscript) {
4247-
locator =
4248-
cs.getConstraintLocator(locator,
4249-
ConstraintLocator::SubscriptMember);
4250-
}
4246+
4247+
// Adjust the locator such that it includes any additional elements to
4248+
// point to the component's callee, e.g a SubscriptMember for a
4249+
// subscript component.
4250+
locator = cs.getCalleeLocator(locator);
42514251

42524252
bool isDynamicMember = false;
42534253
// If this is an unresolved link, make sure we resolved it.

lib/Sema/CSDiagnostics.cpp

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,10 @@ Expr *FailureDiagnostic::getBaseExprFor(Expr *anchor) const {
121121
return nullptr;
122122
}
123123

124-
Optional<SelectedOverload> FailureDiagnostic::getChoiceFor(Expr *expr) const {
124+
Optional<SelectedOverload>
125+
FailureDiagnostic::getChoiceFor(ConstraintLocator *locator) const {
125126
auto &cs = getConstraintSystem();
126-
return getOverloadChoiceIfAvailable(cs.getCalleeLocator(expr));
127+
return getOverloadChoiceIfAvailable(cs.getCalleeLocator(locator));
127128
}
128129

129130
Type FailureDiagnostic::resolveInterfaceType(Type type,
@@ -220,7 +221,7 @@ FailureDiagnostic::getFunctionArgApplyInfo(ConstraintLocator *locator) const {
220221

221222
ValueDecl *callee = nullptr;
222223
Type rawFnType;
223-
if (auto overload = getChoiceFor(anchor)) {
224+
if (auto overload = getChoiceFor(argLocator)) {
224225
// If we have resolved an overload for the callee, then use that to get the
225226
// function type and callee.
226227
callee = overload->choice.getDeclOrNull();
@@ -374,7 +375,7 @@ ValueDecl *RequirementFailure::getDeclRef() const {
374375
if (isFromContextualType())
375376
return getAffectedDeclFromType(cs.getContextualType());
376377

377-
if (auto overload = getChoiceFor(getRawAnchor())) {
378+
if (auto overload = getChoiceFor(getLocator())) {
378379
// If there is a declaration associated with this
379380
// failure e.g. an overload choice of the call
380381
// expression, let's see whether failure is
@@ -746,7 +747,7 @@ bool LabelingFailure::diagnoseAsNote() {
746747
return "(" + str + ")";
747748
};
748749

749-
auto selectedOverload = getChoiceFor(anchor);
750+
auto selectedOverload = getChoiceFor(getLocator());
750751
if (!selectedOverload)
751752
return false;
752753

@@ -3120,8 +3121,8 @@ bool AllowTypeOrInstanceMemberFailure::diagnoseAsError() {
31203121
return true;
31213122
};
31223123

3123-
auto selection = getChoiceFor(ctorRef->getBase());
3124-
if (selection) {
3124+
auto *baseLoc = cs.getConstraintLocator(ctorRef->getBase());
3125+
if (auto selection = getChoiceFor(baseLoc)) {
31253126
OverloadChoice choice = selection->choice;
31263127
if (choice.isDecl() && isMutable(choice.getDecl()) &&
31273128
!isCallArgument(initCall) &&
@@ -4281,15 +4282,13 @@ bool MutatingMemberRefOnImmutableBase::diagnoseAsError() {
42814282
}
42824283

42834284
bool InvalidTupleSplatWithSingleParameterFailure::diagnoseAsError() {
4284-
auto *anchor = getRawAnchor();
4285-
4286-
auto selectedOverload = getChoiceFor(anchor);
4285+
auto selectedOverload = getChoiceFor(getLocator());
42874286
if (!selectedOverload || !selectedOverload->choice.isDecl())
42884287
return false;
42894288

42904289
auto *choice = selectedOverload->choice.getDecl();
42914290

4292-
auto *argExpr = getArgumentExprFor(anchor);
4291+
auto *argExpr = getArgumentExprFor(getRawAnchor());
42934292
if (!argExpr)
42944293
return false;
42954294

lib/Sema/CSDiagnostics.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,9 @@ class FailureDiagnostic {
176176
/// reference or subscript, nullptr otherwise.
177177
Expr *getArgumentExprFor(Expr *anchor) const;
178178

179-
Optional<SelectedOverload> getChoiceFor(Expr *) const;
179+
/// \returns The overload choice made by the constraint system for the callee
180+
/// of a given locator's anchor, or \c None if no such choice can be found.
181+
Optional<SelectedOverload> getChoiceFor(ConstraintLocator *) const;
180182

181183
/// For a given locator describing a function argument conversion, or a
182184
/// constraint within an argument conversion, returns information about the

lib/Sema/CSGen.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3023,6 +3023,8 @@ namespace {
30233023
}
30243024

30253025
case KeyPathExpr::Component::Kind::TupleElement: {
3026+
// Note: If implemented, the logic in `getCalleeLocator` will need
3027+
// updating to return the correct callee locator for this.
30263028
llvm_unreachable("not implemented");
30273029
break;
30283030
}
@@ -3256,7 +3258,9 @@ namespace {
32563258
// Record the labels.
32573259
if (!labelsArePermanent)
32583260
info.Labels = CS.allocateCopy(info.Labels);
3259-
CS.ArgumentInfos[CS.getArgumentInfoLocator(expr)] = info;
3261+
3262+
auto *locator = CS.getConstraintLocator(expr);
3263+
CS.ArgumentInfos[CS.getArgumentInfoLocator(locator)] = info;
32603264
}
32613265
};
32623266

lib/Sema/ConstraintLocator.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,27 @@ class ConstraintLocator : public llvm::FoldingSetNode {
502502
/// Determine whether this locator points to the contextual type.
503503
bool isForContextualType() const;
504504

505+
/// Attempts to cast the first path element of the locator to a specific
506+
/// \c LocatorPathElt subclass, returning \c None if either unsuccessful or
507+
/// the locator has no path elements.
508+
template <class T>
509+
Optional<T> getFirstElementAs() const {
510+
auto path = getPath();
511+
if (path.empty())
512+
return None;
513+
514+
return path[0].getAs<T>();
515+
}
516+
517+
/// Casts the first path element of the locator to a specific
518+
/// \c LocatorPathElt subclass, asserting that it has at least one element.
519+
template <class T>
520+
T castFirstElementTo() const {
521+
auto path = getPath();
522+
assert(!path.empty() && "Expected at least one path element!");
523+
return path[0].castTo<T>();
524+
}
525+
505526
/// Check whether the last element in the path of this locator
506527
/// is of a given kind.
507528
bool isLastElement(ConstraintLocator::PathElementKind kind) const;

lib/Sema/ConstraintSystem.cpp

Lines changed: 55 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -413,14 +413,49 @@ ConstraintLocator *ConstraintSystem::getConstraintLocator(
413413
return getConstraintLocator(anchor, path, builder.getSummaryFlags());
414414
}
415415

416-
ConstraintLocator *ConstraintSystem::getCalleeLocator(Expr *expr) {
416+
ConstraintLocator *
417+
ConstraintSystem::getCalleeLocator(ConstraintLocator *locator) {
418+
auto *anchor = locator->getAnchor();
419+
assert(anchor && "Expected an anchor!");
420+
421+
// If we have a locator that starts with a key path component element, we
422+
// may have a callee given by a property or subscript component.
423+
if (auto componentElt =
424+
locator->getFirstElementAs<LocatorPathElt::KeyPathComponent>()) {
425+
auto *kpExpr = cast<KeyPathExpr>(anchor);
426+
auto component = kpExpr->getComponents()[componentElt->getIndex()];
427+
428+
using ComponentKind = KeyPathExpr::Component::Kind;
429+
switch (component.getKind()) {
430+
case ComponentKind::UnresolvedSubscript:
431+
case ComponentKind::Subscript:
432+
// For a subscript the callee is given by 'component -> subscript member'.
433+
return getConstraintLocator(
434+
anchor, {*componentElt, ConstraintLocator::SubscriptMember});
435+
case ComponentKind::UnresolvedProperty:
436+
case ComponentKind::Property:
437+
// For a property, the choice is just given by the component.
438+
return getConstraintLocator(anchor, *componentElt);
439+
case ComponentKind::TupleElement:
440+
llvm_unreachable("Not implemented by CSGen");
441+
break;
442+
case ComponentKind::Invalid:
443+
case ComponentKind::OptionalForce:
444+
case ComponentKind::OptionalChain:
445+
case ComponentKind::OptionalWrap:
446+
case ComponentKind::Identity:
447+
// These components don't have any callee associated, so just continue.
448+
break;
449+
}
450+
}
451+
417452
// Make sure we handle subscripts before looking at apply exprs. We don't
418453
// want to return a subscript member locator for an expression such as x[](y),
419454
// as its callee is not the subscript, but rather the function it returns.
420-
if (isa<SubscriptExpr>(expr))
421-
return getConstraintLocator(expr, ConstraintLocator::SubscriptMember);
455+
if (isa<SubscriptExpr>(anchor))
456+
return getConstraintLocator(anchor, ConstraintLocator::SubscriptMember);
422457

423-
if (auto *applyExpr = dyn_cast<ApplyExpr>(expr)) {
458+
if (auto *applyExpr = dyn_cast<ApplyExpr>(anchor)) {
424459
auto *fnExpr = applyExpr->getFn();
425460
// For an apply of a metatype, we have a short-form constructor. Unlike
426461
// other locators to callees, these are anchored on the apply expression
@@ -436,27 +471,27 @@ ConstraintLocator *ConstraintSystem::getCalleeLocator(Expr *expr) {
436471
// Otherwise fall through and look for locators anchored on the function
437472
// expr. For CallExprs, this can look through things like parens and
438473
// optional chaining.
439-
if (auto *callExpr = dyn_cast<CallExpr>(expr)) {
440-
expr = callExpr->getDirectCallee();
474+
if (auto *callExpr = dyn_cast<CallExpr>(anchor)) {
475+
anchor = callExpr->getDirectCallee();
441476
} else {
442-
expr = fnExpr;
477+
anchor = fnExpr;
443478
}
444479
}
445480

446-
if (auto *UDE = dyn_cast<UnresolvedDotExpr>(expr)) {
481+
if (auto *UDE = dyn_cast<UnresolvedDotExpr>(anchor)) {
447482
return getConstraintLocator(
448-
expr, TC.getSelfForInitDelegationInConstructor(DC, UDE)
483+
anchor, TC.getSelfForInitDelegationInConstructor(DC, UDE)
449484
? ConstraintLocator::ConstructorMember
450485
: ConstraintLocator::Member);
451486
}
452487

453-
if (isa<UnresolvedMemberExpr>(expr))
454-
return getConstraintLocator(expr, ConstraintLocator::UnresolvedMember);
488+
if (isa<UnresolvedMemberExpr>(anchor))
489+
return getConstraintLocator(anchor, ConstraintLocator::UnresolvedMember);
455490

456-
if (isa<MemberRefExpr>(expr))
457-
return getConstraintLocator(expr, ConstraintLocator::Member);
491+
if (isa<MemberRefExpr>(anchor))
492+
return getConstraintLocator(anchor, ConstraintLocator::Member);
458493

459-
return getConstraintLocator(expr);
494+
return getConstraintLocator(anchor);
460495
}
461496

462497
Type ConstraintSystem::openUnboundGenericType(UnboundGenericType *unbound,
@@ -2462,7 +2497,7 @@ bool ConstraintSystem::diagnoseAmbiguityWithFixes(
24622497
return false;
24632498

24642499
const auto *fix = fixes.front();
2465-
auto *calleeLocator = getCalleeLocator(fix->getAnchor());
2500+
auto *calleeLocator = getCalleeLocator(fix->getLocator());
24662501
if (commonCalleeLocator && commonCalleeLocator != calleeLocator)
24672502
return false;
24682503

@@ -2829,7 +2864,9 @@ void ConstraintSystem::generateConstraints(
28292864
}
28302865
}
28312866

2832-
ConstraintLocator *ConstraintSystem::getArgumentInfoLocator(Expr *anchor) {
2867+
ConstraintLocator *
2868+
ConstraintSystem::getArgumentInfoLocator(ConstraintLocator *locator) {
2869+
auto *anchor = locator->getAnchor();
28332870
if (!anchor)
28342871
return nullptr;
28352872

@@ -2838,12 +2875,12 @@ ConstraintLocator *ConstraintSystem::getArgumentInfoLocator(Expr *anchor) {
28382875
return getConstraintLocator(fnExpr);
28392876
}
28402877

2841-
return getCalleeLocator(anchor);
2878+
return getCalleeLocator(locator);
28422879
}
28432880

28442881
Optional<ConstraintSystem::ArgumentInfo>
28452882
ConstraintSystem::getArgumentInfo(ConstraintLocator *locator) {
2846-
if (auto *infoLocator = getArgumentInfoLocator(locator->getAnchor())) {
2883+
if (auto *infoLocator = getArgumentInfoLocator(locator)) {
28472884
auto known = ArgumentInfos.find(infoLocator);
28482885
if (known != ArgumentInfos.end())
28492886
return known->second;

lib/Sema/ConstraintSystem.h

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1579,9 +1579,10 @@ class ConstraintSystem {
15791579
/// that locator.
15801580
llvm::DenseMap<ConstraintLocator *, ArgumentInfo> ArgumentInfos;
15811581

1582-
/// Form a locator with given anchor which then could be used
1583-
/// to retrieve argument information cached in the constraint system.
1584-
ConstraintLocator *getArgumentInfoLocator(Expr *anchor);
1582+
/// Form a locator that can be used to retrieve argument information cached in
1583+
/// the constraint system for the callee described by the anchor of the
1584+
/// passed locator.
1585+
ConstraintLocator *getArgumentInfoLocator(ConstraintLocator *locator);
15851586

15861587
/// Retrieve the argument info that is associated with a member
15871588
/// reference at the given locator.
@@ -2008,10 +2009,26 @@ class ConstraintSystem {
20082009
return e != ExprWeights.end() ? e->second.second : nullptr;
20092010
}
20102011

2011-
/// Returns a locator describing the callee for a given expression. For
2012-
/// a function application, this is a locator describing the function expr.
2013-
/// For an unresolved dot/member, this is a locator to the member.
2014-
ConstraintLocator *getCalleeLocator(Expr *expr);
2012+
/// Returns a locator describing the callee for the anchor of a given locator.
2013+
///
2014+
/// - For an unresolved dot/member anchor, this will be a locator describing
2015+
/// the member.
2016+
///
2017+
/// - For a subscript anchor, this will be a locator describing the subscript
2018+
/// member.
2019+
///
2020+
/// - For a key path anchor with a property/subscript component path element,
2021+
/// this will be a locator describing the decl referenced by the component.
2022+
///
2023+
/// - For a function application anchor, this will be a locator describing the
2024+
/// 'direct callee' of the call. For example, for the expression \c x.foo?()
2025+
/// the returned locator will describe the member \c foo.
2026+
///
2027+
/// Note that because this function deals with the anchor, given a locator
2028+
/// anchored on \c functionA(functionB()) with path elements pointing to the
2029+
/// argument \c functionB(), the returned callee locator will describe
2030+
/// \c functionA rather than \c functionB.
2031+
ConstraintLocator *getCalleeLocator(ConstraintLocator *locator);
20152032

20162033
public:
20172034

test/Constraints/generics.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -819,3 +819,16 @@ func test_correct_identification_of_requirement_source() {
819819
_ = X(A(), 17)
820820
// expected-error@-1 {{initializer 'init(_:_:)' requires that 'Int' conform to 'P'}}
821821
}
822+
823+
struct SR11435<T> {
824+
subscript<U : P & Hashable>(x x: U) -> U { x } // expected-note {{where 'U' = 'Int'}}
825+
}
826+
827+
extension SR11435 where T : P { // expected-note {{where 'T' = 'Int'}}
828+
var foo: Int { 0 }
829+
}
830+
831+
func test_identification_of_key_path_component_callees() {
832+
_ = \SR11435<Int>.foo // expected-error {{property 'foo' requires that 'Int' conform to 'P'}}
833+
_ = \SR11435<Int>.[x: 5] // expected-error {{subscript 'subscript(x:)' requires that 'Int' conform to 'P'}}
834+
}

0 commit comments

Comments
 (0)