Skip to content

Commit 306edda

Browse files
authored
SE-0025: Allow public members inside internal types. (#3404)
(and any other member with higher access control than its enclosing type) There's no effect, but it is now considered legal and the compiler will no longer warn about it. This allows an API author to prototype their API with proper access levels and still limit the top-level type. If the new getEffectiveAccess computation turns out to be expensive, we can cache the result. Note that the compiler will still warn when putting a public member inside an extension explicitly marked internal, because the extended type could be public and then including a public member would be valid. It is also still an error to put a public member inside a constrained extension of an internal type, though I think this one is safe to relax later. Progress on SE-0025 ('private' and 'fileprivate')
1 parent 6ef9d15 commit 306edda

File tree

7 files changed

+125
-92
lines changed

7 files changed

+125
-92
lines changed

include/swift/AST/Decl.h

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5942,24 +5942,6 @@ inline bool ValueDecl::isSettable(const DeclContext *UseDC,
59425942
return false;
59435943
}
59445944

5945-
namespace impl {
5946-
bool isInternalDeclEffectivelyPublic(const ValueDecl *VD);
5947-
}
5948-
5949-
inline Accessibility ValueDecl::getEffectiveAccess() const {
5950-
switch (getFormalAccess()) {
5951-
case Accessibility::Public:
5952-
return Accessibility::Public;
5953-
case Accessibility::Internal:
5954-
if (impl::isInternalDeclEffectivelyPublic(this)) {
5955-
return Accessibility::Public;
5956-
}
5957-
return Accessibility::Internal;
5958-
case Accessibility::Private:
5959-
return Accessibility::Private;
5960-
}
5961-
}
5962-
59635945
inline Optional<VarDecl *>
59645946
NominalTypeDecl::ToStoredProperty::operator()(Decl *decl) const {
59655947
if (auto var = dyn_cast<VarDecl>(decl)) {

include/swift/AST/DiagnosticsSema.def

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -945,10 +945,6 @@ ERROR(access_control_setter_more,none,
945945
"%select{variable|property|subscript}1 cannot have "
946946
"%select{PRIVATE|an internal|a public}2 setter",
947947
(Accessibility, unsigned, Accessibility))
948-
WARNING(access_control_member_more,none,
949-
"declaring %select{PRIVATE|an internal|a public}0 %1 for "
950-
"%select{a private|an internal|PUBLIC}2 %3",
951-
(Accessibility, DescriptiveDeclKind, Accessibility, DescriptiveDeclKind))
952948
WARNING(access_control_ext_member_more,none,
953949
"declaring %select{PRIVATE|an internal|a public}0 %1 in "
954950
"%select{a private|an internal|PUBLIC}2 extension",

lib/AST/Decl.cpp

Lines changed: 58 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -44,23 +44,6 @@
4444

4545
using namespace swift;
4646

47-
bool impl::isInternalDeclEffectivelyPublic(const ValueDecl *VD) {
48-
assert(VD->getFormalAccess() == Accessibility::Internal);
49-
50-
if (VD->getAttrs().hasAttribute<VersionedAttr>())
51-
return true;
52-
53-
if (auto *fn = dyn_cast<FuncDecl>(VD))
54-
if (auto *ASD = fn->getAccessorStorageDecl())
55-
if (ASD->getAttrs().hasAttribute<VersionedAttr>())
56-
return true;
57-
58-
if (VD->getModuleContext()->isTestingEnabled())
59-
return true;
60-
61-
return false;
62-
}
63-
6447
clang::SourceLocation ClangNode::getLocation() const {
6548
if (auto D = getAsDecl())
6649
return D->getLocation();
@@ -1810,6 +1793,64 @@ SourceLoc ValueDecl::getAttributeInsertionLoc(bool forModifier) const {
18101793
return resultLoc.isValid() ? resultLoc : getStartLoc();
18111794
}
18121795

1796+
/// Returns true if \p VD needs to be treated as publicly-accessible at the SIL,
1797+
/// LLVM, and machine levels.
1798+
///
1799+
/// The most common causes of this are -enable-testing and versioned non-public
1800+
/// declarations.
1801+
static bool isInternalDeclEffectivelyPublic(const ValueDecl *VD) {
1802+
assert(VD->getFormalAccess() == Accessibility::Internal);
1803+
1804+
if (VD->getAttrs().hasAttribute<VersionedAttr>())
1805+
return true;
1806+
1807+
if (auto *fn = dyn_cast<FuncDecl>(VD))
1808+
if (auto *ASD = fn->getAccessorStorageDecl())
1809+
if (ASD->getAttrs().hasAttribute<VersionedAttr>())
1810+
return true;
1811+
1812+
if (VD->getModuleContext()->isTestingEnabled())
1813+
return true;
1814+
1815+
return false;
1816+
}
1817+
1818+
Accessibility ValueDecl::getEffectiveAccess() const {
1819+
Accessibility effectiveAccess = getFormalAccess();
1820+
1821+
// Handle @testable.
1822+
switch (effectiveAccess) {
1823+
case Accessibility::Public:
1824+
break;
1825+
case Accessibility::Internal:
1826+
if (isInternalDeclEffectivelyPublic(this))
1827+
effectiveAccess = Accessibility::Public;
1828+
break;
1829+
case Accessibility::Private:
1830+
break;
1831+
}
1832+
1833+
if (auto enclosingNominal = dyn_cast<NominalTypeDecl>(getDeclContext())) {
1834+
effectiveAccess = std::min(effectiveAccess,
1835+
enclosingNominal->getEffectiveAccess());
1836+
1837+
} else if (auto enclosingExt = dyn_cast<ExtensionDecl>(getDeclContext())) {
1838+
// Just check the base type. If it's a constrained extension, Sema should
1839+
// have already enforced access more strictly.
1840+
if (auto extendedTy = enclosingExt->getExtendedType()) {
1841+
if (auto nominal = extendedTy->getAnyNominal()) {
1842+
effectiveAccess = std::min(effectiveAccess,
1843+
nominal->getEffectiveAccess());
1844+
}
1845+
}
1846+
1847+
} else if (getDeclContext()->isLocalContext()) {
1848+
effectiveAccess = Accessibility::Private;
1849+
}
1850+
1851+
return effectiveAccess;
1852+
}
1853+
18131854

18141855
Type TypeDecl::getDeclaredType() const {
18151856
if (auto TAD = dyn_cast<TypeAliasDecl>(this)) {

lib/Sema/TypeCheckAttr.cpp

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -683,7 +683,6 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
683683
void visitRequiredAttr(RequiredAttr *attr);
684684
void visitRethrowsAttr(RethrowsAttr *attr);
685685

686-
bool visitAbstractAccessibilityAttr(AbstractAccessibilityAttr *attr);
687686
void visitAccessibilityAttr(AccessibilityAttr *attr);
688687
void visitSetterAccessibilityAttr(SetterAccessibilityAttr *attr);
689688

@@ -1267,25 +1266,6 @@ void AttributeChecker::visitRethrowsAttr(RethrowsAttr *attr) {
12671266
attr->setInvalid();
12681267
}
12691268

1270-
bool AttributeChecker::visitAbstractAccessibilityAttr(
1271-
AbstractAccessibilityAttr *attr) {
1272-
DeclContext *dc = D->getDeclContext();
1273-
if (auto nominal = dc->getAsNominalTypeOrNominalTypeExtensionContext()) {
1274-
Accessibility typeAccess = nominal->getFormalAccess();
1275-
if (attr->getAccess() > typeAccess) {
1276-
auto diag = TC.diagnose(attr->getLocation(),
1277-
diag::access_control_member_more,
1278-
attr->getAccess(),
1279-
D->getDescriptiveKind(),
1280-
typeAccess,
1281-
nominal->getDescriptiveKind());
1282-
swift::fixItAccessibility(diag, cast<ValueDecl>(D), typeAccess);
1283-
return true;
1284-
}
1285-
}
1286-
return false;
1287-
}
1288-
12891269
void AttributeChecker::visitAccessibilityAttr(AccessibilityAttr *attr) {
12901270
if (auto extension = dyn_cast<ExtensionDecl>(D)) {
12911271
Type extendedTy = extension->getExtendedType();
@@ -1327,8 +1307,6 @@ void AttributeChecker::visitAccessibilityAttr(AccessibilityAttr *attr) {
13271307
return;
13281308
}
13291309
}
1330-
1331-
visitAbstractAccessibilityAttr(attr);
13321310
}
13331311

13341312
void
@@ -1352,8 +1330,6 @@ AttributeChecker::visitSetterAccessibilityAttr(SetterAccessibilityAttr *attr) {
13521330
attr->setInvalid();
13531331
return;
13541332
}
1355-
1356-
visitAbstractAccessibilityAttr(attr);
13571333
}
13581334

13591335
/// Check that the @_specialize type list has the correct number of entries.
Lines changed: 56 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,98 @@
11
// RUN: %target-parse-verify-swift
2-
// RUN: %target-swift-frontend -emit-silgen -o /dev/null %s
2+
// RUN: %target-swift-frontend -emit-silgen %s | FileCheck %s
33

44
// This file tests that the AST produced after fixing accessibility warnings
55
// is valid according to SILGen and the verifiers.
66

77
public struct PublicStruct {
8+
// CHECK-DAG: sil{{( \[.+\])*}} @_TFV22accessibility_warnings12PublicStructg9publicVarSi
89
public var publicVar = 0
10+
// CHECK-DAG: sil hidden @_TFV22accessibility_warnings12PublicStructCfT_S0_
911
}
1012

1113
internal struct InternalStruct {
12-
public var publicVar = 0 // expected-warning {{declaring a public var for an internal struct}} {{3-9=internal}}
14+
public var publicVar = 0
15+
16+
public private(set) var publicVarPrivateSet = 0
1317

14-
public private(set) var publicVarPrivateSet = 0 // expected-warning {{declaring a public var for an internal struct}} {{3-9=internal}}
18+
public public(set) var publicVarPublicSet = 0
1519

16-
public public(set) var publicVarPublicSet = 0 // expected-warning {{declaring a public var for an internal struct}} {{3-9=internal}} {{10-22=}}
20+
// CHECK-DAG: sil hidden @_TFV22accessibility_warnings14InternalStructg16publicVarGetOnlySi
21+
public var publicVarGetOnly: Int { return 0 }
1722

18-
public var publicVarGetOnly: Int { return 0 } // expected-warning {{declaring a public var for an internal struct}} {{3-9=internal}}
23+
// CHECK-DAG: sil hidden @_TFV22accessibility_warnings14InternalStructg15publicVarGetSetSi
24+
public var publicVarGetSet: Int { get { return 0 } set {} }
1925

20-
public var publicVarGetSet: Int { get { return 0 } set {} } // expected-warning {{declaring a public var for an internal struct}} {{3-9=internal}}
26+
// CHECK-DAG: sil hidden @_TFV22accessibility_warnings14InternalStructCfT_S0_
2127
}
2228

2329
private struct PrivateStruct {
24-
public var publicVar = 0 // expected-warning {{declaring a public var for a private struct}} {{3-9=private}}
30+
public var publicVar = 0
31+
// CHECK-DAG: sil private @_TFV22accessibility_warningsP33_5D2F2E026754A901C0FF90C404896D0213PrivateStructCfT_S0_
2532
}
2633

2734

2835
extension PublicStruct {
36+
// CHECK-DAG: sil @_TFV22accessibility_warnings12PublicStructCfT1xSi_S0_
2937
public init(x: Int) { self.init() }
3038

39+
// CHECK-DAG: sil @_TFV22accessibility_warnings12PublicStructg18publicVarExtensionSi
3140
public var publicVarExtension: Int { get { return 0 } set {} }
3241
}
3342

3443
extension InternalStruct {
35-
public init(x: Int) { self.init() } // expected-warning {{declaring a public initializer for an internal struct}} {{3-9=internal}}
44+
// CHECK-DAG: sil hidden @_TFV22accessibility_warnings14InternalStructCfT1xSi_S0_
45+
public init(x: Int) { self.init() }
3646

37-
public var publicVarExtension: Int { get { return 0 } set {} } // expected-warning {{declaring a public var for an internal struct}} {{3-9=internal}}
47+
// CHECK-DAG: sil hidden @_TFV22accessibility_warnings14InternalStructg18publicVarExtensionSi
48+
public var publicVarExtension: Int { get { return 0 } set {} }
3849
}
3950

4051
extension PrivateStruct {
41-
public init(x: Int) { self.init() } // expected-warning {{declaring a public initializer for a private struct}} {{3-9=private}}
52+
// CHECK-DAG: sil private @_TFV22accessibility_warningsP33_5D2F2E026754A901C0FF90C404896D0213PrivateStructCfT1xSi_S0_
53+
public init(x: Int) { self.init() }
4254

43-
public var publicVarExtension: Int { get { return 0 } set {} } // expected-warning {{declaring a public var for a private struct}} {{3-9=private}}
55+
// CHECK-DAG: sil private @_TFV22accessibility_warningsP33_5D2F2E026754A901C0FF90C404896D0213PrivateStructg18publicVarExtensionSi
56+
public var publicVarExtension: Int { get { return 0 } set {} }
4457
}
4558

4659
public extension PublicStruct {
60+
// CHECK-DAG: sil @_TFV22accessibility_warnings12PublicStruct15extMemberPublicfT_T_
4761
public func extMemberPublic() {}
62+
// CHECK-DAG: sil private @_TFV22accessibility_warnings12PublicStructP33_5D2F2E026754A901C0FF90C404896D0213extImplPublicfT_T_
4863
private func extImplPublic() {}
4964
}
5065
internal extension PublicStruct {
66+
// CHECK-DAG: sil hidden @_TFV22accessibility_warnings12PublicStruct17extMemberInternalfT_T_
5167
public func extMemberInternal() {} // expected-warning {{declaring a public instance method in an internal extension}} {{3-9=internal}}
68+
// CHECK-DAG: sil private @_TFV22accessibility_warnings12PublicStructP33_5D2F2E026754A901C0FF90C404896D0215extImplInternalfT_T_
5269
private func extImplInternal() {}
5370
}
5471
private extension PublicStruct {
72+
// CHECK-DAG: sil private @_TFV22accessibility_warnings12PublicStructP33_5D2F2E026754A901C0FF90C404896D0216extMemberPrivatefT_T_
5573
public func extMemberPrivate() {} // expected-warning {{declaring a public instance method in a private extension}} {{3-9=private}}
74+
// CHECK-DAG: sil private @_TFV22accessibility_warnings12PublicStructP33_5D2F2E026754A901C0FF90C404896D0214extImplPrivatefT_T_
5675
private func extImplPrivate() {}
5776
}
5877

5978
internal extension InternalStruct {
79+
// CHECK-DAG: sil hidden @_TFV22accessibility_warnings14InternalStruct17extMemberInternalfT_T_
6080
public func extMemberInternal() {} // expected-warning {{declaring a public instance method in an internal extension}} {{3-9=internal}}
81+
// CHECK-DAG: sil private @_TFV22accessibility_warnings14InternalStructP33_5D2F2E026754A901C0FF90C404896D0215extImplInternalfT_T_
6182
private func extImplInternal() {}
6283
}
6384
private extension InternalStruct {
85+
// CHECK-DAG: sil private @_TFV22accessibility_warnings14InternalStructP33_5D2F2E026754A901C0FF90C404896D0216extMemberPrivatefT_T_
6486
public func extMemberPrivate() {} // expected-warning {{declaring a public instance method in a private extension}} {{3-9=private}}
87+
// CHECK-DAG: sil private @_TFV22accessibility_warnings14InternalStructP33_5D2F2E026754A901C0FF90C404896D0214extImplPrivatefT_T_
6588
private func extImplPrivate() {}
6689
}
6790

6891

6992
private extension PrivateStruct {
93+
// CHECK-DAG: sil private @_TFV22accessibility_warningsP33_5D2F2E026754A901C0FF90C404896D0213PrivateStruct16extMemberPrivatefT_T_
7094
public func extMemberPrivate() {} // expected-warning {{declaring a public instance method in a private extension}} {{3-9=private}}
95+
// CHECK-DAG: sil private @_TFV22accessibility_warningsP33_5D2F2E026754A901C0FF90C404896D0213PrivateStruct14extImplPrivatefT_T_
7196
private func extImplPrivate() {}
7297
}
7398

@@ -77,7 +102,10 @@ public protocol PublicReadOnlyOperations {
77102
}
78103

79104
internal struct PrivateSettersForReadOnlyInternal : PublicReadOnlyOperations {
80-
public private(set) var size = 0 // expected-warning {{declaring a public var for an internal struct}} {{3-9=internal}}
105+
// CHECK-DAG: sil hidden{{( \[.+\])*}} @_TFV22accessibility_warnings33PrivateSettersForReadOnlyInternalg4sizeSi
106+
public private(set) var size = 0
107+
// CHECK-DAG: sil hidden @_TFV22accessibility_warnings33PrivateSettersForReadOnlyInternalg9subscriptFSiSi
108+
// CHECK-DAG: sil private @_TFV22accessibility_warnings33PrivateSettersForReadOnlyInternals9subscriptFSiSi
81109
internal private(set) subscript (_: Int) -> Int { // no-warning
82110
get { return 42 }
83111
set {}
@@ -86,22 +114,32 @@ internal struct PrivateSettersForReadOnlyInternal : PublicReadOnlyOperations {
86114

87115

88116
public class PublicClass {
117+
// CHECK-DAG: sil{{( \[.+\])*}} @_TFC22accessibility_warnings11PublicClassg9publicVarSi
89118
public var publicVar = 0
119+
// CHECK-DAG: sil hidden @_TFC22accessibility_warnings11PublicClasscfT_S0_
90120
}
91121

92122
internal class InternalClass {
93-
public var publicVar = 0 // expected-warning {{declaring a public var for an internal class}} {{3-9=internal}}
123+
// CHECK-DAG: sil hidden{{( \[.+\])*}} @_TFC22accessibility_warnings13InternalClassg9publicVarSi
124+
public var publicVar = 0
94125

95-
public private(set) var publicVarPrivateSet = 0 // expected-warning {{declaring a public var for an internal class}} {{3-9=internal}}
126+
// CHECK-DAG: sil hidden [transparent] @_TFC22accessibility_warnings13InternalClassg19publicVarPrivateSetSi
127+
public private(set) var publicVarPrivateSet = 0
96128

97-
public public(set) var publicVarPublicSet = 0 // expected-warning {{declaring a public var for an internal class}} {{3-9=internal}}
129+
public public(set) var publicVarPublicSet = 0
98130

99-
public var publicVarGetOnly: Int { return 0 } // expected-warning {{declaring a public var for an internal class}} {{3-9=internal}}
131+
// CHECK-DAG: sil hidden @_TFC22accessibility_warnings13InternalClassg16publicVarGetOnlySi
132+
public var publicVarGetOnly: Int { return 0 }
100133

101-
public var publicVarGetSet: Int { get { return 0 } set {} } // expected-warning {{declaring a public var for an internal class}} {{3-9=internal}}
134+
// CHECK-DAG: sil hidden @_TFC22accessibility_warnings13InternalClassg15publicVarGetSetSi
135+
public var publicVarGetSet: Int { get { return 0 } set {} }
136+
137+
// CHECK-DAG: sil hidden @_TFC22accessibility_warnings13InternalClasscfT_S0_
102138
}
103139

104140
private class PrivateClass {
105-
public var publicVar = 0 // expected-warning {{declaring a public var for a private class}} {{3-9=private}}
141+
// CHECK-DAG: sil private{{( \[.+\])*}} @_TFC22accessibility_warningsP33_5D2F2E026754A901C0FF90C404896D0212PrivateClassg9publicVarSi
142+
public var publicVar = 0
143+
// CHECK-DAG: sil private @_TFC22accessibility_warningsP33_5D2F2E026754A901C0FF90C404896D0212PrivateClasscfT_S0_
106144
}
107145

0 commit comments

Comments
 (0)