[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.
This commit is contained in:
Pavel Yaskevich
2018-12-11 16:10:05 -08:00
parent ebbfa85388
commit f086d41094
3 changed files with 90 additions and 37 deletions

View File

@@ -3734,49 +3734,72 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint(
// If the lookup found no hits at all (either viable or unviable), diagnose it
// as such and try to recover in various ways.
if (shouldAttemptFixes() && baseObjTy->getOptionalObjectType()) {
// If the base type was an optional, look through it.
if (shouldAttemptFixes()) {
if (baseObjTy->getOptionalObjectType()) {
// If the base type was an optional, look through it.
// If the base type is optional because we haven't chosen to force an
// implicit optional, don't try to fix it. The IUO will be forced instead.
if (auto dotExpr = dyn_cast<UnresolvedDotExpr>(locator->getAnchor())) {
auto baseExpr = dotExpr->getBase();
auto resolvedOverload = getResolvedOverloadSets();
while (resolvedOverload) {
if (resolvedOverload->Locator->getAnchor() == baseExpr) {
if (resolvedOverload->Choice.isImplicitlyUnwrappedValueOrReturnValue())
return SolutionKind::Error;
break;
// If the base type is optional because we haven't chosen to force an
// implicit optional, don't try to fix it. The IUO will be forced instead.
if (auto dotExpr = dyn_cast<UnresolvedDotExpr>(locator->getAnchor())) {
auto baseExpr = dotExpr->getBase();
auto resolvedOverload = getResolvedOverloadSets();
while (resolvedOverload) {
if (resolvedOverload->Locator->getAnchor() == baseExpr) {
if (resolvedOverload->Choice
.isImplicitlyUnwrappedValueOrReturnValue())
return SolutionKind::Error;
break;
}
resolvedOverload = resolvedOverload->Previous;
}
resolvedOverload = resolvedOverload->Previous;
}
// The result of the member access can either be the expected member type
// (for '!' or optional members with '?'), or the original member type
// with one extra level of optionality ('?' with non-optional members).
auto innerTV = createTypeVariable(locator, TVO_CanBindToLValue);
Type optTy = getTypeChecker().getOptionalType(
locator->getAnchor()->getSourceRange().Start, innerTV);
SmallVector<Constraint *, 2> optionalities;
auto nonoptionalResult = Constraint::createFixed(
*this, ConstraintKind::Bind,
UnwrapOptionalBase::create(*this, member, locator), innerTV, memberTy,
locator);
auto optionalResult = Constraint::createFixed(
*this, ConstraintKind::Bind,
UnwrapOptionalBase::createWithOptionalResult(*this, member, locator),
optTy, memberTy, locator);
optionalities.push_back(nonoptionalResult);
optionalities.push_back(optionalResult);
addDisjunctionConstraint(optionalities, locator);
// Look through one level of optional.
addValueMemberConstraint(baseObjTy->getOptionalObjectType(), member,
innerTV, useDC, functionRefKind,
outerAlternatives, locator);
return SolutionKind::Solved;
}
// The result of the member access can either be the expected member type
// (for '!' or optional members with '?'), or the original member type with
// one extra level of optionality ('?' with non-optional members).
auto innerTV =
createTypeVariable(locator, TVO_CanBindToLValue);
Type optTy = getTypeChecker().getOptionalType(
locator->getAnchor()->getSourceRange().Start, innerTV);
SmallVector<Constraint *, 2> optionalities;
auto nonoptionalResult = Constraint::createFixed(
*this, ConstraintKind::Bind,
UnwrapOptionalBase::create(*this, member, locator), innerTV, memberTy,
locator);
auto optionalResult = Constraint::createFixed(
*this, ConstraintKind::Bind,
UnwrapOptionalBase::createWithOptionalResult(*this, member, locator),
optTy, memberTy, locator);
optionalities.push_back(nonoptionalResult);
optionalities.push_back(optionalResult);
addDisjunctionConstraint(optionalities, locator);
if (auto *funcType = baseTy->getAs<FunctionType>()) {
// We can't really suggest anything useful unless
// function takes no arguments, otherwise it
// would make sense to report this a missing member.
if (funcType->getNumParams() == 0) {
auto *fix = InsertExplicitCall::create(*this, locator);
if (recordFix(fix))
return SolutionKind::Error;
// Look through one level of optional.
addValueMemberConstraint(baseObjTy->getOptionalObjectType(), member,
innerTV, useDC, functionRefKind, outerAlternatives,
locator);
return SolutionKind::Solved;
auto result = simplifyMemberConstraint(
kind, funcType->getResult(), member, memberTy, useDC,
functionRefKind, outerAlternatives, flags, locatorB);
// If there is indeed a member with given name in result type
// let's return, otherwise let's fall-through and report
// this problem as a missing member.
if (result == SolutionKind::Solved)
return result;
}
}
}
return SolutionKind::Error;
}
@@ -5439,6 +5462,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved;
}
case FixKind::InsertCall:
case FixKind::ExplicitlyEscaping:
case FixKind::CoerceToCheckedCast:
case FixKind::RelabelArguments: