Skip to content

Commit c6f1352

Browse files
committed
Implement SE-0117.
1 parent c77ecd3 commit c6f1352

File tree

66 files changed

+1008
-837
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+1008
-837
lines changed

include/swift/AST/Attr.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,9 +201,9 @@ class DeclAttribute : public AttributeBase {
201201
friend class AbstractAccessibilityAttr;
202202
unsigned : NumDeclAttrBits;
203203

204-
unsigned AccessLevel : 2;
204+
unsigned AccessLevel : 3;
205205
};
206-
enum { NumAccessibilityAttrBits = NumDeclAttrBits + 2 };
206+
enum { NumAccessibilityAttrBits = NumDeclAttrBits + 3 };
207207
static_assert(NumAccessibilityAttrBits <= 32, "fits in an unsigned");
208208

209209
class AutoClosureAttrBitFields {

include/swift/AST/AttrKind.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,11 @@ enum class Accessibility : uint8_t {
5555
FilePrivate,
5656
/// Internal access is limited to the current module.
5757
Internal,
58-
/// Public access is not limited.
59-
Public
58+
/// Public access is not limited, but some capabilities may be
59+
/// restricted outside of the current module.
60+
Public,
61+
/// Open access is not limited, and all capabilities are unrestricted.
62+
Open,
6063
};
6164

6265
enum class InlineKind : uint8_t {

include/swift/AST/Decl.h

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -813,6 +813,13 @@ class alignas(1 << DeclAlignInBits) Decl {
813813
/// Whether this declaration is weak-imported.
814814
bool isWeakImported(ModuleDecl *fromModule) const;
815815

816+
/// Returns true if the nature of this declaration allows overrides.
817+
/// Note that this does not consider whether it is final or whether
818+
/// the class it's on is final.
819+
///
820+
/// If this returns true, the decl can be safely casted to ValueDecl.
821+
bool isPotentiallyOverridable() const;
822+
816823
// Make vanilla new/delete illegal for Decls.
817824
void *operator new(size_t Bytes) = delete;
818825
void operator delete(void *Data) = delete;
@@ -2184,7 +2191,8 @@ class ValueDecl : public Decl {
21842191
Accessibility getFormalAccess(const DeclContext *useDC = nullptr) const {
21852192
assert(hasAccessibility() && "accessibility not computed yet");
21862193
Accessibility result = TypeAndAccess.getInt().getValue();
2187-
if (useDC && result == Accessibility::Internal)
2194+
if (useDC && (result == Accessibility::Internal ||
2195+
result == Accessibility::Public))
21882196
return getFormalAccessImpl(useDC);
21892197
return result;
21902198
}
@@ -6138,6 +6146,16 @@ inline ArrayRef<Requirement> ExtensionDecl::getGenericRequirements() const {
61386146
return GenericSig->getRequirements();
61396147
}
61406148

6149+
inline bool Decl::isPotentiallyOverridable() const {
6150+
if (isa<VarDecl>(this) ||
6151+
isa<SubscriptDecl>(this) ||
6152+
isa<FuncDecl>(this)) {
6153+
return getDeclContext()->getAsClassOrClassExtensionContext();
6154+
} else {
6155+
return false;
6156+
}
6157+
}
6158+
61416159
} // end namespace swift
61426160

61436161
#endif

include/swift/AST/DiagnosticsSema.def

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -988,6 +988,12 @@ ERROR(access_control_extension_more,none,
988988
"extension of %select{private|fileprivate|internal|PUBLIC}0 %1 cannot "
989989
"be declared %select{PRIVATE|fileprivate|internal|public}2",
990990
(Accessibility, DescriptiveDeclKind, Accessibility))
991+
ERROR(access_control_extension_open,none,
992+
"extensions cannot use 'open' as their default access; use 'public'",
993+
())
994+
ERROR(access_control_open_bad_decl,none,
995+
"only classes and overridable class members can be declared 'open';"
996+
" use 'public'", ())
991997

992998
ERROR(invalid_decl_attribute_simple,none,
993999
"attribute cannot be applied to declaration", ())
@@ -1513,6 +1519,10 @@ ERROR(override_not_accessible,none,
15131519
"%select{its enclosing type|the declaration it overrides}2",
15141520
(bool, DescriptiveDeclKind, bool))
15151521

1522+
ERROR(override_of_non_open,none,
1523+
"overriding non-open %0 outside of its defining module",
1524+
(DescriptiveDeclKind))
1525+
15161526
ERROR(method_does_not_override,none,
15171527
"method does not override any method from its superclass", ())
15181528
ERROR(property_does_not_override,none,
@@ -1602,6 +1612,8 @@ ERROR(override_mutable_covariant_subscript,none,
16021612
(Type, Type))
16031613
ERROR(decl_already_final,none,
16041614
"static declarations are already final", ())
1615+
ERROR(open_decl_cannot_be_final,none,
1616+
"%0 cannot be declared both 'final' and 'open'", (DescriptiveDeclKind))
16051617
NOTE(decl_init_here,none,
16061618
"initial value is here", ())
16071619

@@ -1621,6 +1633,9 @@ ERROR(inheritance_from_non_protocol,none,
16211633
"inheritance from non-protocol type %0", (Type))
16221634
ERROR(superclass_not_first,none,
16231635
"superclass %0 must appear first in the inheritance clause", (Type))
1636+
ERROR(superclass_not_open,none,
1637+
"cannot inherit from non-open class %0 outside of its defining module",
1638+
(Type))
16241639
ERROR(circular_class_inheritance,none,
16251640
"circular class inheritance %0", (StringRef))
16261641
NOTE(class_here,none,

include/swift/Serialization/ModuleFormat.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ const uint16_t VERSION_MAJOR = 0;
5353
/// in source control, you should also update the comment to briefly
5454
/// describe what change you made. The content of this comment isn't important;
5555
/// it just ensures a conflict if two people change the module format.
56-
const uint16_t VERSION_MINOR = 259; // Last change: drop explicitlyEscaping
56+
const uint16_t VERSION_MINOR = 260; // Last change: open
5757

5858
using DeclID = PointerEmbeddedInt<unsigned, 31>;
5959
using DeclIDField = BCFixed<31>;
@@ -291,8 +291,9 @@ enum class AccessibilityKind : uint8_t {
291291
FilePrivate,
292292
Internal,
293293
Public,
294+
Open,
294295
};
295-
using AccessibilityKindField = BCFixed<2>;
296+
using AccessibilityKindField = BCFixed<3>;
296297

297298
// These IDs must \em not be renumbered or reordered without incrementing
298299
// VERSION_MAJOR.

lib/AST/ASTDumper.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,9 @@ namespace {
579579
case Accessibility::Public:
580580
OS << "public";
581581
break;
582+
case Accessibility::Open:
583+
OS << "open";
584+
break;
582585
}
583586
}
584587

lib/AST/ASTPrinter.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1146,6 +1146,9 @@ class PrintAST : public ASTVisitor<PrintAST> {
11461146
case Accessibility::Public:
11471147
Printer << tok::kw_public;
11481148
break;
1149+
case Accessibility::Open:
1150+
Printer.printKeyword("open");
1151+
break;
11491152
}
11501153
Printer << suffix << " ";
11511154
}

lib/AST/ASTVerifier.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -692,7 +692,7 @@ struct ASTNodeBase {};
692692
if (D->hasAccessibility()) {
693693
PrettyStackTraceDecl debugStack("verifying access", D);
694694
if (D->getFormalAccessScope() == nullptr &&
695-
D->getFormalAccess() != Accessibility::Public) {
695+
D->getFormalAccess() < Accessibility::Public) {
696696
Out << "non-public decl has no formal access scope\n";
697697
D->dump(Out);
698698
abort();

lib/AST/Attr.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,7 +553,10 @@ StringRef DeclAttribute::getAttrName() const {
553553
return "internal";
554554
case Accessibility::Public:
555555
return "public";
556+
case Accessibility::Open:
557+
return "open";
556558
}
559+
llvm_unreachable("bad accessibility kind");
557560

558561
case DAK_Ownership:
559562
switch (cast<OwnershipAttr>(this)->get()) {
@@ -562,6 +565,7 @@ StringRef DeclAttribute::getAttrName() const {
562565
case Ownership::Unowned: return "unowned";
563566
case Ownership::Unmanaged: return "unowned(unsafe)";
564567
}
568+
llvm_unreachable("bad ownership kind");
565569
case DAK_RawDocComment:
566570
return "<<raw doc comment>>";
567571
case DAK_ObjCBridged:

lib/AST/Decl.cpp

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1227,7 +1227,7 @@ bool AbstractStorageDecl::hasFixedLayout() const {
12271227

12281228
// Private and (unversioned) internal variables always have a
12291229
// fixed layout.
1230-
if (getEffectiveAccess() != Accessibility::Public)
1230+
if (getEffectiveAccess() < Accessibility::Public)
12311231
return true;
12321232

12331233
// Check for an explicit @_fixed_layout attribute.
@@ -1794,12 +1794,9 @@ SourceLoc ValueDecl::getAttributeInsertionLoc(bool forModifier) const {
17941794
return resultLoc.isValid() ? resultLoc : getStartLoc();
17951795
}
17961796

1797-
/// Returns true if \p VD needs to be treated as publicly-accessible at the SIL,
1798-
/// LLVM, and machine levels.
1799-
///
1800-
/// The most common causes of this are -enable-testing and versioned non-public
1801-
/// declarations.
1802-
static bool isInternalDeclEffectivelyPublic(const ValueDecl *VD) {
1797+
/// Returns true if \p VD needs to be treated as publicly-accessible
1798+
/// at the SIL, LLVM, and machine levels due to being versioned.
1799+
static bool isVersionedInternalDecl(const ValueDecl *VD) {
18031800
assert(VD->getFormalAccess() == Accessibility::Internal);
18041801

18051802
if (VD->getAttrs().hasAttribute<VersionedAttr>())
@@ -1810,21 +1807,43 @@ static bool isInternalDeclEffectivelyPublic(const ValueDecl *VD) {
18101807
if (ASD->getAttrs().hasAttribute<VersionedAttr>())
18111808
return true;
18121809

1813-
if (VD->getModuleContext()->isTestingEnabled())
1814-
return true;
1815-
18161810
return false;
18171811
}
18181812

1813+
/// Return the accessibility of an internal or public declaration
1814+
/// that's been testably imported.
1815+
static Accessibility getTestableAccess(const ValueDecl *decl) {
1816+
// Non-final classes are considered open to @testable importers.
1817+
if (auto cls = dyn_cast<ClassDecl>(decl)) {
1818+
if (!cls->isFinal())
1819+
return Accessibility::Open;
1820+
1821+
// Non-final overridable class members are considered open to
1822+
// @testable importers.
1823+
} else if (decl->isPotentiallyOverridable()) {
1824+
if (!cast<ValueDecl>(decl)->isFinal())
1825+
return Accessibility::Open;
1826+
}
1827+
1828+
// Everything else is considered public.
1829+
return Accessibility::Public;
1830+
}
1831+
18191832
Accessibility ValueDecl::getEffectiveAccess() const {
18201833
Accessibility effectiveAccess = getFormalAccess();
18211834

18221835
// Handle @testable.
18231836
switch (effectiveAccess) {
18241837
case Accessibility::Public:
1838+
if (getModuleContext()->isTestingEnabled())
1839+
effectiveAccess = getTestableAccess(this);
1840+
break;
1841+
case Accessibility::Open:
18251842
break;
18261843
case Accessibility::Internal:
1827-
if (isInternalDeclEffectivelyPublic(this))
1844+
if (getModuleContext()->isTestingEnabled())
1845+
effectiveAccess = getTestableAccess(this);
1846+
else if (isVersionedInternalDecl(this))
18281847
effectiveAccess = Accessibility::Public;
18291848
break;
18301849
case Accessibility::FilePrivate:
@@ -1856,13 +1875,14 @@ Accessibility ValueDecl::getEffectiveAccess() const {
18561875
}
18571876

18581877
Accessibility ValueDecl::getFormalAccessImpl(const DeclContext *useDC) const {
1859-
assert(getFormalAccess() == Accessibility::Internal &&
1878+
assert((getFormalAccess() == Accessibility::Internal ||
1879+
getFormalAccess() == Accessibility::Public) &&
18601880
"should be able to fast-path non-internal cases");
18611881
assert(useDC && "should fast-path non-scoped cases");
18621882
if (auto *useSF = dyn_cast<SourceFile>(useDC->getModuleScopeContext()))
18631883
if (useSF->hasTestableImport(getModuleContext()))
1864-
return Accessibility::Public;
1865-
return Accessibility::Internal;
1884+
return getTestableAccess(this);
1885+
return getFormalAccess();
18661886
}
18671887

18681888
const DeclContext *
@@ -1908,6 +1928,7 @@ ValueDecl::getFormalAccessScope(const DeclContext *useDC) const {
19081928
case Accessibility::Internal:
19091929
return result->getParentModule();
19101930
case Accessibility::Public:
1931+
case Accessibility::Open:
19111932
return nullptr;
19121933
}
19131934

@@ -1947,7 +1968,7 @@ Type TypeDecl::getDeclaredInterfaceType() const {
19471968
bool NominalTypeDecl::hasFixedLayout() const {
19481969
// Private and (unversioned) internal types always have a
19491970
// fixed layout.
1950-
if (getEffectiveAccess() != Accessibility::Public)
1971+
if (getEffectiveAccess() < Accessibility::Public)
19511972
return true;
19521973

19531974
// Check for an explicit @_fixed_layout attribute.

0 commit comments

Comments
 (0)