Skip to content

Commit 82c2456

Browse files
authored
Merge pull request #27976 from xedin/extraneous-call
[Diagnostics] Introduce extraneous call fix
2 parents 16cff49 + 1315207 commit 82c2456

File tree

8 files changed

+138
-31
lines changed

8 files changed

+138
-31
lines changed

lib/Sema/CSDiagnostics.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5453,3 +5453,41 @@ bool ExpandArrayIntoVarargsFailure::diagnoseAsNote() {
54535453
}
54545454
return false;
54555455
}
5456+
5457+
bool ExtraneousCallFailure::diagnoseAsError() {
5458+
auto &cs = getConstraintSystem();
5459+
5460+
auto *anchor = getAnchor();
5461+
auto *locator = getLocator();
5462+
5463+
// If this is something like `foo()` where `foo` is a variable
5464+
// or a property, let's suggest dropping `()`.
5465+
auto removeParensFixIt = [&](InFlightDiagnostic &diagnostic) {
5466+
auto *argLoc = cs.getConstraintLocator(getRawAnchor(),
5467+
ConstraintLocator::ApplyArgument);
5468+
5469+
if (auto *TE =
5470+
dyn_cast_or_null<TupleExpr>(simplifyLocatorToAnchor(argLoc))) {
5471+
if (TE->getNumElements() == 0) {
5472+
diagnostic.fixItRemove(TE->getSourceRange());
5473+
}
5474+
}
5475+
};
5476+
5477+
if (auto overload = getChoiceFor(cs.getCalleeLocator(locator))) {
5478+
if (auto *decl = overload->choice.getDeclOrNull()) {
5479+
if (auto *enumCase = dyn_cast<EnumElementDecl>(decl)) {
5480+
auto diagnostic = emitDiagnostic(
5481+
anchor->getLoc(), diag::unexpected_arguments_in_enum_case,
5482+
enumCase->getName());
5483+
removeParensFixIt(diagnostic);
5484+
return true;
5485+
}
5486+
}
5487+
}
5488+
5489+
auto diagnostic = emitDiagnostic(
5490+
anchor->getLoc(), diag::cannot_call_non_function_value, getType(anchor));
5491+
removeParensFixIt(diagnostic);
5492+
return true;
5493+
}

lib/Sema/CSDiagnostics.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1912,6 +1912,15 @@ class MissingForcedDowncastFailure final : public ContextualFailure {
19121912
bool diagnoseAsError() override;
19131913
};
19141914

1915+
class ExtraneousCallFailure final : public FailureDiagnostic {
1916+
public:
1917+
ExtraneousCallFailure(Expr *expr, ConstraintSystem &cs,
1918+
ConstraintLocator *locator)
1919+
: FailureDiagnostic(expr, cs, locator) {}
1920+
1921+
bool diagnoseAsError() override;
1922+
};
1923+
19151924
} // end namespace constraints
19161925
} // end namespace swift
19171926

lib/Sema/CSFix.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -984,3 +984,13 @@ AllowArgumentMismatch::create(ConstraintSystem &cs, Type argType,
984984
return new (cs.getAllocator())
985985
AllowArgumentMismatch(cs, argType, paramType, locator);
986986
}
987+
988+
bool RemoveInvalidCall::diagnose(Expr *root, bool asNote) const {
989+
ExtraneousCallFailure failure(root, getConstraintSystem(), getLocator());
990+
return failure.diagnose(asNote);
991+
}
992+
993+
RemoveInvalidCall *RemoveInvalidCall::create(ConstraintSystem &cs,
994+
ConstraintLocator *locator) {
995+
return new (cs.getAllocator()) RemoveInvalidCall(cs, locator);
996+
}

lib/Sema/CSFix.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,10 @@ enum class FixKind : uint8_t {
211211
/// If an array was passed to a variadic argument, give a specific diagnostic
212212
/// and offer to drop the brackets if it's a literal.
213213
ExpandArrayIntoVarargs,
214+
215+
/// Remove extraneous call to something which can't be invoked e.g.
216+
/// a variable, a property etc.
217+
RemoveCall,
214218
};
215219

216220
class ConstraintFix {
@@ -1469,6 +1473,21 @@ class CoerceToCheckedCast final : public ContextualMismatch {
14691473
Type toType, ConstraintLocator *locator);
14701474
};
14711475

1476+
class RemoveInvalidCall final : public ConstraintFix {
1477+
RemoveInvalidCall(ConstraintSystem &cs, ConstraintLocator *locator)
1478+
: ConstraintFix(cs, FixKind::RemoveCall, locator) {}
1479+
1480+
public:
1481+
std::string getName() const {
1482+
return "remove extraneous call from value of non-function type";
1483+
}
1484+
1485+
bool diagnose(Expr *root, bool asNote = false) const;
1486+
1487+
static RemoveInvalidCall *create(ConstraintSystem &cs,
1488+
ConstraintLocator *locator);
1489+
};
1490+
14721491
} // end namespace constraints
14731492
} // end namespace swift
14741493

lib/Sema/CSSimplify.cpp

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7094,8 +7094,37 @@ ConstraintSystem::simplifyApplicableFnConstraint(
70947094
}
70957095

