Skip to content

Commit bab9b62

Browse files
committed
reimplement the "function produces expected type 'XYZ'; did you mean to call it with '()'?"
fixit hint in CSDiags instead of being a FixKind. This resolves a number of issues with it, particularly that it didn't actually check to see if the function in question takes a () argument or not. This fixes: <rdar://problem/21692808> QoI: Incorrect 'add ()' fixit with trailing closure among other issues. Swift SVN r31728
1 parent 9f01aa2 commit bab9b62

File tree

7 files changed

+34
-80
lines changed

7 files changed

+34
-80
lines changed

Diff for: lib/Sema/CSApply.cpp

-23
Original file line numberDiff line numberDiff line change
@@ -5803,29 +5803,6 @@ bool ConstraintSystem::applySolutionFix(Expr *expr,
58035803
case FixKind::None:
58045804
llvm_unreachable("no-fix marker should never make it into solution");
58055805

5806-
case FixKind::NullaryCall: {
5807-
// Dig for the function we want to call.
5808-
auto type = solution.simplifyType(TC, affected->getType())
5809-
->getRValueType();
5810-
if (auto tupleTy = type->getAs<TupleType>()) {
5811-
if (tupleTy->getElementTypes().size()) {
5812-
if (auto tuple = dyn_cast<TupleExpr>(affected))
5813-
affected = tuple->getElement(0);
5814-
type = tupleTy->getElement(0).getType()->getRValueType();
5815-
}
5816-
}
5817-
5818-
if (auto optTy = type->getAnyOptionalObjectType())
5819-
type = optTy;
5820-
5821-
if (type->is<AnyFunctionType>())
5822-
type = type->castTo<AnyFunctionType>()->getResult();
5823-
5824-
TC.diagnose(affected->getLoc(), diag::missing_nullary_call, type)
5825-
.fixItInsertAfter(affected->getEndLoc(), "()");
5826-
return true;
5827-
}
5828-
58295806
case FixKind::RemoveNullaryCall:
58305807
if (auto apply = dyn_cast<ApplyExpr>(affected)) {
58315808
auto type = solution.simplifyType(TC, apply->getFn()->getType())

Diff for: lib/Sema/CSDiag.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -2862,6 +2862,18 @@ bool FailureDiagnosis::diagnoseContextualConversionError() {
28622862
return false;
28632863
}
28642864

2865+
// If we're trying to convert something of type "() -> T" to T, then we
2866+
// probably meant to call the value.
2867+
if (auto srcFT = exprType->getAs<AnyFunctionType>()) {
2868+
if (srcFT->getInput()->isVoid() &&
2869+
CS->TC.isConvertibleTo(srcFT->getResult(), contextualType, CS->DC)) {
2870+
diagnose(expr->getLoc(), diag::missing_nullary_call, srcFT->getResult())
2871+
.highlight(expr->getSourceRange())
2872+
.fixItInsertAfter(expr->getEndLoc(), "()");
2873+
return true;
2874+
}
2875+
}
2876+
28652877
// When complaining about conversion to a protocol type, complain about
28662878
// conformance instead of "conversion".
28672879
if (contextualType->is<ProtocolType>() ||

Diff for: lib/Sema/CSSimplify.cpp

+3-43
Original file line numberDiff line numberDiff line change
@@ -900,20 +900,9 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
900900
ConstraintLocatorBuilder locator) {
901901
// An @autoclosure function type can be a subtype of a
902902
// non-@autoclosure function type.
903-
if (func1->isAutoClosure() != func2->isAutoClosure()) {
904-
if (func2->isAutoClosure() || kind < TypeMatchKind::Subtype) {
905-
// If the second type is an autoclosure and the first type appears to
906-
// accept no arguments, try to add the ().
907-
if (func2->isAutoClosure() && shouldAttemptFixes() &&
908-
kind >= TypeMatchKind::Conversion &&
909-
isFunctionTypeAcceptingNoArguments(func1)) {
910-
unsigned subFlags = (flags | TMF_GenerateConstraints) & ~TMF_ApplyingFix;
911-
return simplifyFixConstraint(FixKind::NullaryCall, func1, func2, kind,
912-
subFlags, locator);
913-
}
914-
return SolutionKind::Error;
915-
}
916-
}
903+
if (func1->isAutoClosure() != func2->isAutoClosure() &&
904+
(func2->isAutoClosure() || kind < TypeMatchKind::Subtype))
905+
return SolutionKind::Error;
917906

918907
// A non-throwing function can be a subtype of a throwing function.
919908
if (func1->throws() != func2->throws()) {
@@ -2014,12 +2003,6 @@ ConstraintSystem::matchTypes(Type type1, Type type2, TypeMatchKind kind,
20142003
!(flags & TMF_ApplyingFix) && kind >= TypeMatchKind::Conversion) {
20152004
Type objectType1 = type1->getRValueObjectType();
20162005

2017-
// If the source type is a function type that could be applied with (),
2018-
// try it.
2019-
if (isFunctionTypeAcceptingNoArguments(objectType1)) {
2020-
conversionsOrFixes.push_back(FixKind::NullaryCall);
2021-
}
2022-
20232006
// If we have an optional type, try to force-unwrap it.
20242007
// FIXME: Should we also try '?'?
20252008
if (objectType1->getOptionalObjectType()) {
@@ -4284,29 +4267,6 @@ ConstraintSystem::simplifyFixConstraint(Fix fix,
42844267
case FixKind::None:
42854268
return matchTypes(type1, type2, matchKind, subFlags, locator);
42864269

4287-
case FixKind::NullaryCall: {
4288-
// Assume that '()' was applied to the first type.
4289-
4290-
// If the function was actually in a tuple, tuple'ify the
4291-
// FIXME: This is yet another awful hack due to one-element tuples.
4292-
auto funcTy = type1->getRValueType();
4293-
Identifier nameToAdd;
4294-
if (auto tupleTy = funcTy->getAs<TupleType>()) {
4295-
int scalarIdx = tupleTy->getElementForScalarInit();
4296-
nameToAdd = tupleTy->getElement(scalarIdx).getName();
4297-
funcTy = tupleTy->getElementType(scalarIdx);
4298-
}
4299-
4300-
if (auto optObjectTy = funcTy->getAnyOptionalObjectType())
4301-
funcTy = optObjectTy;
4302-
4303-
auto resultTy = funcTy->castTo<AnyFunctionType>()->getResult();
4304-
if (!nameToAdd.empty())
4305-
resultTy = TupleType::get(TupleTypeElt(resultTy, nameToAdd),
4306-
getASTContext());
4307-
return matchTypes(resultTy, type2, matchKind, subFlags, locator);
4308-
}
4309-
43104270
case FixKind::RemoveNullaryCall:
43114271
llvm_unreachable("Always applied directly");
43124272

Diff for: lib/Sema/Constraint.cpp

-2
Original file line numberDiff line numberDiff line change
@@ -435,8 +435,6 @@ StringRef Fix::getName(FixKind kind) {
435435
switch (kind) {
436436
case FixKind::None:
437437
return "prevent fixes";
438-
case FixKind::NullaryCall:
439-
return "fix: add nullary call";
440438
case FixKind::ForceOptional:
441439
return "fix: force optional";
442440
case FixKind::ForceDowncast:

Diff for: test/Constraints/diagnostics.swift

+10-2
Original file line numberDiff line numberDiff line change
@@ -455,8 +455,7 @@ let _ : Color = .rainbow(42) // expected-error {{cannot convert value of type '
455455

456456
let _ : (Int, Float) = (42.0, 12) // expected-error {{cannot convert value of type 'Double' to specified type 'Int'}}
457457

458-
// FIXME: Why two errors?
459-
let _ : Color = .rainbow // expected-error 2 {{function produces expected type 'Color'; did you mean to call it with '()'?}}
458+
let _ : Color = .rainbow // expected-error {{contextual member 'rainbow' expects argument of type '()'}}
460459

461460
let _: Color = .overload(a : 1.0) // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}}
462461
let _: Color = .overload(1.0) // expected-error {{ambiguous reference to member 'overload'}}
@@ -597,3 +596,12 @@ extension Array {
597596
func safeAssign<T: RawRepresentable>(inout lhs: T) -> Bool {} // expected-note {{in call to function 'safeAssign'}}
598597
let a = safeAssign // expected-error {{generic parameter 'T' could not be inferred}}
599598

599+
600+
// <rdar://problem/21692808> QoI: Incorrect 'add ()' fixit with trailing closure
601+
func foo() -> [Int] {
602+
return Array <Int> (count: 1) {
603+
return 1
604+
}
605+
}
606+
607+

Diff for: test/Constraints/fixes.swift

+7-7
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ func f4() -> B { }
1414
func f5(a: A) { }
1515
func f6(a: A, _: Int) { }
1616

17-
func createB() -> B { }
18-
func createB(i: Int) -> B { }
17+
func createB() -> B { } // expected-note {{found this candidate}}
18+
func createB(i: Int) -> B { } // expected-note {{found this candidate}}
1919

2020
func f7(a: A, _: () -> Int) -> B { }
2121
func f7(a: A, _: Int) -> Int { }
@@ -25,8 +25,8 @@ func forgotCall() {
2525
// Simple cases
2626
var x: Int
2727
x = f1 // expected-error{{function produces expected type 'Int'; did you mean to call it with '()'?}}{{9-9=()}}
28-
x = f2 // expected-error{{function produces expected type 'Int'; did you mean to call it with '()'?}}{{9-9=()}}
29-
x = f3 // expected-error{{function produces expected type 'Int'; did you mean to call it with '()'?}}{{9-9=()}}
28+
x = f2 // expected-error{{cannot assign value of type '(Int) -> Int' to type 'Int'}}
29+
x = f3 // expected-error{{cannot assign value of type '(Int...) -> Int' to type 'Int'}}
3030

3131
// With a supertype conversion
3232
var a = A()
@@ -35,13 +35,13 @@ func forgotCall() {
3535
// As a call
3636
f5(f4) // expected-error{{function produces expected type 'B'; did you mean to call it with '()'?}}{{8-8=()}}
3737
f6(f4, f2) // expected-error{{function produces expected type 'B'; did you mean to call it with '()'?}}{{8-8=()}}
38-
// expected-error @-1{{function produces expected type 'Int'; did you mean to call it with '()'?}}{{12-12=()}}
3938

4039
// With overloading: only one succeeds.
41-
a = createB // expected-error{{function produces expected type 'B'; did you mean to call it with '()'?}}{{14-14=()}}
40+
a = createB // expected-error{{ambiguous reference to member 'createB'}}
4241

4342
// With overloading, pick the fewest number of fixes.
44-
var b = f7(f4, f1) // expected-error{{function produces expected type 'B'; did you mean to call it with '()'?}}{{16-16=()}}
43+
var b = f7(f4, f1) // expected-error{{cannot invoke 'f7' with an argument list of type '(() -> B, () -> Int)'}}
44+
// expected-note @-1 {{expected an argument list of type '(A, () -> Int)'}}
4545
b.iAmAB()
4646
}
4747

Diff for: test/stmt/statements.swift

+2-3
Original file line numberDiff line numberDiff line change
@@ -402,9 +402,8 @@ func test_is_as_patterns() {
402402
// <rdar://problem/21387308> Fuzzing SourceKit: crash in Parser::parseStmtForEach(...)
403403
func matching_pattern_recursion() {
404404
switch 42 {
405-
// FIXME: this is a terrible diagnostic
406-
case { // expected-error {{function produces expected type 'Range<Int>'; did you mean to call it with '()'?}} {{4-4=()}}
407-
for i in zs {
405+
case { // expected-error {{expression pattern of type '() -> ()' cannot match values of type 'Int'}}
406+
for i in zs { // expected-error {{use of unresolved identifier 'zs'}}
408407
}
409408
}: break
410409
}

0 commit comments

Comments
 (0)