Skip to content

Commit 53a9b1f

Browse files
authored
Merge pull request swiftlang#23312 from xedin/form-complete-member-overload-sets
[ConstraintSystem] Include unviable-by-fixable choices into member overload sets
2 parents 892c406 + 852169a commit 53a9b1f

File tree

11 files changed

+72
-62
lines changed

11 files changed

+72
-62
lines changed

lib/Sema/CSDiag.cpp

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -791,15 +791,19 @@ void FailureDiagnosis::diagnoseUnviableLookupResults(
791791
// Otherwise, we have at least one (and potentially many) viable candidates
792792
// sort them out. If all of the candidates have the same problem (commonly
793793
// because there is exactly one candidate!) diagnose this.
794-
bool sameProblem = true;
795-
auto firstProblem = result.UnviableCandidates[0].second;
794+
auto firstProblem = result.UnviableReasons[0];
795+
bool sameProblem = llvm::all_of(
796+
result.UnviableReasons,
797+
[&firstProblem](const MemberLookupResult::UnviableReason &problem) {
798+
return problem == firstProblem;
799+
});
800+
796801
ValueDecl *member = nullptr;
797802
for (auto cand : result.UnviableCandidates) {
798803
if (member == nullptr)
799-
member = cand.first.getDecl();
800-
sameProblem &= cand.second == firstProblem;
804+
member = cand.getDecl();
801805
}
802-
806+
803807
auto instanceTy = baseObjTy;
804808
if (auto *MTT = instanceTy->getAs<AnyMetatypeType>())
805809
instanceTy = MTT->getInstanceType();
@@ -842,7 +846,7 @@ void FailureDiagnosis::diagnoseUnviableLookupResults(
842846
}
843847

844848
case MemberLookupResult::UR_Inaccessible: {
845-
auto decl = result.UnviableCandidates[0].first.getDecl();
849+
auto decl = result.UnviableCandidates[0].getDecl();
846850
// FIXME: What if the unviable candidates have different levels of access?
847851
//
848852
// If we found an inaccessible member of a protocol extension, it might
@@ -853,8 +857,8 @@ void FailureDiagnosis::diagnoseUnviableLookupResults(
853857
diagnose(nameLoc, diag::candidate_inaccessible, decl->getBaseName(),
854858
decl->getFormalAccessScope().accessLevelForDiagnostics());
855859
for (auto cand : result.UnviableCandidates)
856-
diagnose(cand.first.getDecl(), diag::decl_declared_here, memberName);
857-
860+
diagnose(cand.getDecl(), diag::decl_declared_here, memberName);
861+
858862
return;
859863
}
860864
}
@@ -4206,7 +4210,7 @@ bool FailureDiagnosis::diagnoseMethodAttributeFailures(
42064210

42074211
SmallVector<OverloadChoice, 2> choices;
42084212
for (auto &unviable : results.UnviableCandidates)
4209-
choices.push_back(OverloadChoice(baseType, unviable.first.getDecl(),
4213+
choices.push_back(OverloadChoice(baseType, unviable.getDecl(),
42104214
UDE->getFunctionRefKind()));
42114215

42124216
CalleeCandidateInfo unviableCandidates(baseType, choices, hasTrailingClosure,

lib/Sema/CSGen.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3749,7 +3749,7 @@ swift::resolveValueMember(DeclContext &DC, Type BaseTy, DeclName Name) {
37493749

37503750
// Keep track of all the unviable members.
37513751
for (auto Can : LookupResult.UnviableCandidates)
3752-
Result.Impl.AllDecls.push_back(Can.first.getDecl());
3752+
Result.Impl.AllDecls.push_back(Can.getDecl());
37533753

37543754
// Keep track of the start of viable choices.
37553755
Result.Impl.ViableStartIdx = Result.Impl.AllDecls.size();

lib/Sema/CSSimplify.cpp

Lines changed: 27 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3753,8 +3753,15 @@ performMemberLookup(ConstraintKind constraintKind, DeclName memberName,
37533753
if (decl->isInstanceMember()) {
37543754
if ((isa<FuncDecl>(decl) && !hasInstanceMethods) ||
37553755
(!isa<FuncDecl>(decl) && !hasInstanceMembers)) {
3756-
result.addUnviable(candidate,
3757-
MemberLookupResult::UR_InstanceMemberOnType);
3756+
// `AnyObject` has special semantics, so let's just let it be.
3757+
// Otherwise adjust base type and reference kind to make it
3758+
// look as if lookup was done on the instance, that helps
3759+
// with diagnostics.
3760+
auto choice = instanceTy->isAnyObject()
3761+
? candidate
3762+
: OverloadChoice(instanceTy, decl,
3763+
FunctionRefKind::SingleApply);
3764+
result.addUnviable(choice, MemberLookupResult::UR_InstanceMemberOnType);
37583765
return;
37593766
}
37603767

@@ -3926,10 +3933,10 @@ performMemberLookup(ConstraintKind constraintKind, DeclName memberName,
39263933
result.addViable(
39273934
OverloadChoice::getDynamicMemberLookup(baseTy, decl, name));
39283935
}
3929-
for (auto candidate : subscripts.UnviableCandidates) {
3930-
auto decl = candidate.first.getDecl();
3936+
for (auto index : indices(subscripts.UnviableCandidates)) {
3937+
auto decl = subscripts.UnviableCandidates[index].getDecl();
39313938
auto choice = OverloadChoice::getDynamicMemberLookup(baseTy, decl,name);
3932-
result.addUnviable(choice, candidate.second);
3939+
result.addUnviable(choice, subscripts.UnviableReasons[index]);
39333940
}
39343941
}
39353942
}
@@ -4203,9 +4210,9 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint(
42034210
break;
42044211
}
42054212

4213+
SmallVector<Constraint *, 4> candidates;
42064214
// If we found viable candidates, then we're done!
42074215
if (!result.ViableCandidates.empty()) {
4208-
llvm::SmallVector<Constraint *, 8> candidates;
42094216
generateConstraints(
42104217
candidates, memberTy, result.ViableCandidates, useDC, locator,
42114218
result.getFavoredIndex(), /*requiresFix=*/false,
@@ -4222,11 +4229,24 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint(
42224229
generateConstraints(candidates, memberTy, outerAlternatives,
42234230
useDC, locator);
42244231
}
4232+
}
4233+
4234+
if (!result.UnviableCandidates.empty()) {
4235+
// Generate constraints for unvailable choices if they have a fix,
4236+
// and disable them by default, they'd get picked up in the "salvage" mode.
4237+
generateConstraints(
4238+
candidates, memberTy, result.UnviableCandidates, useDC, locator,
4239+
/*favoredChoice=*/None, /*requiresFix=*/true,
4240+
[&](unsigned idx, const OverloadChoice &choice) {
4241+
return fixMemberRef(*this, baseTy, member, choice, locator,
4242+
result.UnviableReasons[idx]);
4243+
});
4244+
}
42254245

4246+
if (!candidates.empty()) {
42264247
addOverloadSet(candidates, locator);
42274248
return SolutionKind::Solved;
42284249
}
4229-
42304250

42314251
// If the lookup found no hits at all (either viable or unviable), diagnose it
42324252
// as such and try to recover in various ways.
@@ -4238,30 +4258,6 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint(
42384258
if (!MissingMembers.insert(locator))
42394259
return SolutionKind::Error;
42404260

4241-
if (!result.UnviableCandidates.empty()) {
4242-
SmallVector<OverloadChoice, 8> choices;
4243-
llvm::transform(
4244-
result.UnviableCandidates, std::back_inserter(choices),
4245-
[](const std::pair<OverloadChoice, MemberLookupResult::UnviableReason>
4246-
&candidate) { return candidate.first; });
4247-
4248-
SmallVector<Constraint *, 4> candidates;
4249-
generateConstraints(candidates, memberTy, choices, useDC, locator,
4250-
/*favoredChoice=*/None, /*requiresFix=*/true,
4251-
[&](unsigned idx, const OverloadChoice &choice) {
4252-
return fixMemberRef(
4253-
*this, baseTy, member, choice, locator,
4254-
result.UnviableCandidates[idx].second);
4255-
});
4256-
4257-
// If there are any viable "fixed" candidates, let's schedule
4258-
// them to be attempted.
4259-
if (!candidates.empty()) {
4260-
addOverloadSet(candidates, locator);
4261-
return SolutionKind::Solved;
4262-
}
4263-
}
4264-
42654261
if (baseObjTy->getOptionalObjectType()) {
42664262
// If the base type was an optional, look through it.
42674263

lib/Sema/CSSolver.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1305,8 +1305,10 @@ ConstraintSystem::filterDisjunction(
13051305
for (unsigned constraintIdx : indices(disjunction->getNestedConstraints())) {
13061306
auto constraint = disjunction->getNestedConstraints()[constraintIdx];
13071307

1308-
// Skip already-disabled constraints.
1309-
if (constraint->isDisabled())
1308+
// Skip already-disabled constraints. Let's treat disabled
1309+
// choices which have a fix as "enabled" ones here, so we can
1310+
// potentially infer some type information from them.
1311+
if (constraint->isDisabled() && !constraint->getFix())
13101312
continue;
13111313

13121314
if (pred(constraint)) {

lib/Sema/CSStep.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,9 @@ StepResult DisjunctionStep::resume(bool prevFailed) {
430430
bool DisjunctionStep::shouldSkip(const DisjunctionChoice &choice) const {
431431
auto &ctx = CS.getASTContext();
432432

433-
if (choice.isDisabled()) {
433+
bool attemptFixes = CS.shouldAttemptFixes();
434+
// Enable "fixed" overload choices in "diagnostic" mode.
435+
if (!(attemptFixes && choice.hasFix()) && choice.isDisabled()) {
434436
if (isDebugMode()) {
435437
auto &log = getDebugLogger();
436438
log << "(skipping ";
@@ -442,7 +444,7 @@ bool DisjunctionStep::shouldSkip(const DisjunctionChoice &choice) const {
442444
}
443445

444446
// Skip unavailable overloads unless solver is in the "diagnostic" mode.
445-
if (!CS.shouldAttemptFixes() && choice.isUnavailable())
447+
if (!attemptFixes && choice.isUnavailable())
446448
return true;
447449

448450
if (ctx.LangOpts.DisableConstraintSolverPerformanceHacks)

lib/Sema/Constraint.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ Constraint::Constraint(Type type, OverloadChoice choice, DeclContext *useDC,
169169
ConstraintFix *fix, ConstraintLocator *locator,
170170
ArrayRef<TypeVariableType *> typeVars)
171171
: Kind(ConstraintKind::BindOverload), TheFix(fix), HasRestriction(false),
172-
IsActive(false), IsDisabled(false), RememberChoice(false),
172+
IsActive(false), IsDisabled(bool(fix)), RememberChoice(false),
173173
IsFavored(false),
174174
NumTypeVariables(typeVars.size()), Overload{type, choice, useDC},
175175
Locator(locator) {

lib/Sema/Constraint.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,7 @@ class Constraint final : public llvm::ilist_node<Constraint>,
401401
ConstraintLocator *locator);
402402

403403
/// Create a bind overload choice with a fix.
404+
/// Note: This constraint is going to be disabled by default.
404405
static Constraint *createFixedChoice(ConstraintSystem &cs, Type type,
405406
OverloadChoice choice,
406407
DeclContext *useDC, ConstraintFix *fix,

lib/Sema/ConstraintSystem.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2525,10 +2525,9 @@ void ConstraintSystem::generateConstraints(
25252525
}
25262526

25272527
for (auto index : indices(choices)) {
2528-
const auto &choice = choices[index];
25292528
if (favoredIndex && (*favoredIndex == index))
25302529
continue;
25312530

2532-
recordChoice(constraints, index, choice);
2531+
recordChoice(constraints, index, choices[index]);
25332532
}
25342533
}

lib/Sema/ConstraintSystem.h

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -873,11 +873,12 @@ struct MemberLookupResult {
873873
/// The member is inaccessible (e.g. a private member in another file).
874874
UR_Inaccessible,
875875
};
876-
877-
/// This is a list of considered (but rejected) candidates, along with a
878-
/// reason for their rejection.
879-
SmallVector<std::pair<OverloadChoice, UnviableReason>, 4> UnviableCandidates;
880876

877+
/// This is a list of considered (but rejected) candidates, along with a
878+
/// reason for their rejection. Split into separate collections to make
879+
/// it easier to use in conjunction with viable candidates.
880+
SmallVector<OverloadChoice, 4> UnviableCandidates;
881+
SmallVector<UnviableReason, 4> UnviableReasons;
881882

882883
/// Mark this as being an already-diagnosed error and return itself.
883884
MemberLookupResult &markErrorAlreadyDiagnosed() {
@@ -890,7 +891,8 @@ struct MemberLookupResult {
890891
}
891892

892893
void addUnviable(OverloadChoice candidate, UnviableReason reason) {
893-
UnviableCandidates.push_back({candidate, reason});
894+
UnviableCandidates.push_back(candidate);
895+
UnviableReasons.push_back(reason);
894896
}
895897

896898
Optional<unsigned> getFavoredIndex() const {
@@ -2474,7 +2476,7 @@ class ConstraintSystem {
24742476
/// \param requiresFix Determines whether choices require a fix to
24752477
/// be included in the result. If the fix couldn't be provided by
24762478
/// `getFix` for any given choice, such choice would be filtered out.
2477-
////
2479+
///
24782480
/// \param getFix Optional callback to determine a fix for a given
24792481
/// choice (first argument is a position of current choice,
24802482
/// second - the choice in question).
@@ -3678,6 +3680,10 @@ class DisjunctionChoice {
36783680

36793681
bool isDisabled() const { return Choice->isDisabled(); }
36803682

3683+
bool hasFix() const {
3684+
return bool(Choice->getFix());
3685+
}
3686+
36813687
bool isUnavailable() const {
36823688
if (auto *decl = getDecl(Choice))
36833689
return decl->getAttrs().isUnavailable(decl->getASTContext());

test/Constraints/members.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -359,19 +359,19 @@ extension Sequence {
359359
}
360360

361361
class C_25341015 {
362-
static func baz(_ x: Int, _ y: Int) {} // expected-note {{'baz' declared here}}
362+
static func baz(_ x: Int, _ y: Int) {}
363363
func baz() {}
364364
func qux() {
365-
baz(1, 2) // expected-error {{use of 'baz' refers to instance method 'baz()' rather than static method 'baz' in class 'C_25341015'}} expected-note {{use 'C_25341015.' to reference the static method}}
365+
baz(1, 2) // expected-error {{static member 'baz' cannot be used on instance of type 'C_25341015'}} {{5-5=C_25341015.}}
366366
}
367367
}
368368

369369
struct S_25341015 {
370-
static func foo(_ x: Int, y: Int) {} // expected-note {{'foo(_:y:)' declared here}}
370+
static func foo(_ x: Int, y: Int) {}
371371

372372
func foo(z: Int) {}
373373
func bar() {
374-
foo(1, y: 2) // expected-error {{use of 'foo' refers to instance method 'foo(z:)' rather than static method 'foo(_:y:)' in struct 'S_25341015'}} expected-note {{use 'S_25341015.' to reference the static method}}
374+
foo(1, y: 2) // expected-error {{static member 'foo' cannot be used on instance of type 'S_25341015'}} {{5-5=S_25341015.}}
375375
}
376376
}
377377

0 commit comments

Comments
 (0)