Skip to content

Commit 174fd14

Browse files
committed
[CSDiagnostics] Diagnose invalid partial application of init delegation
1 parent 315a0ad commit 174fd14

File tree

2 files changed

+64
-13
lines changed

2 files changed

+64
-13
lines changed

lib/Sema/CSDiagnostics.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1479,11 +1479,22 @@ bool MissingMemberFailure::diagnoseAsError() {
14791479
}
14801480

14811481
bool PartialApplicationFailure::diagnoseAsError() {
1482+
auto &cs = getConstraintSystem();
14821483
auto *anchor = cast<UnresolvedDotExpr>(getRawAnchor());
1484+
1485+
RefKind kind = RefKind::MutatingMethod;
1486+
1487+
// If this is initializer delegation chain, we have a tailored message.
1488+
if (getOverloadChoiceIfAvailable(cs.getConstraintLocator(
1489+
anchor, ConstraintLocator::ConstructorMember))) {
1490+
kind = anchor->getBase()->isSuperExpr() ? RefKind::SuperInit
1491+
: RefKind::SelfInit;
1492+
}
1493+
14831494
auto diagnostic = CompatibilityWarning
14841495
? diag::partial_application_of_function_invalid_swift4
14851496
: diag::partial_application_of_function_invalid;
14861497

1487-
emitDiagnostic(anchor->getNameLoc(), diagnostic, RefKind::MutatingMethod);
1498+
emitDiagnostic(anchor->getNameLoc(), diagnostic, kind);
14881499
return true;
14891500
}

lib/Sema/ConstraintSystem.cpp

Lines changed: 52 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1640,27 +1640,62 @@ bool isMutatingMethod(const ValueDecl *decl) {
16401640
return cast<FuncDecl>(decl)->isMutating();
16411641
}
16421642

1643+
static bool shouldCheckForPartialApplication(ConstraintSystem &cs,
1644+
const ValueDecl *decl,
1645+
ConstraintLocator *locator) {
1646+
auto *anchor = locator->getAnchor();
1647+
if (!(anchor && isa<UnresolvedDotExpr>(anchor)))
1648+
return false;
1649+
1650+
// FIXME(diagnostics): This check should be removed together with
1651+
// expression based diagnostics.
1652+
if (cs.TC.isExprBeingDiagnosed(anchor))
1653+
return false;
1654+
1655+
// If this is a reference to instance method marked as 'mutating'
1656+
// it should be checked for invalid partial application.
1657+
if (isMutatingMethod(decl))
1658+
return true;
1659+
1660+
// Another unsupported partial application is related
1661+
// to constructor delegation via `self.init` or `super.init`.
1662+
1663+
if (!isa<ConstructorDecl>(decl))
1664+
return false;
1665+
1666+
auto *UDE = cast<UnresolvedDotExpr>(anchor);
1667+
// This is `super.init`
1668+
if (UDE->getBase()->isSuperExpr())
1669+
return true;
1670+
1671+
// Or this might be `self.init`.
1672+
if (auto *DRE = dyn_cast<DeclRefExpr>(UDE->getBase())) {
1673+
if (auto *baseDecl = DRE->getDecl())
1674+
return baseDecl->getBaseName() == cs.getASTContext().Id_self;
1675+
}
1676+
1677+
return false;
1678+
}
1679+
16431680
/// Try to identify and fix failures related to partial function application
16441681
/// e.g. partial application of `init` or 'mutating' instance methods.
16451682
static std::pair<bool, unsigned>
16461683
isInvalidPartialApplication(ConstraintSystem &cs, const ValueDecl *member,
16471684
ConstraintLocator *locator) {
1648-
if (!isMutatingMethod(member))
1649-
return {false, 0};
1650-
1651-
auto *anchor = locator->getAnchor();
1652-
if (!isa<UnresolvedDotExpr>(anchor))
1685+
if (!shouldCheckForPartialApplication(cs, member, locator))
16531686
return {false, 0};
16541687

1688+
auto anchor = cast<UnresolvedDotExpr>(locator->getAnchor());
16551689
// If this choice is a partial application of `init` or
16561690
// `mutating` instance method we should report that it's not allowed.
1657-
auto baseTy = cs.getType(cast<UnresolvedDotExpr>(anchor)->getBase())
1658-
->getWithoutSpecifierType();
1659-
1660-
// If base is a metatype it would be ignored, but if it is
1661-
// some other type it means that we have a single application
1662-
// level already.
1663-
unsigned level = cs.simplifyType(baseTy)->is<MetatypeType>() ? 0 : 1;
1691+
auto baseTy =
1692+
cs.simplifyType(cs.getType(anchor->getBase()))->getWithoutSpecifierType();
1693+
1694+
// If base is a metatype it would be ignored (unless this is an initializer
1695+
// call), but if it is some other type it means that we have a single
1696+
// application level already.
1697+
unsigned level =
1698+
baseTy->is<MetatypeType>() && !isa<ConstructorDecl>(member) ? 0 : 1;
16641699
if (auto *call = dyn_cast_or_null<CallExpr>(cs.getParentExpr(anchor))) {
16651700
level += dyn_cast_or_null<CallExpr>(cs.getParentExpr(call)) ? 2 : 1;
16661701
}
@@ -1926,6 +1961,11 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator,
19261961
// partial function application e.g. partial application of
19271962
// mutating method or initializer.
19281963

1964+
// This check is supposed to be performed without
1965+
// `shouldAttemptFixes` because name lookup can't
1966+
// detect that particular partial application is
1967+
// invalid, so it has to return all of the candidates.
1968+
19291969
bool isInvalidPartialApply;
19301970
unsigned level;
19311971

0 commit comments

Comments
 (0)