Skip to content

Commit adba382

Browse files
authored
Merge pull request swiftlang#21238 from xedin/diag-property-as-member-via-fix
[CSFix] Call a function/member which is incorrectly used as a property
2 parents 570840f + 9818b55 commit adba382

File tree

7 files changed

+144
-62
lines changed

7 files changed

+144
-62
lines changed

lib/Sema/CSDiag.cpp

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7392,26 +7392,9 @@ bool FailureDiagnosis::diagnoseMemberFailures(
73927392
// Produce a specific diagnostic + fixit for this situation.
73937393
if (auto baseFTy = baseObjTy->getAs<AnyFunctionType>()) {
73947394
if (baseExpr && baseFTy->getParams().empty()) {
7395-
SourceLoc insertLoc = baseExpr->getEndLoc();
7396-
7397-
if (auto *DRE = dyn_cast<DeclRefExpr>(baseExpr)) {
7398-
diagnose(baseExpr->getLoc(), diag::did_not_call_function,
7399-
DRE->getDecl()->getBaseName().getIdentifier())
7400-
.fixItInsertAfter(insertLoc, "()");
7401-
return true;
7402-
}
7403-
7404-
if (auto *DSCE = dyn_cast<DotSyntaxCallExpr>(baseExpr))
7405-
if (auto *DRE = dyn_cast<DeclRefExpr>(DSCE->getFn())) {
7406-
diagnose(baseExpr->getLoc(), diag::did_not_call_method,
7407-
DRE->getDecl()->getBaseName().getIdentifier())
7408-
.fixItInsertAfter(insertLoc, "()");
7409-
return true;
7410-
}
7411-
7412-
diagnose(baseExpr->getLoc(), diag::did_not_call_function_value)
7413-
.fixItInsertAfter(insertLoc, "()");
7414-
return true;
7395+
auto failure =
7396+
MissingCallFailure(expr, CS, CS.getConstraintLocator(baseExpr));
7397+
return failure.diagnoseAsError();
74157398
}
74167399
}
74177400

lib/Sema/CSDiagnostics.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1240,3 +1240,38 @@ bool NonOptionalUnwrapFailure::diagnoseAsError() {
12401240

12411241
return true;
12421242
}
1243+
1244+
bool MissingCallFailure::diagnoseAsError() {
1245+
auto *baseExpr = getAnchor();
1246+
SourceLoc insertLoc = baseExpr->getEndLoc();
1247+
1248+
if (auto *FVE = dyn_cast<ForceValueExpr>(baseExpr))
1249+
baseExpr = FVE->getSubExpr();
1250+
1251+
if (auto *DRE = dyn_cast<DeclRefExpr>(baseExpr)) {
1252+
emitDiagnostic(baseExpr->getLoc(), diag::did_not_call_function,
1253+
DRE->getDecl()->getBaseName().getIdentifier())
1254+
.fixItInsertAfter(insertLoc, "()");
1255+
return true;
1256+
}
1257+
1258+
if (auto *UDE = dyn_cast<UnresolvedDotExpr>(baseExpr)) {
1259+
emitDiagnostic(baseExpr->getLoc(), diag::did_not_call_method,
1260+
UDE->getName().getBaseIdentifier())
1261+
.fixItInsertAfter(insertLoc, "()");
1262+
return true;
1263+
}
1264+
1265+
if (auto *DSCE = dyn_cast<DotSyntaxCallExpr>(baseExpr)) {
1266+
if (auto *DRE = dyn_cast<DeclRefExpr>(DSCE->getFn())) {
1267+
emitDiagnostic(baseExpr->getLoc(), diag::did_not_call_method,
1268+
DRE->getDecl()->getBaseName().getIdentifier())
1269+
.fixItInsertAfter(insertLoc, "()");
1270+
return true;
1271+
}
1272+
}
1273+
1274+
emitDiagnostic(baseExpr->getLoc(), diag::did_not_call_function_value)
1275+
.fixItInsertAfter(insertLoc, "()");
1276+
return true;
1277+
}

lib/Sema/CSDiagnostics.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,15 @@ class NonOptionalUnwrapFailure final : public FailureDiagnostic {
630630
bool diagnoseAsError() override;
631631
};
632632

633+
class MissingCallFailure final : public FailureDiagnostic {
634+
public:
635+
MissingCallFailure(Expr *root, ConstraintSystem &cs,
636+
ConstraintLocator *locator)
637+
: FailureDiagnostic(root, cs, locator) {}
638+
639+
bool diagnoseAsError() override;
640+
};
641+
633642
} // end namespace constraints
634643
} // end namespace swift
635644

