mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[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:
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user