Skip to content

[Sema] Minimum access for override method is fileprivate #4404

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 19, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions lib/Sema/TypeCheckDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5548,11 +5548,12 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
std::min(classDecl->getFormalAccess(), overriddenAccess);
if (requiredAccess == Accessibility::Open && decl->isFinal())
requiredAccess = Accessibility::Public;
else if (requiredAccess == Accessibility::Private)
requiredAccess = Accessibility::FilePrivate;

bool shouldDiagnose = false;
bool shouldDiagnoseSetter = false;
if (requiredAccess > Accessibility::Private &&
!isa<ConstructorDecl>(decl)) {
if (!isa<ConstructorDecl>(decl)) {
shouldDiagnose = (decl->getFormalAccess() < requiredAccess);

if (!shouldDiagnose && matchDecl->isSettable(classDecl)) {
Expand All @@ -5562,6 +5563,8 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
const DeclContext *accessDC = nullptr;
if (requiredAccess == Accessibility::Internal)
accessDC = classDecl->getParentModule();
else if (requiredAccess == Accessibility::FilePrivate)
accessDC = classDecl->getDeclContext();
shouldDiagnoseSetter = ASD->isSettable(accessDC) &&
!ASD->isSetterAccessibleFrom(accessDC);
}
Expand Down Expand Up @@ -6494,11 +6497,14 @@ class DeclChecker : public DeclVisitor<DeclChecker> {

if (CD->isRequired() && ContextTy) {
if (auto nominal = ContextTy->getAnyNominal()) {
if (CD->getFormalAccess() <
std::min(nominal->getFormalAccess(), Accessibility::Public)) {
auto requiredAccess = std::min(nominal->getFormalAccess(),
Accessibility::Public);
if (requiredAccess == Accessibility::Private)
requiredAccess = Accessibility::FilePrivate;
if (CD->getFormalAccess() < requiredAccess) {
auto diag = TC.diagnose(CD,
diag::required_initializer_not_accessible);
fixItAccessibility(diag, CD, nominal->getFormalAccess());
fixItAccessibility(diag, CD, requiredAccess);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion test/SILGen/Inputs/mangling_private_helper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ open class Base {
// Demonstrate the need for a vtable entry for privateMethod().
// This isn't strictly necessary.
private class Subclass : Base {
override private func privateMethod() {}
override fileprivate func privateMethod() {}
}
2 changes: 1 addition & 1 deletion test/SILOptimizer/Inputs/devirt_access_other_module.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@ public func getExternalClass() -> ExternalClass {
}

private class PrivateSubclass : ExternalClass {
override private func foo() {}
override fileprivate func foo() {}
}
32 changes: 32 additions & 0 deletions test/Sema/accessibility.swift
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,38 @@ internal class InternalSubPrivateSet: Base {
}
}

private class PrivateSub: Base {
required private init() {} // expected-error {{'required' initializer must be as accessible as its enclosing type}} {{12-19=fileprivate}}
private override func foo() {} // expected-error {{overriding instance method must be as accessible as its enclosing type}} {{3-10=fileprivate}}
private override var bar: Int { // expected-error {{overriding var must be as accessible as its enclosing type}} {{3-10=fileprivate}}
get { return 0 }
set {}
}
private override subscript () -> () { return () } // expected-error {{overriding subscript must be as accessible as its enclosing type}} {{3-10=fileprivate}}
}

private class PrivateSubGood: Base {
required fileprivate init() {}
fileprivate override func foo() {}
fileprivate override var bar: Int {
get { return 0 }
set {}
}
fileprivate override subscript () -> () { return () }
}

private class PrivateSubPrivateSet: Base {
required fileprivate init() {}
fileprivate override func foo() {}
private(set) override var bar: Int { // expected-error {{setter of overriding var must be as accessible as its enclosing type}}
get { return 0 }
set {}
}
private(set) override subscript () -> () { // okay; read-only in base class
get { return () }
set {}
}
}

public typealias PublicTA1 = PublicStruct
public typealias PublicTA2 = InternalStruct // expected-error {{type alias cannot be declared public because its underlying type uses an internal type}}
Expand Down