Skip to content

Commit f086d41

Browse files
committed
[CSFix] Call a function/member which is incorrectly used as a property
If the base type for the member lookup is a function, let's try to use its result type as a base instead, maybe there is just a call missing.
1 parent ebbfa85 commit f086d41

File tree

3 files changed

+92
-39
lines changed

3 files changed

+92
-39
lines changed

lib/Sema/CSFix.cpp

Lines changed: 10 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,12 @@ 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+
return false;
231+
}
232+
233+
InsertExplicitCall *InsertExplicitCall::create(ConstraintSystem &cs,
234+
ConstraintLocator *locator) {
235+
return new (cs.getAllocator()) InsertExplicitCall(cs, locator);
236+
}

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:

0 commit comments

Comments
 (0)