Skip to content

Commit 352f4b7

Browse files
committed
[Diagnostics] SR-2484: Improve diagnostic for incorrectly called private init
1 parent dbdda27 commit 352f4b7

File tree

3 files changed

+89
-41
lines changed

3 files changed

+89
-41
lines changed

lib/Sema/CSDiag.cpp

Lines changed: 77 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1877,8 +1877,11 @@ bool CalleeCandidateInfo::diagnoseSimpleErrors(const Expr *E) {
18771877
CS->TC.diagnose(loc, diag::candidate_inaccessible, decl->getName(),
18781878
decl->getFormalAccess());
18791879
}
1880-
for (auto cand : candidates)
1881-
CS->TC.diagnose(cand.getDecl(),diag::decl_declared_here, decl->getName());
1880+
for (auto cand : candidates) {
1881+
if (auto decl = cand.getDecl()) {
1882+
CS->TC.diagnose(decl, diag::decl_declared_here, decl->getFullName());
1883+
}
1884+
}
18821885

18831886
return true;
18841887
}
@@ -2235,7 +2238,8 @@ bool FailureDiagnosis::diagnoseGeneralMemberFailure(Constraint *constraint) {
22352238
assert(isMemberConstraint(constraint));
22362239

22372240
auto memberName = constraint->getMember();
2238-
2241+
auto isInitializer = memberName.isSimpleName(CS->TC.Context.Id_init);
2242+
22392243
// Get the referenced base expression from the failed constraint, along with
22402244
// the SourceRange for the member ref. In "x.y", this returns the expr for x
22412245
// and the source range for y.
@@ -2328,12 +2332,21 @@ bool FailureDiagnosis::diagnoseGeneralMemberFailure(Constraint *constraint) {
23282332
.highlight(anchor->getSourceRange()).highlight(memberRange);
23292333
return true;
23302334
}
2331-
2332-
MemberLookupResult result =
2333-
CS->performMemberLookup(constraint->getKind(), constraint->getMember(),
2334-
baseTy, constraint->getFunctionRefKind(),
2335-
constraint->getLocator(),
2336-
/*includeInaccessibleMembers*/true);
2335+
2336+
// If this is initializer/constructor lookup we are dealing this.
2337+
if (isInitializer) {
2338+
// Let's check what is the base type we are trying to look it up on
2339+
// because only MetatypeType is viable to find constructor on, as per
2340+
// rules in ConstraintSystem::performMemberLookup.
2341+
if (!baseTy->is<AnyMetatypeType>()) {
2342+
baseTy = MetatypeType::get(baseTy, CS->getASTContext());
2343+
}
2344+
}
2345+
2346+
MemberLookupResult result = CS->performMemberLookup(
2347+
constraint->getKind(), memberName, baseTy,
2348+
constraint->getFunctionRefKind(), constraint->getLocator(),
2349+
/*includeInaccessibleMembers*/ true);
23372350

23382351
switch (result.OverallResult) {
23392352
case MemberLookupResult::Unsolved:
@@ -2349,48 +2362,72 @@ bool FailureDiagnosis::diagnoseGeneralMemberFailure(Constraint *constraint) {
23492362
case MemberLookupResult::HasResults:
23502363
break;
23512364
}
2352-
2353-
// If this is a failing lookup, it has no viable candidates here.
2354-
if (result.ViableCandidates.empty()) {
2355-
// Diagnose 'super.init', which can only appear inside another initializer,
2356-
// specially.
2357-
if (result.UnviableCandidates.empty() &&
2358-
memberName.isSimpleName(CS->TC.Context.Id_init) &&
2359-
!baseObjTy->is<MetatypeType>()) {
2360-
if (auto ctorRef = dyn_cast<UnresolvedDotExpr>(expr)) {
2361-
if (isa<SuperRefExpr>(ctorRef->getBase())) {
2362-
diagnose(anchor->getLoc(),
2363-
diag::super_initializer_not_in_initializer);
2364-
return true;
2365-
}
2366-
2367-
// Suggest inserting a call to 'type(of:)' to construct another object
2368-
// of the same dynamic type.
2369-
SourceRange fixItRng = ctorRef->getNameLoc().getSourceRange();
2370-
2371-
// Surround the caller in `type(of:)`.
2372-
diagnose(anchor->getLoc(), diag::init_not_instance_member)
2373-
.fixItInsert(fixItRng.Start, "type(of: ")
2374-
.fixItInsertAfter(fixItRng.End, ")");
2365+
2366+
// Since the lookup was allowing inaccessible members, let's check
2367+
// if it found anything of that sort, which is easy to diagnose.
2368+
bool allUnavailable = !CS->TC.getLangOpts().DisableAvailabilityChecking;
2369+
for (auto &member : result.ViableCandidates) {
2370+
if (!member.isDecl()) {
2371+
// if there is no declaration, this choice is implicitly available.
2372+
allUnavailable = false;
2373+
continue;
2374+
}
2375+
2376+
auto decl = member.getDecl();
2377+
// Check availability of the found choice.
2378+
if (!decl->getAttrs().isUnavailable(CS->getASTContext()))
2379+
allUnavailable = false;
2380+
2381+
if (decl->isAccessibleFrom(CS->DC))
2382+
continue;
2383+
2384+
if (auto *CD = dyn_cast<ConstructorDecl>(decl)) {
2385+
CS->TC.diagnose(anchor->getLoc(), diag::init_candidate_inaccessible,
2386+
CD->getResultType(), decl->getFormalAccess());
2387+
} else {
2388+
CS->TC.diagnose(anchor->getLoc(), diag::candidate_inaccessible,
2389+
decl->getName(), decl->getFormalAccess());
2390+
}
2391+
2392+
for (auto &candidate : result.ViableCandidates) {
2393+
if (auto decl = candidate.getDecl()) {
2394+
CS->TC.diagnose(decl, diag::decl_declared_here, decl->getFullName());
2395+
}
2396+
}
2397+
2398+
return true;
2399+
}
2400+
2401+
// Diagnose 'super.init', which can only appear inside another initializer,
2402+
// specially.
2403+
if (result.UnviableCandidates.empty() && isInitializer &&
2404+
!baseObjTy->is<MetatypeType>()) {
2405+
if (auto ctorRef = dyn_cast<UnresolvedDotExpr>(expr)) {
2406+
if (isa<SuperRefExpr>(ctorRef->getBase())) {
2407+
diagnose(anchor->getLoc(), diag::super_initializer_not_in_initializer);
23752408
return true;
23762409
}
2410+
2411+
// Suggest inserting a call to 'type(of:)' to construct another object
2412+
// of the same dynamic type.
2413+
SourceRange fixItRng = ctorRef->getNameLoc().getSourceRange();
2414+
2415+
// Surround the caller in `type(of:)`.
2416+
diagnose(anchor->getLoc(), diag::init_not_instance_member)
2417+
.fixItInsert(fixItRng.Start, "type(of: ")
2418+
.fixItInsertAfter(fixItRng.End, ")");
2419+
return true;
23772420
}
2421+
}
23782422

2423+
if (result.ViableCandidates.empty()) {
23792424
// FIXME: Dig out the property DeclNameLoc.
23802425
diagnoseUnviableLookupResults(result, baseObjTy, anchor, memberName,
23812426
DeclNameLoc(memberRange.Start),
23822427
anchor->getLoc());
23832428
return true;
23842429
}
23852430

2386-
2387-
bool allUnavailable = !CS->TC.getLangOpts().DisableAvailabilityChecking;
2388-
for (auto match : result.ViableCandidates) {
2389-
if (!match.isDecl() ||
2390-
!match.getDecl()->getAttrs().isUnavailable(CS->getASTContext()))
2391-
allUnavailable = false;
2392-
}
2393-
23942431
if (allUnavailable) {
23952432
auto firstDecl = result.ViableCandidates[0].getDecl();
23962433
// FIXME: We need the enclosing CallExpr to rewrite the argument labels.

test/Constraints/super_constructor.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,14 @@ class B {
5353
}
5454
}
5555

56+
// SR-2484: Bad diagnostic for incorrectly calling private init
57+
class SR_2484 {
58+
private init() {} // expected-note {{'init()' declared here}}
59+
private init(a: Int) {} // expected-note {{'init(a:)' declared here}}
60+
}
61+
62+
class Impl_2484 : SR_2484 {
63+
init() {
64+
super.init() // expected-error {{'SR_2484' initializer is inaccessible due to 'private' protection level}}
65+
}
66+
}

test/NameBinding/Inputs/accessibility_other.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ extension Foo {
1111
}
1212

1313
struct PrivateInit {
14-
private init() {} // expected-note {{'init' declared here}}
14+
private init() {} // expected-note {{'init()' declared here}}
1515
}
1616

1717
extension Foo {

0 commit comments

Comments
 (0)