lib/Sema/CSFix.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "ConstraintSystem.h"
2323
#include "swift/AST/Expr.h"
2424
#include "swift/AST/Type.h"
25+
#include "swift/AST/Types.h"
2526
#include "swift/Basic/SourceManager.h"
2627
#include "llvm/ADT/SmallString.h"
2728
#include "llvm/Support/raw_ostream.h"
@@ -224,3 +225,13 @@ RemoveUnwrap *RemoveUnwrap::create(ConstraintSystem &cs, Type baseType,
224225
ConstraintLocator *locator) {
225226
return new (cs.getAllocator()) RemoveUnwrap(cs, baseType, locator);
226227
}
228+
229+
bool InsertExplicitCall::diagnose(Expr *root, bool asNote) const {
230+
auto failure = MissingCallFailure(root, getConstraintSystem(), getLocator());
231+
return failure.diagnose(asNote);
232+
}
233+
234+
InsertExplicitCall *InsertExplicitCall::create(ConstraintSystem &cs,
235+
ConstraintLocator *locator) {
236+
return new (cs.getAllocator()) InsertExplicitCall(cs, locator);
237+
}

lib/Sema/CSFix.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "swift/AST/Expr.h"
2222
#include "swift/AST/Identifier.h"
2323
#include "swift/AST/Type.h"
24+
#include "swift/AST/Types.h"
2425
#include "llvm/ADT/ArrayRef.h"
2526
#include "llvm/ADT/SmallVector.h"
2627
#include "llvm/Support/TrailingObjects.h"
@@ -92,6 +93,9 @@ enum class FixKind : uint8_t {
9293

9394
/// Remove `!` or `?` because base is not an optional type.
9495
RemoveUnwrap,
96+
97+
/// Add explicit `()` at the end of function or member to call it.
98+
InsertCall,
9599
};
96100

97101
class ConstraintFix {
@@ -428,6 +432,21 @@ class RemoveUnwrap final : public ConstraintFix {
428432
ConstraintLocator *locator);
429433
};
430434

435+
class InsertExplicitCall final : public ConstraintFix {
436+
public:
437+
InsertExplicitCall(ConstraintSystem &cs, ConstraintLocator *locator)
438+
: ConstraintFix(cs, FixKind::InsertCall, locator) {}
439+
440+
std::string getName() const override {
441+
return "insert explicit `()` to make a call";
442+
}
443+
444+
bool diagnose(Expr *root, bool asNote = false) const override;
445+
446+
static InsertExplicitCall *create(ConstraintSystem &cs,
447+
ConstraintLocator *locator);
448+
};
449+
431450
} // end namespace constraints
432451
} // end namespace swift
433452

lib/Sema/CSSimplify.cpp

