Skip to content

Commit 9a217b5

Browse files
committed
Switch override checking over to access scopes.
The class version of f65ad81. Fixes some incorrect diagnostics. We really do need https://bugs.swift.org/browse/SR-2209 to make this all cleaner. rdar://problem/27820665
1 parent 5d21c2a commit 9a217b5

File tree

3 files changed

+157
-44
lines changed

3 files changed

+157
-44
lines changed

lib/Sema/TypeCheckDecl.cpp

Lines changed: 69 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -5538,62 +5538,87 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
55385538
}
55395539
}
55405540

5541-
auto overriddenAccess = matchDecl->getFormalAccess();
5542-
55435541
// Check that the override has the required accessibility.
55445542
// Overrides have to be at least as accessible as what they
55455543
// override, except:
55465544
// - they don't have to be more accessible than their class and
55475545
// - a final method may be public instead of open.
5548-
// FIXME: Copied from TypeCheckProtocol.cpp.
5549-
Accessibility requiredAccess =
5550-
std::min(classDecl->getFormalAccess(), overriddenAccess);
5551-
if (requiredAccess == Accessibility::Open && decl->isFinal())
5552-
requiredAccess = Accessibility::Public;
5553-
else if (requiredAccess == Accessibility::Private)
5554-
requiredAccess = Accessibility::FilePrivate;
5555-
5556-
bool shouldDiagnose = false;
5557-
bool shouldDiagnoseSetter = false;
5558-
if (!isa<ConstructorDecl>(decl)) {
5559-
shouldDiagnose = (decl->getFormalAccess() < requiredAccess);
5560-
5561-
if (!shouldDiagnose && matchDecl->isSettable(classDecl)) {
5562-
auto matchASD = cast<AbstractStorageDecl>(matchDecl);
5563-
if (matchASD->isSetterAccessibleFrom(classDecl)) {
5564-
auto ASD = cast<AbstractStorageDecl>(decl);
5565-
const DeclContext *accessDC = nullptr;
5566-
if (requiredAccess == Accessibility::Internal)
5567-
accessDC = classDecl->getParentModule();
5568-
else if (requiredAccess == Accessibility::FilePrivate)
5569-
accessDC = classDecl->getDeclContext();
5570-
shouldDiagnoseSetter = ASD->isSettable(accessDC) &&
5571-
!ASD->isSetterAccessibleFrom(accessDC);
5572-
}
5573-
}
5574-
}
5575-
if (shouldDiagnose || shouldDiagnoseSetter) {
5576-
bool overriddenForcesAccess = (requiredAccess == overriddenAccess);
5577-
{
5578-
auto diag = TC.diagnose(decl, diag::override_not_accessible,
5579-
shouldDiagnoseSetter,
5580-
decl->getDescriptiveKind(),
5581-
overriddenForcesAccess);
5582-
fixItAccessibility(diag, decl, requiredAccess, shouldDiagnoseSetter);
5583-
}
5584-
TC.diagnose(matchDecl, diag::overridden_here);
5585-
}
5586-
5587-
// Diagnose attempts to override a non-open method from outside its
5546+
// Also diagnose attempts to override a non-open method from outside its
55885547
// defining module. This is not required for constructors, which are
55895548
// never really "overridden" in the intended sense here, because of
55905549
// course derived classes will change how the class is initialized.
5591-
if (matchDecl->getFormalAccess(decl->getDeclContext())
5592-
< Accessibility::Open &&
5550+
Accessibility matchAccess =
5551+
matchDecl->getFormalAccess(decl->getDeclContext());
5552+
if (matchAccess < Accessibility::Open &&
55935553
matchDecl->getModuleContext() != decl->getModuleContext() &&
55945554
!isa<ConstructorDecl>(decl)) {
55955555
TC.diagnose(decl, diag::override_of_non_open,
55965556
decl->getDescriptiveKind());
5557+
5558+
} else if (matchAccess == Accessibility::Open &&
5559+
classDecl->getFormalAccess(decl->getDeclContext()) ==
5560+
Accessibility::Open &&
5561+
decl->getFormalAccess() != Accessibility::Open &&
5562+
!decl->isFinal()) {
5563+
{
5564+
auto diag = TC.diagnose(decl, diag::override_not_accessible,
5565+
/*setter*/false,
5566+
decl->getDescriptiveKind(),
5567+
/*fromOverridden*/true);
5568+
fixItAccessibility(diag, decl, Accessibility::Open);
5569+
}
5570+
TC.diagnose(matchDecl, diag::overridden_here);
5571+
5572+
} else {
5573+
auto matchAccessScope =
5574+
matchDecl->getFormalAccessScope(decl->getDeclContext());
5575+
const DeclContext *requiredAccessScope =
5576+
classDecl->getFormalAccessScope(decl->getDeclContext());
5577+
5578+
// FIXME: This is the same operation as
5579+
// TypeAccessScopeChecker::intersectAccess.
5580+
if (!requiredAccessScope) {
5581+
requiredAccessScope = matchAccessScope;
5582+
} else if (matchAccessScope) {
5583+
if (matchAccessScope->isChildContextOf(requiredAccessScope)) {
5584+
requiredAccessScope = matchAccessScope;
5585+
} else {
5586+
assert(requiredAccessScope == matchAccessScope ||
5587+
requiredAccessScope->isChildContextOf(matchAccessScope));
5588+
}
5589+
}
5590+
5591+
bool shouldDiagnose = false;
5592+
bool shouldDiagnoseSetter = false;
5593+
if (!isa<ConstructorDecl>(decl)) {
5594+
shouldDiagnose = !decl->isAccessibleFrom(requiredAccessScope);
5595+
5596+
if (!shouldDiagnose && matchDecl->isSettable(decl->getDeclContext())){
5597+
auto matchASD = cast<AbstractStorageDecl>(matchDecl);
5598+
if (matchASD->isSetterAccessibleFrom(decl->getDeclContext())) {
5599+
const auto *ASD = cast<AbstractStorageDecl>(decl);
5600+
shouldDiagnoseSetter =
5601+
ASD->isSettable(requiredAccessScope) &&
5602+
!ASD->isSetterAccessibleFrom(requiredAccessScope);
5603+
}
5604+
}
5605+
}
5606+
if (shouldDiagnose || shouldDiagnoseSetter) {
5607+
bool overriddenForcesAccess =
5608+
(requiredAccessScope == matchAccessScope &&
5609+
matchAccess != Accessibility::Open);
5610+
Accessibility requiredAccess =
5611+
accessibilityFromScopeForDiagnostics(requiredAccessScope);
5612+
{
5613+
auto diag = TC.diagnose(decl, diag::override_not_accessible,
5614+
shouldDiagnoseSetter,
5615+
decl->getDescriptiveKind(),
5616+
overriddenForcesAccess);
5617+
fixItAccessibility(diag, decl, requiredAccess,
5618+
shouldDiagnoseSetter);
5619+
}
5620+
TC.diagnose(matchDecl, diag::overridden_here);
5621+
}
55975622
}
55985623

55995624
bool mayHaveMismatchedOptionals =

test/Sema/accessibility.swift

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,48 @@ internal class InternalSubPrivateSet: Base {
198198
}
199199
}
200200

