Skip to content

Commit effd0d0

Browse files
authored
Merge pull request #26302 from xedin/remove-label-mismatch-from-lookup
[Diagnostics] Don't filter overload set candidates based on labels in lookup
2 parents 3f6e367 + 1b4f9c3 commit effd0d0

21 files changed

+209
-166
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1051,6 +1051,9 @@ ERROR(argument_out_of_order_unnamed_named,none,
10511051
ERROR(argument_out_of_order_unnamed_unnamed,none,
10521052
"unnamed argument #%0 must precede unnamed argument #%1",
10531053
(unsigned, unsigned))
1054+
NOTE(candidate_expected_different_labels,none,
1055+
"incorrect labels for candidate (have: '%0', expected: '%1')",
1056+
(StringRef, StringRef))
10541057

10551058
ERROR(member_shadows_global_function,none,
10561059
"use of %0 refers to %1 %2 rather than %3 %4 in %5 %6",

lib/Sema/CSDiag.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -741,7 +741,6 @@ void FailureDiagnosis::diagnoseUnviableLookupResults(
741741
return;
742742

743743
switch (firstProblem) {
744-
case MemberLookupResult::UR_LabelMismatch:
745744
case MemberLookupResult::UR_WritableKeyPathOnReadOnlyMember:
746745
case MemberLookupResult::UR_ReferenceWritableKeyPathOnMutatingMember:
747746
case MemberLookupResult::UR_KeyPathWithAnyObjectRootType:
@@ -4192,7 +4191,7 @@ bool FailureDiagnosis::diagnoseTrailingClosureErrors(ApplyExpr *callExpr) {
41924191
};
41934192

41944193
SmallPtrSet<TypeBase *, 4> possibleTypes;
4195-
auto currentType = CS.getType(fnExpr);
4194+
auto currentType = CS.simplifyType(CS.getType(fnExpr));
41964195

41974196
// If current type has type variables or unresolved types
41984197
// let's try to re-typecheck it to see if we can get some

lib/Sema/CSDiagnostics.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "swift/Parse/Lexer.h"
3434
#include "llvm/ADT/ArrayRef.h"
3535
#include "llvm/ADT/SmallString.h"
36+
#include <string>
3637

3738
using namespace swift;
3839
using namespace constraints;
@@ -691,6 +692,46 @@ bool LabelingFailure::diagnoseAsError() {
691692
isa<SubscriptExpr>(anchor));
692693
}
693694

695+
bool LabelingFailure::diagnoseAsNote() {
696+
auto *anchor = getRawAnchor();
697+
698+
auto *argExpr = getArgumentExprFor(anchor);
699+
if (!argExpr)
700+
return false;
701+
702+
SmallVector<Identifier, 4> argLabels;
703+
if (auto *paren = dyn_cast<ParenExpr>(argExpr)) {
704+
argLabels.push_back(Identifier());
705+
} else if (auto *tuple = dyn_cast<TupleExpr>(argExpr)) {
706+
argLabels.append(tuple->getElementNames().begin(),
707+
tuple->getElementNames().end());
708+
} else {
709+
return false;
710+
}
711+
712+
auto stringifyLabels = [](ArrayRef<Identifier> labels) -> std::string {
713+
std::string str;
714+
for (auto label : labels) {
715+
str += label.empty() ? "_" : label.str();
716+
str += ':';
717+
}
718+
return "(" + str + ")";
719+
};
720+
721+
auto selectedOverload = getChoiceFor(anchor);
722+
if (!selectedOverload)
723+
return false;
724+
725+
const auto &choice = selectedOverload->choice;
726+
if (auto *decl = choice.getDeclOrNull()) {
727+
emitDiagnostic(decl, diag::candidate_expected_different_labels,
728+
stringifyLabels(argLabels), stringifyLabels(CorrectLabels));
729+
return true;
730+
}
731+
732+
return false;
733+
}
734+
694735
bool NoEscapeFuncToTypeConversionFailure::diagnoseAsError() {
695736
auto *anchor = getAnchor();
696737

lib/Sema/CSDiagnostics.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,7 @@ class LabelingFailure final : public FailureDiagnostic {
529529
: FailureDiagnostic(root, cs, locator), CorrectLabels(labels) {}
530530

531531
bool diagnoseAsError() override;
532+
bool diagnoseAsNote() override;
532533
};
533534

534535
/// Diagnose errors related to converting function type which

lib/Sema/CSSimplify.cpp

Lines changed: 70 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -110,36 +110,31 @@ bool constraints::doesMemberRefApplyCurriedSelf(Type baseTy,
110110
// curried self.
111111
if (decl->isInstanceMember()) {
112112
assert(baseTy);
113-
if (isa<AbstractFunctionDecl>(decl) && baseTy->is<AnyMetatypeType>())
113+
if (isa<AbstractFunctionDecl>(decl) &&
114+
baseTy->getRValueType()->is<AnyMetatypeType>())
114115
return false;
115116
}
116117

117118
// Otherwise the reference applies self.
118119
return true;
119120
}
120121

121-
bool constraints::areConservativelyCompatibleArgumentLabels(
122-
OverloadChoice choice,
123-
ArrayRef<Identifier> labels,
124-
bool hasTrailingClosure) {
122+
static bool
123+
areConservativelyCompatibleArgumentLabels(OverloadChoice choice,
124+
ArrayRef<FunctionType::Param> args,
125+
bool hasTrailingClosure) {
125126
ValueDecl *decl = nullptr;
126-
Type baseType;
127127
switch (choice.getKind()) {
128128
case OverloadChoiceKind::Decl:
129129
case OverloadChoiceKind::DeclViaBridge:
130130
case OverloadChoiceKind::DeclViaDynamic:
131131
case OverloadChoiceKind::DeclViaUnwrappedOptional:
132132
decl = choice.getDecl();
133-
baseType = choice.getBaseType();
134-
if (baseType)
135-
baseType = baseType->getRValueType();
136133
break;
137134

138-
case OverloadChoiceKind::KeyPathApplication:
139-
// Key path applications are written as if subscript[keyPath:].
140-
return !hasTrailingClosure && labels.size() == 1 && labels[0].is("keyPath");
141-
142135
case OverloadChoiceKind::BaseType:
136+
// KeyPath application is not filtered in `performMemberLookup`.
137+
case OverloadChoiceKind::KeyPathApplication:
143138
case OverloadChoiceKind::DynamicMemberLookup:
144139
case OverloadChoiceKind::KeyPathDynamicMemberLookup:
145140
case OverloadChoiceKind::TupleIndex:
@@ -149,17 +144,13 @@ bool constraints::areConservativelyCompatibleArgumentLabels(
149144
if (!decl->hasParameterList())
150145
return true;
151146

152-
SmallVector<AnyFunctionType::Param, 8> argInfos;
153-
for (auto argLabel : labels) {
154-
argInfos.push_back(AnyFunctionType::Param(Type(), argLabel, {}));
155-
}
156-
157147
// This is a member lookup, which generally means that the call arguments
158148
// (if we have any) will apply to the second level of parameters, with
159149
// the member lookup applying the curried self at the first level. But there
160150
// are cases where we can get an unapplied declaration reference back.
161151
auto hasAppliedSelf =
162-
decl->hasCurriedSelf() && doesMemberRefApplyCurriedSelf(baseType, decl);
152+
decl->hasCurriedSelf() &&
153+
doesMemberRefApplyCurriedSelf(choice.getBaseType(), decl);
163154

164155
auto *fnType = decl->getInterfaceType()->castTo<AnyFunctionType>();
165156
if (hasAppliedSelf) {
@@ -173,10 +164,9 @@ bool constraints::areConservativelyCompatibleArgumentLabels(
173164
MatchCallArgumentListener listener;
174165
SmallVector<ParamBinding, 8> unusedParamBindings;
175166

176-
return !matchCallArguments(argInfos, params, paramInfo,
177-
hasTrailingClosure,
178-
/*allow fixes*/ false,
179-
listener, unusedParamBindings);
167+
return !matchCallArguments(args, params, paramInfo, hasTrailingClosure,
168+
/*allow fixes*/ false, listener,
169+
unusedParamBindings);
180170
}
181171

182172
Expr *constraints::getArgumentLabelTargetExpr(Expr *fn) {
@@ -873,14 +863,19 @@ getCalleeDeclAndArgs(ConstraintSystem &cs,
873863

874864
class ArgumentFailureTracker : public MatchCallArgumentListener {
875865
ConstraintSystem &CS;
866+
ArrayRef<AnyFunctionType::Param> Arguments;
867+
ArrayRef<AnyFunctionType::Param> Parameters;
876868
SmallVectorImpl<ParamBinding> &Bindings;
877869
ConstraintLocatorBuilder Locator;
878870

879871
public:
880872
ArgumentFailureTracker(ConstraintSystem &cs,
873+
ArrayRef<AnyFunctionType::Param> args,
874+
ArrayRef<AnyFunctionType::Param> params,
881875
SmallVectorImpl<ParamBinding> &bindings,
882876
ConstraintLocatorBuilder locator)
883-
: CS(cs), Bindings(bindings), Locator(locator) {}
877+
: CS(cs), Arguments(args), Parameters(params), Bindings(bindings),
878+
Locator(locator) {}
884879

885880
bool missingLabel(unsigned paramIndex) override {
886881
return !CS.shouldAttemptFixes();
@@ -912,9 +907,27 @@ class ArgumentFailureTracker : public MatchCallArgumentListener {
912907
if (!anchor)
913908
return true;
914909

910+
unsigned numExtraneous = 0;
911+
for (unsigned paramIdx = 0, n = Bindings.size(); paramIdx != n;
912+
++paramIdx) {
913+
if (Bindings[paramIdx].empty())
914+
continue;
915+
916+
const auto paramLabel = Parameters[paramIdx].getLabel();
917+
for (auto argIdx : Bindings[paramIdx]) {
918+
auto argLabel = Arguments[argIdx].getLabel();
919+
if (paramLabel.empty() && !argLabel.empty())
920+
++numExtraneous;
921+
}
922+
}
923+
915924
auto *locator = CS.getConstraintLocator(anchor);
916925
auto *fix = RelabelArguments::create(CS, newLabels, locator);
917926
CS.recordFix(fix);
927+
// Re-labeling fixes with extraneous labels should take
928+
// lower priority vs. other fixes on same/different
929+
// overload(s) where labels did line up correctly.
930+
CS.increaseScore(ScoreKind::SK_Fix, numExtraneous);
918931
return false;
919932
}
920933
};
@@ -944,7 +957,8 @@ ConstraintSystem::TypeMatchResult constraints::matchCallArguments(
944957

945958
// Match up the call arguments to the parameters.
946959
SmallVector<ParamBinding, 4> parameterBindings;
947-
ArgumentFailureTracker listener(cs, parameterBindings, locator);
960+
ArgumentFailureTracker listener(cs, argsWithLabels, params, parameterBindings,
961+
locator);
948962
if (constraints::matchCallArguments(argsWithLabels, params,
949963
paramInfo,
950964
hasTrailingClosure,
@@ -4175,19 +4189,15 @@ performMemberLookup(ConstraintKind constraintKind, DeclName memberName,
41754189

41764190
// If we have a simple name, determine whether there are argument
41774191
// labels we can use to restrict the set of lookup results.
4178-
Optional<ArgumentLabelState> argumentLabels;
4179-
if (memberName.isSimpleName()) {
4180-
argumentLabels = getArgumentLabels(*this,
4181-
ConstraintLocatorBuilder(memberLocator));
4182-
4192+
if (baseObjTy->isAnyObject() && memberName.isSimpleName()) {
41834193
// If we're referencing AnyObject and we have argument labels, put
41844194
// the argument labels into the name: we don't want to look for
41854195
// anything else, because the cost of the general search is so
41864196
// high.
4187-
if (baseObjTy->isAnyObject() && argumentLabels) {
4197+
if (auto argumentLabels =
4198+
getArgumentLabels(*this, ConstraintLocatorBuilder(memberLocator))) {
41884199
memberName = DeclName(TC.Context, memberName.getBaseName(),
41894200
argumentLabels->Labels);
4190-
argumentLabels.reset();
41914201
}
41924202
}
41934203

@@ -4226,7 +4236,6 @@ performMemberLookup(ConstraintKind constraintKind, DeclName memberName,
42264236
bridgedType = classType;
42274237
}
42284238
}
4229-
bool labelMismatch = false;
42304239

42314240
// Local function that adds the given declaration if it is a
42324241
// reasonable choice.
@@ -4291,20 +4300,6 @@ performMemberLookup(ConstraintKind constraintKind, DeclName memberName,
42914300
hasInstanceMethods = true;
42924301
}
42934302

4294-
// If the argument labels for this result are incompatible with
4295-
// the call site, skip it.
4296-
// FIXME: The subscript check here forces the use of the
4297-
// function-application simplification logic to handle labels.
4298-
if (argumentLabels &&
4299-
(!candidate.isDecl() || !isa<SubscriptDecl>(candidate.getDecl())) &&
4300-
!areConservativelyCompatibleArgumentLabels(
4301-
candidate, argumentLabels->Labels,
4302-
argumentLabels->HasTrailingClosure)) {
4303-
labelMismatch = true;
4304-
result.addUnviable(candidate, MemberLookupResult::UR_LabelMismatch);
4305-
return;
4306-
}
4307-
43084303
// If our base is an existential type, we can't make use of any
43094304
// member whose signature involves associated types.
43104305
if (instanceTy->isExistentialType()) {
@@ -4494,8 +4489,6 @@ performMemberLookup(ConstraintKind constraintKind, DeclName memberName,
44944489
};
44954490

44964491
// Add all results from this lookup.
4497-
retry_after_fail:
4498-
labelMismatch = false;
44994492
for (auto result : lookup)
45004493
addChoice(getOverloadChoice(result.getValueDecl(),
45014494
/*isBridged=*/false,
@@ -4603,14 +4596,6 @@ performMemberLookup(ConstraintKind constraintKind, DeclName memberName,
46034596
}
46044597
}
46054598

4606-
// If we rejected some possibilities due to an argument-label
4607-
// mismatch and ended up with nothing, try again ignoring the
4608-
// labels. This allows us to perform typo correction on the labels.
4609-
if (result.ViableCandidates.empty() && labelMismatch && shouldAttemptFixes()){
4610-
argumentLabels.reset();
4611-
goto retry_after_fail;
4612-
}
4613-
46144599
// If we have no viable or unviable candidates, and we're generating,
46154600
// diagnostics, rerun the query with inaccessible members included, so we can
46164601
// include them in the unviable candidates list.
@@ -4855,7 +4840,6 @@ fixMemberRef(ConstraintSystem &cs, Type baseTy,
48554840
: nullptr;
48564841
}
48574842

4858-
case MemberLookupResult::UR_LabelMismatch:
48594843
// TODO(diagnostics): Add a new fix that is suggests to
48604844
// add `subscript(dynamicMember: {Writable}KeyPath<T, U>)`
48614845
// overload here, that would help if such subscript has
@@ -5882,7 +5866,6 @@ ConstraintSystem::simplifyKeyPathApplicationConstraint(
58825866
Type ConstraintSystem::simplifyAppliedOverloads(
58835867
TypeVariableType *fnTypeVar,
58845868
const FunctionType *argFnType,
5885-
Optional<ArgumentLabelState> argumentLabels,
58865869
ConstraintLocatorBuilder locator) {
58875870
Type fnType(fnTypeVar);
58885871

@@ -5923,6 +5906,8 @@ Type ConstraintSystem::simplifyAppliedOverloads(
59235906
return markFailure();
59245907
};
59255908

5909+
auto argumentInfo = getArgumentLabels(*this, locator);
5910+
59265911
// Consider each of the constraints in the disjunction.
59275912
retry_after_fail:
59285913
bool hasUnhandledConstraints = false;
@@ -5936,12 +5921,18 @@ Type ConstraintSystem::simplifyAppliedOverloads(
59365921

59375922
// Determine whether the argument labels we have conflict with those of
59385923
// this overload choice.
5939-
if (argumentLabels &&
5940-
!areConservativelyCompatibleArgumentLabels(
5941-
choice, argumentLabels->Labels,
5942-
argumentLabels->HasTrailingClosure)) {
5943-
labelMismatch = true;
5944-
return false;
5924+
if (argumentInfo) {
5925+
auto args = argFnType->getParams();
5926+
5927+
SmallVector<FunctionType::Param, 8> argsWithLabels;
5928+
argsWithLabels.append(args.begin(), args.end());
5929+
FunctionType::relabelParams(argsWithLabels, argumentInfo->Labels);
5930+
5931+
if (!areConservativelyCompatibleArgumentLabels(
5932+
choice, argsWithLabels, argumentInfo->HasTrailingClosure)) {
5933+
labelMismatch = true;
5934+
return false;
5935+
}
59455936
}
59465937

59475938
// Determine the type that this choice will have.
@@ -5968,7 +5959,7 @@ Type ConstraintSystem::simplifyAppliedOverloads(
59685959
switch (filterResult) {
59695960
case SolutionKind::Error:
59705961
if (labelMismatch && shouldAttemptFixes()) {
5971-
argumentLabels = None;
5962+
argumentInfo.reset();
59725963
goto retry_after_fail;
59735964
}
59745965

@@ -6081,16 +6072,20 @@ ConstraintSystem::simplifyApplicableFnConstraint(
60816072

60826073
};
60836074

6084-
// If the right-hand side is a type variable, try to simplify the overload
6085-
// set.
6086-
if (auto typeVar = desugar2->getAs<TypeVariableType>()) {
6087-
auto argumentLabels = getArgumentLabels(*this, locator);
6088-
Type newType2 =
6089-
simplifyAppliedOverloads(typeVar, func1, argumentLabels, locator);
6090-
if (!newType2)
6091-
return SolutionKind::Error;
6075+
// Don't attempt this optimization in "diagnostic mode" because
6076+
// in such mode we'd like to attempt all of the available
6077+
// overloads regardless of of problems related to missing or
6078+
// extraneous labels and/or arguments.
6079+
if (!(solverState && shouldAttemptFixes())) {
6080+
// If the right-hand side is a type variable,
6081+
// try to simplify the overload set.
6082+
if (auto typeVar = desugar2->getAs<TypeVariableType>()) {
6083+
Type newType2 = simplifyAppliedOverloads(typeVar, func1, locator);
6084+
if (!newType2)
6085+
return SolutionKind::Error;
60926086

6093-
desugar2 = newType2->getDesugaredType();
6087+
desugar2 = newType2->getDesugaredType();
6088+
}
60946089
}
60956090

60966091
// If right-hand side is a type variable, the constraint is unsolved.

0 commit comments

Comments
 (0)