Lines changed: 63 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3734,49 +3734,72 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint(
37343734

37353735
// If the lookup found no hits at all (either viable or unviable), diagnose it
37363736
// as such and try to recover in various ways.
3737-
if (shouldAttemptFixes() && baseObjTy->getOptionalObjectType()) {
3738-
// If the base type was an optional, look through it.
3739-
3740-
// If the base type is optional because we haven't chosen to force an
3741-
// implicit optional, don't try to fix it. The IUO will be forced instead.
3742-
if (auto dotExpr = dyn_cast<UnresolvedDotExpr>(locator->getAnchor())) {
3743-
auto baseExpr = dotExpr->getBase();
3744-
auto resolvedOverload = getResolvedOverloadSets();
3745-
while (resolvedOverload) {
3746-
if (resolvedOverload->Locator->getAnchor() == baseExpr) {
3747-
if (resolvedOverload->Choice.isImplicitlyUnwrappedValueOrReturnValue())
3748-
return SolutionKind::Error;
3749-
break;
3737+
if (shouldAttemptFixes()) {
3738+
if (baseObjTy->getOptionalObjectType()) {
3739+
// If the base type was an optional, look through it.
3740+
3741+
// If the base type is optional because we haven't chosen to force an
3742+
// implicit optional, don't try to fix it. The IUO will be forced instead.
3743+
if (auto dotExpr = dyn_cast<UnresolvedDotExpr>(locator->getAnchor())) {
3744+
auto baseExpr = dotExpr->getBase();
3745+
auto resolvedOverload = getResolvedOverloadSets();
3746+
while (resolvedOverload) {
3747+
if (resolvedOverload->Locator->getAnchor() == baseExpr) {
3748+
if (resolvedOverload->Choice
3749+
.isImplicitlyUnwrappedValueOrReturnValue())
3750+
return SolutionKind::Error;
3751+
break;
3752+
}
3753+
resolvedOverload = resolvedOverload->Previous;
37503754
}
3751-
resolvedOverload = resolvedOverload->Previous;
37523755
}
3756+
3757+
// The result of the member access can either be the expected member type
3758+
// (for '!' or optional members with '?'), or the original member type
3759+
// with one extra level of optionality ('?' with non-optional members).
3760+
auto innerTV = createTypeVariable(locator, TVO_CanBindToLValue);
3761+
Type optTy = getTypeChecker().getOptionalType(
3762+
locator->getAnchor()->getSourceRange().Start, innerTV);
3763+
SmallVector<Constraint *, 2> optionalities;
3764+
auto nonoptionalResult = Constraint::createFixed(
3765+
*this, ConstraintKind::Bind,
3766+
UnwrapOptionalBase::create(*this, member, locator), innerTV, memberTy,
3767+
locator);
3768+
auto optionalResult = Constraint::createFixed(
3769+
*this, ConstraintKind::Bind,
3770+
UnwrapOptionalBase::createWithOptionalResult(*this, member, locator),
3771+
optTy, memberTy, locator);
3772+
optionalities.push_back(nonoptionalResult);
3773+
optionalities.push_back(optionalResult);
3774+
addDisjunctionConstraint(optionalities, locator);
3775+
3776+
// Look through one level of optional.
3777+
addValueMemberConstraint(baseObjTy->getOptionalObjectType(), member,
3778+
innerTV, useDC, functionRefKind,
3779+
outerAlternatives, locator);
3780+
return SolutionKind::Solved;
37533781
}
37543782

3755-
// The result of the member access can either be the expected member type
3756-
// (for '!' or optional members with '?'), or the original member type with
3757-
// one extra level of optionality ('?' with non-optional members).
3758-
auto innerTV =
3759-
createTypeVariable(locator, TVO_CanBindToLValue);
3760-
Type optTy = getTypeChecker().getOptionalType(
3761-
locator->getAnchor()->getSourceRange().Start, innerTV);
3762-
SmallVector<Constraint *, 2> optionalities;
3763-
auto nonoptionalResult = Constraint::createFixed(
3764-
*this, ConstraintKind::Bind,
3765-
UnwrapOptionalBase::create(*this, member, locator), innerTV, memberTy,
3766-
locator);
3767-
auto optionalResult = Constraint::createFixed(
3768-
*this, ConstraintKind::Bind,
3769-
UnwrapOptionalBase::createWithOptionalResult(*this, member, locator),
3770-
optTy, memberTy, locator);
3771-
optionalities.push_back(nonoptionalResult);
3772-
optionalities.push_back(optionalResult);
3773-
addDisjunctionConstraint(optionalities, locator);
3774-
3775-
// Look through one level of optional.
3776-
addValueMemberConstraint(baseObjTy->getOptionalObjectType(), member,
3777-
innerTV, useDC, functionRefKind, outerAlternatives,
3778-
locator);
3779-
return SolutionKind::Solved;
3783+
if (auto *funcType = baseTy->getAs<FunctionType>()) {
3784+
// We can't really suggest anything useful unless
3785+
// function takes no arguments, otherwise it
3786+
// would make sense to report this a missing member.
3787+
if (funcType->getNumParams() == 0) {
3788+
auto *fix = InsertExplicitCall::create(*this, locator);
3789+
if (recordFix(fix))
3790+
return SolutionKind::Error;
3791+
3792+
auto result = simplifyMemberConstraint(
3793+
kind, funcType->getResult(), member, memberTy, useDC,
3794+
functionRefKind, outerAlternatives, flags, locatorB);
3795+
3796+
// If there is indeed a member with given name in result type
3797+
// let's return, otherwise let's fall-through and report
3798+
// this problem as a missing member.
3799+
if (result == SolutionKind::Solved)
3800+
return result;
3801+
}
3802+
}
37803803
}
37813804
return SolutionKind::Error;
37823805
}
@@ -5439,6 +5462,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
54395462
return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved;
54405463
}
54415464

5465+
case FixKind::InsertCall:
54425466
case FixKind::ExplicitlyEscaping:
54435467
case FixKind::CoerceToCheckedCast:
54445468
case FixKind::RelabelArguments:

test/Constraints/fixes.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,10 @@ class U {
104104

105105
class T {
106106
func m1() {
107-
// FIXME: should apply nullary function fixit here. {{function produces expected type 'U'; did you mean to call it with '()'?}}
108-
// <rdar://problem/17741575>
109-
let l = self.m2!.prop1 // expected-error{{cannot force unwrap value of non-optional type '() -> U?'}} {{24-25=}}
107+
// <rdar://problem/17741575>
108+
let l = self.m2!.prop1
109+
// expected-error@-1 {{cannot force unwrap value of non-optional type '() -> U?'}} {{22-23=}}
110+
// expected-error@-2 {{method 'm2' was used as a property; add () to call it}} {{23-23=()}}
110111
}
111112

112113
func m2() -> U! {

0 commit comments

Comments
 (0)