201+
fileprivate class FilePrivateSub: Base {
202+
required private init() {} // expected-error {{'required' initializer must be as accessible as its enclosing type}} {{12-19=fileprivate}}
203+
private override func foo() {} // expected-error {{overriding instance method must be as accessible as its enclosing type}} {{3-10=fileprivate}}
204+
private override var bar: Int { // expected-error {{overriding var must be as accessible as its enclosing type}} {{3-10=fileprivate}}
205+
get { return 0 }
206+
set {}
207+
}
208+
private override subscript () -> () { return () } // expected-error {{overriding subscript must be as accessible as its enclosing type}} {{3-10=fileprivate}}
209+
}
210+
211+
fileprivate class FilePrivateSubGood: Base {
212+
required init() {} // no-warning
213+
override func foo() {}
214+
override var bar: Int {
215+
get { return 0 }
216+
set {}
217+
}
218+
override subscript () -> () { return () }
219+
}
220+
221+
fileprivate class FilePrivateSubGood2: Base {
222+
fileprivate required init() {} // no-warning
223+
fileprivate override func foo() {}
224+
fileprivate override var bar: Int {
225+
get { return 0 }
226+
set {}
227+
}
228+
fileprivate override subscript () -> () { return () }
229+
}
230+
231+
fileprivate class FilePrivateSubPrivateSet: Base {
232+
required init() {}
233+
private(set) override var bar: Int { // expected-error {{overriding var must be as accessible as its enclosing type}} {{3-10=fileprivate}}
234+
get { return 0 }
235+
set {}
236+
}
237+
private(set) override subscript () -> () { // okay; read-only in base class
238+
get { return () }
239+
set {}
240+
}
241+
}
242+
201243
private class PrivateSub: Base {
202244
required private init() {} // expected-error {{'required' initializer must be as accessible as its enclosing type}} {{12-19=fileprivate}}
203245
private override func foo() {} // expected-error {{overriding instance method must be as accessible as its enclosing type}} {{3-10=fileprivate}}

test/attr/open.swift

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,52 @@ class SubClass : ExternalOpenClass {
7777
}
7878
}
7979