70967096
// Handle applications of @dynamicCallable types.
7097-
return simplifyDynamicCallableApplicableFnConstraint(type1, origType2,
7098-
subflags, locator);
7097+
auto result = simplifyDynamicCallableApplicableFnConstraint(
7098+
type1, origType2, subflags, locator);
7099+
7100+
if (shouldAttemptFixes() && result == SolutionKind::Error) {
7101+
// Skip this fix if the type is not yet resolved or
7102+
// it's a function type/metatype which points to argument mismatches.
7103+
if (desugar2->is<TypeVariableType>() || desugar2->is<FunctionType>() ||
7104+
desugar2->is<AnyMetatypeType>())
7105+
return SolutionKind::Error;
7106+
7107+
if (auto objectTy = desugar2->lookThroughAllOptionalTypes()) {
7108+
if (objectTy->isAny() || objectTy->isAnyObject())
7109+
return SolutionKind::Error;
7110+
}
7111+
7112+
// If there are any type variables associated with arguments/result
7113+
// they have to be marked as "holes".
7114+
type1.visit([&](Type subType) {
7115+
if (auto *typeVar = subType->getAs<TypeVariableType>())
7116+
recordHole(typeVar);
7117+
});
7118+
7119+
auto *fix = RemoveInvalidCall::create(*this, getConstraintLocator(locator));
7120+
// Let's make this fix as high impact so if there is a function or member
7121+
// overload with e.g. argument-to-parameter type mismatches it would take
7122+
// a higher priority.
7123+
return recordFix(fix, /*impact=*/10) ? SolutionKind::Error
7124+
: SolutionKind::Solved;
7125+
}
7126+
7127+
return result;
70997128
}
71007129

71017130
/// Looks up and returns the @dynamicCallable required methods (if they exist)
@@ -8007,6 +8036,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
80078036
case FixKind::UseSubscriptOperator:
80088037
case FixKind::ExplicitlyEscaping:
80098038
case FixKind::RelabelArguments:
8039+
case FixKind::RemoveCall:
80108040
case FixKind::RemoveUnwrap:
80118041
case FixKind::DefineMemberBasedOnUse:
80128042
case FixKind::AllowMemberRefOnExistential:

