Skip to content

Commit d4b67bf

Browse files
committed
[Diagnostics] Improve argument labeling diagnostics
Extend new labeling diagnostics (via fixes) to support member references and subscripts.
1 parent 1a66c77 commit d4b67bf

File tree

10 files changed

+53
-19
lines changed

10 files changed

+53
-19
lines changed

lib/Sema/CSDiagnostics.cpp

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -366,10 +366,25 @@ bool MissingConformanceFailure::diagnoseAsError() {
366366

367367
bool LabelingFailure::diagnoseAsError() {
368368
auto &cs = getConstraintSystem();
369-
auto *call = cast<CallExpr>(getAnchor());
370-
return diagnoseArgumentLabelError(cs.getASTContext(), call->getArg(),
371-
CorrectLabels,
372-
isa<SubscriptExpr>(call->getFn()));
369+
auto *anchor = getRawAnchor();
370+
371+
Expr *argExpr = nullptr;
372+
if (auto *UDE = dyn_cast<UnresolvedDotExpr>(anchor)) {
373+
if (auto *call = dyn_cast_or_null<CallExpr>(findParentExpr(UDE)))
374+
argExpr = call->getArg();
375+
} else if (auto *UME = dyn_cast<UnresolvedMemberExpr>(anchor)) {
376+
argExpr = UME->getArgument();
377+
} else if (auto *call = dyn_cast<CallExpr>(anchor)) {
378+
argExpr = call->getArg();
379+
} else if (auto *SE = dyn_cast<SubscriptExpr>(anchor)) {
380+
argExpr = SE->getIndex();
381+
}
382+
383+
if (!argExpr)
384+
return false;
385+
386+
return diagnoseArgumentLabelError(cs.getASTContext(), argExpr, CorrectLabels,
387+
isa<SubscriptExpr>(anchor));
373388
}
374389

375390
bool NoEscapeFuncToTypeConversionFailure::diagnoseAsError() {

lib/Sema/CSDiagnostics.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -443,9 +443,9 @@ class LabelingFailure final : public FailureDiagnostic {
443443
ArrayRef<Identifier> CorrectLabels;
444444

445445
public:
446-
LabelingFailure(ConstraintSystem &cs, ConstraintLocator *locator,
446+
LabelingFailure(Expr *root, ConstraintSystem &cs, ConstraintLocator *locator,
447447
ArrayRef<Identifier> labels)
448-
: FailureDiagnostic(nullptr, cs, locator), CorrectLabels(labels) {}
448+
: FailureDiagnostic(root, cs, locator), CorrectLabels(labels) {}
449449

450450
bool diagnoseAsError() override;
451451
};

lib/Sema/CSFix.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,8 @@ MarkExplicitlyEscaping::create(ConstraintSystem &cs, ConstraintLocator *locator,
145145
}
146146

147147
bool RelabelArguments::diagnose(Expr *root, bool asNote) const {
148-
LabelingFailure failure(getConstraintSystem(), getLocator(), getLabels());
148+
LabelingFailure failure(root, getConstraintSystem(), getLocator(),
149+
getLabels());
149150
return failure.diagnose(asNote);
150151
}
151152

lib/Sema/CSSimplify.cpp

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -755,7 +755,7 @@ class ArgumentFailureTracker : public MatchCallArgumentListener {
755755
return true;
756756

757757
auto *anchor = Locator.getBaseLocator()->getAnchor();
758-
if (!anchor || !isa<CallExpr>(anchor))
758+
if (!anchor)
759759
return true;
760760

761761
auto *locator = CS.getConstraintLocator(anchor);
@@ -1229,6 +1229,7 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
12291229
if (func1Params.size() != func2Params.size())
12301230
return getTypeMatchFailure(argumentLocator);
12311231

1232+
bool hasLabelingFailures = false;
12321233
for (unsigned i : indices(func1Params)) {
12331234
auto func1Param = func1Params[i];
12341235
auto func2Param = func2Params[i];
@@ -1242,8 +1243,15 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
12421243
// FIXME: We should not end up with labels here at all, but we do
12431244
// from invalid code in diagnostics, and as a result of code completion
12441245
// directly building constraint systems.
1245-
if (func1Param.getLabel() != func2Param.getLabel())
1246-
return getTypeMatchFailure(argumentLocator);
1246+
if (func1Param.getLabel() != func2Param.getLabel()) {
1247+
if (!shouldAttemptFixes())
1248+
return getTypeMatchFailure(argumentLocator);
1249+
1250+
// If we are allowed to attempt fixes, let's ignore labeling
1251+
// failures, and create a fix to re-label arguments if types
1252+
// line up correctly.
1253+
hasLabelingFailures = true;
1254+
}
12471255

12481256
// FIXME: We should check value ownership too, but it's not completely
12491257
// trivial because of inout-to-pointer conversions.
@@ -1260,6 +1268,17 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
12601268
return result;
12611269
}
12621270

1271+
if (hasLabelingFailures) {
1272+
SmallVector<Identifier, 4> correctLabels;
1273+
for (const auto &param : func2Params)
1274+
correctLabels.push_back(param.getLabel());
1275+
1276+
auto *fix = RelabelArguments::create(*this, correctLabels,
1277+
getConstraintLocator(argumentLocator));
1278+
if (recordFix(fix))
1279+
return getTypeMatchFailure(argumentLocator);
1280+
}
1281+
12631282
// Result type can be covariant (or equal).
12641283
return matchTypes(func1->getResult(), func2->getResult(), subKind,
12651284
subflags,

test/Constraints/diagnostics.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,7 @@ let _: Color = .overload(1) // expected-error {{ambiguous reference to member '
448448
let _: Color = .frob(1.0, &i) // expected-error {{missing argument label 'b:' in call}}
449449
let _: Color = .frob(1.0, b: &i) // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}}
450450
let _: Color = .frob(1, i) // expected-error {{missing argument label 'b:' in call}}
451+
// expected-error@-1 {{passing value of type 'Int' to an inout parameter requires explicit '&'}}
451452
let _: Color = .frob(1, b: i) // expected-error {{passing value of type 'Int' to an inout parameter requires explicit '&'}} {{28-28=&}}
452453
let _: Color = .frob(1, &d) // expected-error {{missing argument label 'b:' in call}}
453454
let _: Color = .frob(1, b: &d) // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}}

test/Constraints/generics.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -630,7 +630,7 @@ let arr = [BottleLayout]()
630630
let layout = BottleLayout(count:1)
631631
let ix = arr.firstIndex(of:layout) // expected-error {{argument type 'BottleLayout' does not conform to expected type 'Equatable'}}
632632

633-
let _: () -> UInt8 = { .init("a" as Unicode.Scalar) } // expected-error {{initializer 'init(_:)' requires that 'Unicode.Scalar' conform to 'BinaryInteger'}}
633+
let _: () -> UInt8 = { .init("a" as Unicode.Scalar) } // expected-error {{missing argument label 'ascii:' in call}}
634634

635635
// https://bugs.swift.org/browse/SR-9068
636636
func compare<C: Collection, Key: Hashable, Value: Equatable>(c: C)

test/Constraints/patterns.swift

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -291,10 +291,7 @@ switch staticMembers {
291291
case .init(0): break
292292
case .init(_): break // expected-error{{'_' can only appear in a pattern}}
293293
case .init(let x): break // expected-error{{cannot appear in an expression}}
294-
case .init(opt: 0): break
295-
// expected-error@-1 {{value of optional type 'StaticMembers?' must be unwrapped to a value of type 'StaticMembers'}}
296-
// expected-note@-2 {{coalesce}}
297-
// expected-note@-3 {{force-unwrap}}
294+
case .init(opt: 0): break // expected-error{{pattern cannot match values of type 'StaticMembers'}}
298295

299296
case .prop: break
300297
// TODO: repeated error message

test/Constraints/subscript.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ struct SR718 {
9191
subscript(a a : UInt) -> Int { return 0 }
9292
}
9393

94-
SR718()[a: Int()] // expected-error {{cannot convert value of type 'Int' to expected argument type 'UInt'}}
94+
SR718()[a: Int()] // expected-error {{extraneous argument label 'a:' in subscript}}
9595

9696
// rdar://problem/25601561 - Qol: Bad diagnostic for failed assignment from Any to more specific type
9797

test/Parse/super.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ class B {
1616
class D : B {
1717
override init() {
1818
super.init()
19+
super.init(42)
20+
// expected-error@-1 {{missing argument label 'x:' in call}}
1921
}
2022

2123
override init(x:Int) {

test/decl/func/keyword-argument-defaults.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,10 +106,9 @@ func testMethods(_ i: Int, x: Y) {
106106

107107
func testSubscripts(_ i: Int, s: String, x: Y) {
108108
var i2 = x[i]
109-
var i3 = x[x: i] // expected-error{{cannot subscript a value of type 'Y' with an index of type '(x: Int)'}}
110-
// expected-note @-1 {{overloads for 'subscript' exist with these partially matching parameter lists: (Int), (y: String)}}
109+
var i3 = x[x: i] // expected-error{{extraneous argument label 'x:' in subscript}}
111110
var s2 = x[y: s]
112-
var s3 = x[s] // expected-error{{cannot convert value of type 'String' to expected argument type 'Int'}}
111+
var s3 = x[s] // expected-error{{missing argument label 'y:' in subscript}}
113112
}
114113

115114
// Operators

0 commit comments

Comments
 (0)