80+
open class InvalidOpenSubClass : ExternalOpenClass {
81+
public override func openMethod() {} // expected-error {{overriding instance method must be as accessible as the declaration it overrides}} {{3-9=open}}
82+
public override var openProperty: Int { get{return 0} set{} } // expected-error {{overriding var must be as accessible as the declaration it overrides}} {{3-9=open}}
83+
public override subscript(index: MarkerForOpenSubscripts) -> Int { // expected-error {{overriding subscript must be as accessible as the declaration it overrides}} {{3-9=open}}
84+
get { return 0 }
85+
set {}
86+
}
87+
}
88+
89+
open class InvalidOpenSubClass2 : ExternalOpenClass {
90+
internal override func openMethod() {} // expected-error {{overriding instance method must be as accessible as the declaration it overrides}} {{3-11=open}}
91+
internal override var openProperty: Int { get{return 0} set{} } // expected-error {{overriding var must be as accessible as the declaration it overrides}} {{3-11=open}}
92+
internal override subscript(index: MarkerForOpenSubscripts) -> Int { // expected-error {{overriding subscript must be as accessible as the declaration it overrides}} {{3-11=open}}
93+
get { return 0 }
94+
set {}
95+
}
96+
}
97+
98+
open class OpenSubClassFinalMembers : ExternalOpenClass {
99+
final public override func openMethod() {}
100+
final public override var openProperty: Int { get{return 0} set{} }
101+
final public override subscript(index: MarkerForOpenSubscripts) -> Int {
102+
get { return 0 }
103+
set {}
104+
}
105+
}
106+
107+
open class InvalidOpenSubClassFinalMembers : ExternalOpenClass {
108+
final internal override func openMethod() {} // expected-error {{overriding instance method must be as accessible as its enclosing type}} {{9-17=public}}
109+
final internal override var openProperty: Int { get{return 0} set{} } // expected-error {{overriding var must be as accessible as its enclosing type}} {{9-17=public}}
110+
final internal override subscript(index: MarkerForOpenSubscripts) -> Int { // expected-error {{overriding subscript must be as accessible as its enclosing type}} {{9-17=public}}
111+
get { return 0 }
112+
set {}
113+
}
114+
}
115+
116+
public class PublicSubClass : ExternalOpenClass {
117+
public override func openMethod() {}
118+
public override var openProperty: Int { get{return 0} set{} }
119+
public override subscript(index: MarkerForOpenSubscripts) -> Int {
120+
get { return 0 }
121+
set {}
122+
}
123+
}
124+
125+
80126
// The proposal originally made these invalid, but we changed our minds.
81127
open class OpenSuperClass {
82128
public func publicMethod() {}

0 commit comments

Comments
 (0)