Skip to content

Commit ad802c3

Browse files
authored
Merge pull request #22693 from xedin/opt-type-req-locators
[CSFix] Use fully qualified locators for requirement failures
2 parents ab827a9 + 70b5bce commit ad802c3

File tree

3 files changed

+33
-31
lines changed

3 files changed

+33
-31
lines changed

lib/Sema/CSDiagnostics.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,9 @@ Expr *FailureDiagnostic::findParentExpr(Expr *subExpr) const {
8686
}
8787

8888
Type RequirementFailure::getOwnerType() const {
89-
return getType(getAnchor())->getInOutObjectType()->getMetatypeInstanceType();
89+
return getType(getRawAnchor())
90+
->getInOutObjectType()
91+
->getMetatypeInstanceType();
9092
}
9193

9294
const GenericContext *RequirementFailure::getGenericContext() const {

lib/Sema/CSDiagnostics.h

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ class RequirementFailure : public FailureDiagnostic {
203203
if (!expr)
204204
return;
205205

206-
if (auto *parentExpr = findParentExpr(getAnchor()))
206+
if (auto *parentExpr = findParentExpr(getRawAnchor()))
207207
Apply = dyn_cast<ApplyExpr>(parentExpr);
208208
}
209209

@@ -254,12 +254,31 @@ class RequirementFailure : public FailureDiagnostic {
254254
if (isConditional())
255255
return true;
256256

257+
auto *anchor = getAnchor();
258+
// In the situations like this:
259+
//
260+
// ```swift
261+
// enum E<T: P> { case foo(T) }
262+
// let _: E = .foo(...)
263+
// ```
264+
//
265+
// `E` is going to be opened twice. First, when
266+
// it's used as a contextual type, and when `E.foo`
267+
// is found and its function type is opened.
268+
// We still want to record both fixes but should
269+
// avoid diagnosing the same problem multiple times.
270+
if (isa<UnresolvedMemberExpr>(anchor)) {
271+
auto path = getLocator()->getPath();
272+
if (path.front().getKind() != ConstraintLocator::UnresolvedMember)
273+
return false;
274+
}
275+
257276
// For static/initializer calls there is going to be
258277
// a separate fix, attached to the argument, which is
259278
// much easier to diagnose.
260279
// For operator calls we can't currently produce a good
261280
// diagnostic, so instead let's refer to expression diagnostics.
262-
return !(Apply && (isOperator(Apply) || isa<TypeExpr>(getAnchor())));
281+
return !(Apply && (isOperator(Apply) || isa<TypeExpr>(anchor)));
263282
}
264283

265284
static bool isOperator(const ApplyExpr *apply) {

lib/Sema/CSSimplify.cpp

Lines changed: 9 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1612,29 +1612,22 @@ static ConstraintFix *fixRequirementFailure(ConstraintSystem &cs, Type type1,
16121612
if (type1->hasDependentMember() || type2->hasDependentMember())
16131613
return nullptr;
16141614

1615-
auto reqPath = path.take_back(2);
1616-
auto req = reqPath.back();
1617-
1618-
ConstraintLocator *reqLoc = nullptr;
1615+
auto req = path.back();
16191616
if (req.isConditionalRequirement()) {
16201617
// path is - ... -> open generic -> type req # -> cond req #,
16211618
// to identify type requirement we only need `open generic -> type req #`
16221619
// part, because that's how fixes for type requirements are recorded.
1623-
reqPath = path.drop_back().take_back(2);
1620+
auto reqPath = path.drop_back();
16241621
// If underlying conformance requirement has been fixed,
16251622
// then there is no reason to fix up conditional requirements.
16261623
if (cs.hasFixFor(cs.getConstraintLocator(anchor, reqPath,
16271624
/*summaryFlags=*/0)))
16281625
return nullptr;
1629-
1630-
// For conditional requirements we need a full path.
1631-
reqLoc = cs.getConstraintLocator(anchor, path, /*summaryFlags=*/0);
1632-
} else {
1633-
// Build simplified locator which only contains anchor and requirement info.
1634-
reqLoc = cs.getConstraintLocator(anchor, reqPath,
1635-
/*summaryFlags=*/0);
16361626
}
16371627

1628+
auto *reqLoc = cs.getConstraintLocator(anchor, path,
1629+
/*summaryFlags=*/0);
1630+
16381631
auto reqKind = static_cast<RequirementKind>(req.getValue2());
16391632
switch (reqKind) {
16401633
case RequirementKind::SameType: {
@@ -2789,32 +2782,20 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
27892782

27902783
if (path.back().isTypeParameterRequirement() ||
27912784
path.back().isConditionalRequirement()) {
2792-
ConstraintLocator *reqLoc = nullptr;
27932785
if (path.back().isConditionalRequirement()) {
2794-
// Drop 'conditional requirement' element remainder
2786+
// Drop 'conditional requirement' element, remainder
27952787
// of the path is going to point to type requirement
27962788
// this conditional comes from.
27972789
auto reqPath = ArrayRef<LocatorPathElt>(path).drop_back();
27982790
// Underlying conformance requirement is itself fixed,
27992791
// this wouldn't lead to a right solution.
2800-
if (hasFixFor(getConstraintLocator(anchor, reqPath.take_back(2),
2792+
if (hasFixFor(getConstraintLocator(anchor, reqPath,
28012793
/*summaryFlags=*/0)))
28022794
return SolutionKind::Error;
2803-
2804-
// For conditional requirements we need complete path, which includes
2805-
// type requirement position, to be able to fetch conformance later.
2806-
reqLoc = getConstraintLocator(locator);
2807-
} else {
2808-
// Let's strip all of the unnecessary information from locator,
2809-
// diagnostics only care about anchor - to lookup type,
2810-
// generic signature where requirement comes from, and
2811-
// what was the requirement# which is not satisfied.
2812-
auto reqPath = ArrayRef<LocatorPathElt>(path).take_back(2);
2813-
reqLoc = getConstraintLocator(anchor, reqPath,
2814-
/*summaryFlags=*/0);
28152795
}
28162796

2817-
auto *fix = MissingConformance::create(*this, type, protocol, reqLoc);
2797+
auto *fix = MissingConformance::create(*this, type, protocol,
2798+
getConstraintLocator(locator));
28182799
if (!recordFix(fix))
28192800
return SolutionKind::Solved;
28202801
}

0 commit comments

Comments
 (0)