mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[Diagnostics] Improve argument labeling diagnostics
Extend new labeling diagnostics (via fixes) to support member references and subscripts.
This commit is contained in:
@@ -366,10 +366,25 @@ bool MissingConformanceFailure::diagnoseAsError() {
|
||||
|
||||
bool LabelingFailure::diagnoseAsError() {
|
||||
auto &cs = getConstraintSystem();
|
||||
auto *call = cast<CallExpr>(getAnchor());
|
||||
return diagnoseArgumentLabelError(cs.getASTContext(), call->getArg(),
|
||||
CorrectLabels,
|
||||
isa<SubscriptExpr>(call->getFn()));
|
||||
auto *anchor = getRawAnchor();
|
||||
|
||||
Expr *argExpr = nullptr;
|
||||
if (auto *UDE = dyn_cast<UnresolvedDotExpr>(anchor)) {
|
||||
if (auto *call = dyn_cast_or_null<CallExpr>(findParentExpr(UDE)))
|
||||
argExpr = call->getArg();
|
||||
} else if (auto *UME = dyn_cast<UnresolvedMemberExpr>(anchor)) {
|
||||
argExpr = UME->getArgument();
|
||||
} else if (auto *call = dyn_cast<CallExpr>(anchor)) {
|
||||
argExpr = call->getArg();
|
||||
} else if (auto *SE = dyn_cast<SubscriptExpr>(anchor)) {
|
||||
argExpr = SE->getIndex();
|
||||
}
|
||||
|
||||
if (!argExpr)
|
||||
return false;
|
||||
|
||||
return diagnoseArgumentLabelError(cs.getASTContext(), argExpr, CorrectLabels,
|
||||
isa<SubscriptExpr>(anchor));
|
||||
}
|
||||
|
||||
bool NoEscapeFuncToTypeConversionFailure::diagnoseAsError() {
|
||||
|
||||
@@ -443,9 +443,9 @@ class LabelingFailure final : public FailureDiagnostic {
|
||||
ArrayRef<Identifier> CorrectLabels;
|
||||
|
||||
public:
|
||||
LabelingFailure(ConstraintSystem &cs, ConstraintLocator *locator,
|
||||
LabelingFailure(Expr *root, ConstraintSystem &cs, ConstraintLocator *locator,
|
||||
ArrayRef<Identifier> labels)
|
||||
: FailureDiagnostic(nullptr, cs, locator), CorrectLabels(labels) {}
|
||||
: FailureDiagnostic(root, cs, locator), CorrectLabels(labels) {}
|
||||
|
||||
bool diagnoseAsError() override;
|
||||
};
|
||||
|
||||
@@ -145,7 +145,8 @@ MarkExplicitlyEscaping::create(ConstraintSystem &cs, ConstraintLocator *locator,
|
||||
}
|
||||
|
||||
bool RelabelArguments::diagnose(Expr *root, bool asNote) const {
|
||||
LabelingFailure failure(getConstraintSystem(), getLocator(), getLabels());
|
||||
LabelingFailure failure(root, getConstraintSystem(), getLocator(),
|
||||
getLabels());
|
||||
return failure.diagnose(asNote);
|
||||
}
|
||||
|
||||
|
||||
@@ -755,7 +755,7 @@ public:
|
||||
return true;
|
||||
|
||||
auto *anchor = Locator.getBaseLocator()->getAnchor();
|
||||
if (!anchor || !isa<CallExpr>(anchor))
|
||||
if (!anchor)
|
||||
return true;
|
||||
|
||||
auto *locator = CS.getConstraintLocator(anchor);
|
||||
@@ -1229,6 +1229,7 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
|
||||
if (func1Params.size() != func2Params.size())
|
||||
return getTypeMatchFailure(argumentLocator);
|
||||
|
||||
bool hasLabelingFailures = false;
|
||||
for (unsigned i : indices(func1Params)) {
|
||||
auto func1Param = func1Params[i];
|
||||
auto func2Param = func2Params[i];
|
||||
@@ -1242,9 +1243,16 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
|
||||
// FIXME: We should not end up with labels here at all, but we do
|
||||
// from invalid code in diagnostics, and as a result of code completion
|
||||
// directly building constraint systems.
|
||||
if (func1Param.getLabel() != func2Param.getLabel())
|
||||
if (func1Param.getLabel() != func2Param.getLabel()) {
|
||||
if (!shouldAttemptFixes())
|
||||
return getTypeMatchFailure(argumentLocator);
|
||||
|
||||
// If we are allowed to attempt fixes, let's ignore labeling
|
||||
// failures, and create a fix to re-label arguments if types
|
||||
// line up correctly.
|
||||
hasLabelingFailures = true;
|
||||
}
|
||||
|
||||
// FIXME: We should check value ownership too, but it's not completely
|
||||
// trivial because of inout-to-pointer conversions.
|
||||
|
||||
@@ -1260,6 +1268,17 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
|
||||
return result;
|
||||
}
|
||||
|
||||
if (hasLabelingFailures) {
|
||||
SmallVector<Identifier, 4> correctLabels;
|
||||
for (const auto ¶m : func2Params)
|
||||
correctLabels.push_back(param.getLabel());
|
||||
|
||||
auto *fix = RelabelArguments::create(*this, correctLabels,
|
||||
getConstraintLocator(argumentLocator));
|
||||
if (recordFix(fix))
|
||||
return getTypeMatchFailure(argumentLocator);
|
||||
}
|
||||
|
||||
// Result type can be covariant (or equal).
|
||||
return matchTypes(func1->getResult(), func2->getResult(), subKind,
|
||||
subflags,
|
||||
|
||||
@@ -448,6 +448,7 @@ let _: Color = .overload(1) // expected-error {{ambiguous reference to member '
|
||||
let _: Color = .frob(1.0, &i) // expected-error {{missing argument label 'b:' in call}}
|
||||
let _: Color = .frob(1.0, b: &i) // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}}
|
||||
let _: Color = .frob(1, i) // expected-error {{missing argument label 'b:' in call}}
|
||||
// expected-error@-1 {{passing value of type 'Int' to an inout parameter requires explicit '&'}}
|
||||
let _: Color = .frob(1, b: i) // expected-error {{passing value of type 'Int' to an inout parameter requires explicit '&'}} {{28-28=&}}
|
||||
let _: Color = .frob(1, &d) // expected-error {{missing argument label 'b:' in call}}
|
||||
let _: Color = .frob(1, b: &d) // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}}
|
||||
|
||||
@@ -630,7 +630,7 @@ let arr = [BottleLayout]()
|
||||
let layout = BottleLayout(count:1)
|
||||
let ix = arr.firstIndex(of:layout) // expected-error {{argument type 'BottleLayout' does not conform to expected type 'Equatable'}}
|
||||
|
||||
let _: () -> UInt8 = { .init("a" as Unicode.Scalar) } // expected-error {{initializer 'init(_:)' requires that 'Unicode.Scalar' conform to 'BinaryInteger'}}
|
||||
let _: () -> UInt8 = { .init("a" as Unicode.Scalar) } // expected-error {{missing argument label 'ascii:' in call}}
|
||||
|
||||
// https://bugs.swift.org/browse/SR-9068
|
||||
func compare<C: Collection, Key: Hashable, Value: Equatable>(c: C)
|
||||
|
||||
@@ -291,10 +291,7 @@ switch staticMembers {
|
||||
case .init(0): break
|
||||
case .init(_): break // expected-error{{'_' can only appear in a pattern}}
|
||||
case .init(let x): break // expected-error{{cannot appear in an expression}}
|
||||
case .init(opt: 0): break
|
||||
// expected-error@-1 {{value of optional type 'StaticMembers?' must be unwrapped to a value of type 'StaticMembers'}}
|
||||
// expected-note@-2 {{coalesce}}
|
||||
// expected-note@-3 {{force-unwrap}}
|
||||
case .init(opt: 0): break // expected-error{{pattern cannot match values of type 'StaticMembers'}}
|
||||
|
||||
case .prop: break
|
||||
// TODO: repeated error message
|
||||
|
||||
@@ -91,7 +91,7 @@ struct SR718 {
|
||||
subscript(a a : UInt) -> Int { return 0 }
|
||||
}
|
||||
|
||||
SR718()[a: Int()] // expected-error {{cannot convert value of type 'Int' to expected argument type 'UInt'}}
|
||||
SR718()[a: Int()] // expected-error {{extraneous argument label 'a:' in subscript}}
|
||||
|
||||
// rdar://problem/25601561 - Qol: Bad diagnostic for failed assignment from Any to more specific type
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@ class B {
|
||||
class D : B {
|
||||
override init() {
|
||||
super.init()
|
||||
super.init(42)
|
||||
// expected-error@-1 {{missing argument label 'x:' in call}}
|
||||
}
|
||||
|
||||
override init(x:Int) {
|
||||
|
||||
@@ -106,10 +106,9 @@ func testMethods(_ i: Int, x: Y) {
|
||||
|
||||
func testSubscripts(_ i: Int, s: String, x: Y) {
|
||||
var i2 = x[i]
|
||||
var i3 = x[x: i] // expected-error{{cannot subscript a value of type 'Y' with an index of type '(x: Int)'}}
|
||||
// expected-note @-1 {{overloads for 'subscript' exist with these partially matching parameter lists: (Int), (y: String)}}
|
||||
var i3 = x[x: i] // expected-error{{extraneous argument label 'x:' in subscript}}
|
||||
var s2 = x[y: s]
|
||||
var s3 = x[s] // expected-error{{cannot convert value of type 'String' to expected argument type 'Int'}}
|
||||
var s3 = x[s] // expected-error{{missing argument label 'y:' in subscript}}
|
||||
}
|
||||
|
||||
// Operators
|
||||
|
||||
Reference in New Issue
Block a user