Skip to content

Commit 62eccd5

Browse files
committed
[ConstraintSystem] Use fixes to diagnose missing argument labels
Let the solver disregard missing argument labels and record correct ones, so such problem could be diagnosed later on iff there were no other more serious failures.
1 parent df22c36 commit 62eccd5

File tree

7 files changed

+82
-3
lines changed

7 files changed

+82
-3
lines changed

lib/Sema/CSApply.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8101,6 +8101,13 @@ bool ConstraintSystem::applySolutionFix(Expr *expr,
81018101
getASTContext().TheAnyType);
81028102
return true;
81038103
}
8104+
8105+
case FixKind::RelabelArguments: {
8106+
auto *call = cast<CallExpr>(locator->getAnchor());
8107+
return diagnoseArgumentLabelError(getASTContext(), call->getArg(),
8108+
fix.first.getArgumentLabels(*this),
8109+
isa<SubscriptExpr>(call->getFn()));
8110+
}
81048111
}
81058112

81068113
// FIXME: It would be really nice to emit a follow-up note showing where

lib/Sema/CSSimplify.cpp

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,15 @@ matchCallArguments(ArrayRef<AnyFunctionType::Param> args,
499499
auto fromArgIdx = boundArgIdx;
500500
auto toArgIdx = argIdx;
501501

502+
// If there is no re-ordering going on, and index is past
503+
// the number of parameters, it could only mean that this
504+
// is variadic parameter, so let's just move on.
505+
if (fromArgIdx == toArgIdx && toArgIdx >= params.size()) {
506+
assert(args[fromArgIdx].getLabel().empty());
507+
argIdx++;
508+
continue;
509+
}
510+
502511
// First let's double check if out-of-order argument is nothing
503512
// more than a simple label mismatch, because in situation where
504513
// one argument requires label and another one doesn't, but caller
@@ -692,6 +701,32 @@ getCalleeDeclAndArgs(ConstraintSystem &cs,
692701
return std::make_tuple(nullptr, 0, argLabels, hasTrailingClosure);
693702
}
694703

704+
class ArgumentFailureTracker : public MatchCallArgumentListener {
705+
ConstraintSystem &CS;
706+
ConstraintLocatorBuilder Locator;
707+
708+
public:
709+
ArgumentFailureTracker(ConstraintSystem &cs, ConstraintLocatorBuilder locator)
710+
: CS(cs), Locator(locator) {}
711+
712+
bool missingLabel(unsigned paramIndex) override {
713+
return !CS.shouldAttemptFixes();
714+
}
715+
716+
bool relabelArguments(ArrayRef<Identifier> newLabels) override {
717+
if (!CS.shouldAttemptFixes())
718+
return true;
719+
720+
auto *anchor = Locator.getBaseLocator()->getAnchor();
721+
if (!anchor || !isa<CallExpr>(anchor))
722+
return true;
723+
724+
CS.recordFix(Fix::fixArgumentLabels(CS, newLabels),
725+
CS.getConstraintLocator(anchor));
726+
return false;
727+
}
728+
};
729+
695730
// Match the argument of a call to the parameter.
696731
static ConstraintSystem::TypeMatchResult
697732
matchCallArguments(ConstraintSystem &cs, ConstraintKind kind,
@@ -747,7 +782,7 @@ matchCallArguments(ConstraintSystem &cs, ConstraintKind kind,
747782
auto args = decomposeArgType(argType, argLabels);
748783

749784
// Match up the call arguments to the parameters.
750-
MatchCallArgumentListener listener;
785+
ArgumentFailureTracker listener(cs, locator);
751786
SmallVector<ParamBinding, 4> parameterBindings;
752787
if (constraints::matchCallArguments(args, params,
753788
defaultMap,
@@ -4910,6 +4945,7 @@ ConstraintSystem::simplifyFixConstraint(Fix fix, Type type1, Type type2,
49104945
case FixKind::ExplicitlyEscaping:
49114946
case FixKind::ExplicitlyEscapingToAny:
49124947
case FixKind::CoerceToCheckedCast:
4948+
case FixKind::RelabelArguments:
49134949
llvm_unreachable("handled elsewhere");
49144950
}
49154951

lib/Sema/Constraint.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,13 @@ Fix Fix::getUnwrapOptionalBase(ConstraintSystem &cs, DeclName memberName) {
493493
return Fix(FixKind::UnwrapOptionalBase, index);
494494
}
495495

496+
Fix Fix::fixArgumentLabels(ConstraintSystem &cs,
497+
ArrayRef<Identifier> newLabels) {
498+
unsigned index = cs.FixedArgLabels.size();
499+
cs.FixedArgLabels.push_back(newLabels);
500+
return Fix(FixKind::RelabelArguments, index);
501+
}
502+
496503
Type Fix::getTypeArgument(ConstraintSystem &cs) const {
497504
assert(getKind() == FixKind::ForceDowncast);
498505
return cs.FixedTypes[Data];
@@ -504,6 +511,11 @@ DeclName Fix::getDeclNameArgument(ConstraintSystem &cs) const {
504511
return cs.FixedDeclNames[Data];
505512
}
506513

514+
ArrayRef<Identifier> Fix::getArgumentLabels(ConstraintSystem &cs) const {
515+
assert(getKind() == FixKind::RelabelArguments);
516+
return cs.FixedArgLabels[Data];
517+
}
518+
507519
StringRef Fix::getName(FixKind kind) {
508520
switch (kind) {
509521
case FixKind::ForceOptional:
@@ -519,6 +531,8 @@ StringRef Fix::getName(FixKind kind) {
519531
case FixKind::ExplicitlyEscaping:
520532
case FixKind::ExplicitlyEscapingToAny:
521533
return "fix: add @escaping";
534+
case FixKind::RelabelArguments:
535+
return "fix: re-label argument(s)";
522536
}
523537

524538
llvm_unreachable("Unhandled FixKind in switch.");

lib/Sema/Constraint.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,10 @@ enum class FixKind : uint8_t {
249249
ExplicitlyEscaping,
250250
/// Mark function type as explicitly '@escaping' to be convertable to 'Any'.
251251
ExplicitlyEscapingToAny,
252+
253+
/// Arguments have labeling failures - missing/extraneous or incorrect
254+
/// labels attached to the, fix it by suggesting proper labels.
255+
RelabelArguments,
252256
};
253257

254258
/// Describes a fix that can be applied to a constraint before visiting it.
@@ -276,6 +280,11 @@ class Fix {
276280
/// with the given name.
277281
static Fix getUnwrapOptionalBase(ConstraintSystem &cs, DeclName memberName);
278282

283+
/// Produce a new fix that re-labels existing arguments so they much
284+
/// what parameters expect.
285+
static Fix fixArgumentLabels(ConstraintSystem &cs,
286+
ArrayRef<Identifier> newLabels);
287+
279288
/// Retrieve the kind of fix.
280289
FixKind getKind() const { return Kind; }
281290

@@ -285,6 +294,9 @@ class Fix {
285294
/// If this fix has a name argument, retrieve it.
286295
DeclName getDeclNameArgument(ConstraintSystem &cs) const;
287296

297+
/// If this fix is an argument re-labeling, retrieve new labels.
298+
ArrayRef<Identifier> getArgumentLabels(ConstraintSystem &cs) const;
299+
288300
/// Return a string representation of a fix.
289301
static llvm::StringRef getName(FixKind kind);
290302

lib/Sema/ConstraintSystem.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1008,6 +1008,9 @@ class ConstraintSystem {
10081008
/// Declaration names used in fixes.
10091009
std::vector<DeclName> FixedDeclNames;
10101010

1011+
/// Argument labels fixed by the constraint solver.
1012+
SmallVector<std::vector<Identifier>, 4> FixedArgLabels;
1013+
10111014
/// \brief The set of remembered disjunction choices used to reach
10121015
/// the current constraint system.
10131016
SmallVector<std::pair<ConstraintLocator*, unsigned>, 32>

test/Constraints/keyword_arguments.swift

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ struct X2 {
3333
init(a: Int) { }
3434
func f2(b: Int) { }
3535
}
36-
X2(5).f2(5) // expected-error{{missing argument label 'a:' in call}}{{4-4=a: }}
36+
X2(5).f2(5)
37+
// expected-error@-1 {{missing argument label 'a:' in call}} {{4-4=a: }}
38+
// expected-error@-2 {{missing argument label 'b:' in call}} {{10-10=b: }}
3739

3840

3941
// -------------------------------------------
@@ -401,3 +403,8 @@ _ = acceptTuple2(tuple1)
401403
_ = acceptTuple2((1, "hello", 3.14159))
402404

403405

406+
func generic_and_missing_label(x: Int) {}
407+
func generic_and_missing_label<T>(x: T) {}
408+
409+
generic_and_missing_label(42)
410+
// expected-error@-1 {{missing argument label 'x:' in call}} {{27-27=x: }}

test/IDE/complete_unresolved_members.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ var a = {() in
207207
OptionSetTaker5([.#^UNRESOLVED_18^#], .Option4, .South, .West)
208208
}
209209
var Container = OptionTakerContainer1()
210-
Container.OptionSetTaker1(.#^UNRESOLVED_19^#
210+
Container.OptionSetTaker1(.#^UNRESOLVED_19^#)
211211
Container.EnumTaker1(.#^UNRESOLVED_20^#
212212

213213
func parserSync() {}

0 commit comments

Comments
 (0)