test/Constraints/closures.swift

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,8 @@ func r21544303() {
100100
inSubcall = false
101101

102102
var v2 : Bool = false
103-
v2 = inSubcall
104-
{ // expected-error {{cannot call value of non-function type 'Bool'}} expected-note {{did you mean to use a 'do' statement?}} {{3-3=do }}
103+
v2 = inSubcall // expected-error {{cannot call value of non-function type 'Bool'}}
104+
{
105105
}
106106
}
107107

@@ -114,56 +114,56 @@ func SR3671() {
114114
{ consume($0) }(42)
115115
;
116116

117-
({ $0(42) } { consume($0) }) // expected-note {{callee is here}}
117+
({ $0(42) } { consume($0) }) // expected-error {{cannot call value of non-function type '()'}} expected-note {{callee is here}}
118118

119-
{ print(42) } // expected-warning {{braces here form a trailing closure separated from its callee by multiple newlines}} expected-note {{did you mean to use a 'do' statement?}} {{3-3=do }} expected-error {{cannot call value of non-function type '()'}}
119+
{ print(42) } // expected-warning {{braces here form a trailing closure separated from its callee by multiple newlines}} expected-note {{did you mean to use a 'do' statement?}} {{3-3=do }}
120120
;
121121

122-
({ $0(42) } { consume($0) }) // expected-note {{callee is here}}
122+
({ $0(42) } { consume($0) }) // expected-error {{cannot call value of non-function type '()'}} expected-note {{callee is here}}
123123

124-
{ print($0) } // expected-warning {{braces here form a trailing closure separated from its callee by multiple newlines}} expected-error {{cannot call value of non-function type '()'}}
124+
{ print($0) } // expected-warning {{braces here form a trailing closure separated from its callee by multiple newlines}}
125125
;
126126

127-
({ $0(42) } { consume($0) }) // expected-note {{callee is here}}
127+
({ $0(42) } { consume($0) }) // expected-error {{cannot call value of non-function type '()'}} expected-note {{callee is here}}
128128

129-
{ [n] in print(42) } // expected-warning {{braces here form a trailing closure separated from its callee by multiple newlines}} expected-error {{cannot call value of non-function type '()'}}
129+
{ [n] in print(42) } // expected-warning {{braces here form a trailing closure separated from its callee by multiple newlines}}
130130
;
131131

132-
({ $0(42) } { consume($0) }) // expected-note {{callee is here}}
132+
({ $0(42) } { consume($0) }) // expected-error {{cannot call value of non-function type '()'}} expected-note {{callee is here}}
133133

134-
{ consume($0) }(42) // expected-warning {{braces here form a trailing closure separated from its callee by multiple newlines}} expected-error {{cannot call value of non-function type '()'}}
134+
{ consume($0) }(42) // expected-warning {{braces here form a trailing closure separated from its callee by multiple newlines}}
135135
;
136136

137-
({ $0(42) } { consume($0) }) // expected-note {{callee is here}}
137+
({ $0(42) } { consume($0) }) // expected-error {{cannot call value of non-function type '()'}} expected-note {{callee is here}}
138138

139-
{ (x: Int) in consume(x) }(42) // expected-warning {{braces here form a trailing closure separated from its callee by multiple newlines}} expected-error {{cannot call value of non-function type '()'}}
139+
{ (x: Int) in consume(x) }(42) // expected-warning {{braces here form a trailing closure separated from its callee by multiple newlines}}
140140
;
141141

142142
// This is technically a valid call, so nothing goes wrong until (42)
143143

144-
{ $0(3) }
145-
{ consume($0) }(42) // expected-error {{cannot call value of non-function type '()'}}
144+
{ $0(3) } // expected-error {{cannot call value of non-function type '()'}}
145+
{ consume($0) }(42)
146146
;
147-
({ $0(42) })
148-
{ consume($0) }(42) // expected-error {{cannot call value of non-function type '()'}}
147+
({ $0(42) }) // expected-error {{cannot call value of non-function type '()'}}
148+
{ consume($0) }(42)
149149
;
150-
{ $0(3) }
151-
{ [n] in consume($0) }(42) // expected-error {{cannot call value of non-function type '()'}}
150+
{ $0(3) } // expected-error {{cannot call value of non-function type '()'}}
151+
{ [n] in consume($0) }(42)
152152
;
153-
({ $0(42) })
154-
{ [n] in consume($0) }(42) // expected-error {{cannot call value of non-function type '()'}}
153+
({ $0(42) }) // expected-error {{cannot call value of non-function type '()'}}
154+
{ [n] in consume($0) }(42)
155155
;
156156

157157
// Equivalent but more obviously unintended.
158158

159-
{ $0(3) } // expected-note {{callee is here}}
159+
{ $0(3) } // expected-error {{cannot call value of non-function type '()'}} expected-note {{callee is here}}
160160

161-
{ consume($0) }(42) // expected-error {{cannot call value of non-function type '()'}}
161+
{ consume($0) }(42)
162162
// expected-warning@-1 {{braces here form a trailing closure separated from its callee by multiple newlines}}
163163

164-
({ $0(3) }) // expected-note {{callee is here}}
164+
({ $0(3) }) // expected-error {{cannot call value of non-function type '()'}} expected-note {{callee is here}}
165165

166-
{ consume($0) }(42) // expected-error {{cannot call value of non-function type '()'}}
166+
{ consume($0) }(42)
167167
// expected-warning@-1 {{braces here form a trailing closure separated from its callee by multiple newlines}}
168168
;
169169

@@ -407,6 +407,7 @@ func r20789423() {
407407

408408
let p: C
409409
print(p.f(p)()) // expected-error {{cannot convert value of type 'C' to expected argument type 'Int'}}
410+
// expected-error@-1:11 {{cannot call value of non-function type '()'}}
410411

411412
let _f = { (v: Int) in // expected-error {{unable to infer complex closure return type; add explicit type to disambiguate}} {{23-23=-> String }}
412413
print("a")

test/Constraints/diagnostics.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ func rdar20142523() {
169169
func rdar21080030() {
170170
var s = "Hello"
171171
// SR-7599: This should be `cannot_call_non_function_value`
172-
if s.count() == 0 {} // expected-error{{cannot invoke 'count' with no arguments}}
172+
if s.count() == 0 {} // expected-error{{cannot call value of non-function type 'Int'}} {{13-15=}}
173173
}
174174

175175
// <rdar://problem/21248136> QoI: problem with return type inference mis-diagnosed as invalid arguments
@@ -530,8 +530,8 @@ let _: Color = .frob(1, &d) // expected-error {{missing argument label 'b:' in c
530530
let _: Color = .frob(1, b: &d) // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}}
531531
var someColor : Color = .red // expected-error {{enum type 'Color' has no case 'red'; did you mean 'Red'}}
532532
someColor = .red // expected-error {{enum type 'Color' has no case 'red'; did you mean 'Red'}}
533-
someColor = .svar() // expected-error {{static property 'svar' is not a function}}
534-
someColor = .svar(1) // expected-error {{static property 'svar' is not a function}}
533+
someColor = .svar() // expected-error {{cannot call value of non-function type 'Color'}}
534+
someColor = .svar(1) // expected-error {{cannot call value of non-function type 'Color'}}
535535

536536
func testTypeSugar(_ a : Int) {
537537
typealias Stride = Int

test/Index/invalid_code.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class CrashTest {
1717
init() { }
1818
}
1919
// CHECK: [[@LINE+1]]:13 | instance-method/Swift | returnSelf
20-
CrashTest().returnSelf(["": 0]).something()
20+
CrashTest().returnSelf(["": 0]).something
2121

2222
class CrashTest2 {
2323
// CHECK: [[@LINE+1]]:8 | instance-method/Swift | bar
@@ -48,4 +48,4 @@ extension Protector where T: RangeReplaceableCollection {
4848
_ = newElement
4949
}
5050
}
51-
}
51+
}

0 commit comments

Comments
 (0)