Skip to content

Commit f72576d

Browse files
authored
Merge pull request #5237 from xedin/SR-2484
SR-2484: Improve diagnostic for incorrectly called private init
2 parents 47f0c3a + 352f4b7 commit f72576d

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
@@ -1889,8 +1889,11 @@ bool CalleeCandidateInfo::diagnoseSimpleErrors(const Expr *E) {
18891889
CS->TC.diagnose(loc, diag::candidate_inaccessible, decl->getName(),
18901890
decl->getFormalAccess());
18911891
}
1892-
for (auto cand : candidates)
1893-
CS->TC.diagnose(cand.getDecl(),diag::decl_declared_here, decl->getName());
1892+
for (auto cand : candidates) {
1893+
if (auto decl = cand.getDecl()) {
1894+
CS->TC.diagnose(decl, diag::decl_declared_here, decl->getFullName());
1895+
}
1896+
}
18941897

18951898
return true;
18961899
}
@@ -2247,7 +2250,8 @@ bool FailureDiagnosis::diagnoseGeneralMemberFailure(Constraint *constraint) {
22472250
assert(isMemberConstraint(constraint));
22482251

22492252
auto memberName = constraint->getMember();
2250-
2253+
auto isInitializer = memberName.isSimpleName(CS->TC.Context.Id_init);
2254+
22512255
// Get the referenced base expression from the failed constraint, along with
22522256
// the SourceRange for the member ref. In "x.y", this returns the expr for x
22532257
// and the source range for y.
@@ -2340,12 +2344,21 @@ bool FailureDiagnosis::diagnoseGeneralMemberFailure(Constraint *constraint) {
23402344
.highlight(anchor->getSourceRange()).highlight(memberRange);
23412345
return true;
23422346
}
2343-
2344-
MemberLookupResult result =
2345-
CS->performMemberLookup(constraint->getKind(), constraint->getMember(),
2346-
baseTy, constraint->getFunctionRefKind(),
2347-
constraint->getLocator(),
2348-
/*includeInaccessibleMembers*/true);
2347+
2348+
// If this is initializer/constructor lookup we are dealing this.
2349+
if (isInitializer) {
2350+
// Let's check what is the base type we are trying to look it up on
2351+
// because only MetatypeType is viable to find constructor on, as per
2352+
// rules in ConstraintSystem::performMemberLookup.
2353+
if (!baseTy->is<AnyMetatypeType>()) {
2354+
baseTy = MetatypeType::get(baseTy, CS->getASTContext());
2355+
}
2356+
}
2357+
2358+
MemberLookupResult result = CS->performMemberLookup(
2359+
constraint->getKind(), memberName, baseTy,
2360+
constraint->getFunctionRefKind(), constraint->getLocator(),
2361+
/*includeInaccessibleMembers*/ true);
23492362

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

2435+
if (result.ViableCandidates.empty()) {
23912436
// FIXME: Dig out the property DeclNameLoc.
23922437
diagnoseUnviableLookupResults(result, baseObjTy, anchor, memberName,
23932438
DeclNameLoc(memberRange.Start),
23942439
anchor->getLoc());
23952440
return true;
23962441
}
23972442

2398-
2399-
bool allUnavailable = !CS->TC.getLangOpts().DisableAvailabilityChecking;
2400-
for (auto match : result.ViableCandidates) {
2401-
if (!match.isDecl() ||
2402-
!match.getDecl()->getAttrs().isUnavailable(CS->getASTContext()))
2403-
allUnavailable = false;
2404-
}
2405-
24062443
if (allUnavailable) {
24072444
auto firstDecl = result.ViableCandidates[0].getDecl();
24082445
// 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)