Skip to content

Commit 178e676

Browse files
authored
Merge pull request #15787 from slavapestov/se-0193-inlinable-is-usable-from-inline
SE-0193: @inlinable implies @usableFromInline
2 parents 09e1e3c + e39b907 commit 178e676

File tree

107 files changed

+137
-1530
lines changed

Some content is hidden

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

107 files changed

+137
-1530
lines changed

Diff for: CHANGELOG.md

+16-4
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,18 @@ Swift 5.0
6161
Swift 4.2
6262
---------
6363

64+
* [SE-0193][]
65+
66+
Various function-like declarations can now be marked as `@inlinable`,
67+
making their bodies available for optimizations from other modules.
68+
69+
Inlinable function bodies must only reference public declarations, unless
70+
the referenced declaration is marked as `@usableFromInline`.
71+
72+
Note that the presence of the attribute itself does not force inlining or
73+
any other optimization to be performed, nor does it have any effect on
74+
optimizations performed within a single module.
75+
6476
* The C `long double` type is now imported as `Float80` on i386 and x86_64
6577
macOS and Linux. The tgmath functions in the Darwin and glibc modules now
6678
 support `Float80` as well as `Float` and `Double`. Several tgmath
@@ -103,10 +115,10 @@ Swift 4.2
103115

104116
* [SE-0143][]
105117

106-
Runtime query of conditional conformances is now implemented. Therefore,
107-
a dynamic cast such as `value as? P`, where the dynamic type of `value`
108-
conditionally conforms to `P`, will succeed when the conditional
109-
requirements are met.
118+
Runtime query of conditional conformances is now implemented. Therefore,
119+
a dynamic cast such as `value as? P`, where the dynamic type of `value`
120+
conditionally conforms to `P`, will succeed when the conditional
121+
requirements are met.
110122

111123
**Add new entries to the top of this section, not here!**
112124

Diff for: include/swift/AST/DiagnosticsSema.def

+6-3
Original file line numberDiff line numberDiff line change
@@ -3736,15 +3736,18 @@ ERROR(fixed_layout_attr_on_internal_type,
37363736
"%select{private|fileprivate|internal|%error|%error}1",
37373737
(DeclName, AccessLevel))
37383738

3739-
ERROR(versioned_attr_with_explicit_access,
3739+
ERROR(usable_from_inline_attr_with_explicit_access,
37403740
none, "'@usableFromInline' attribute can only be applied to internal "
37413741
"declarations, but %0 is %select{private|fileprivate|%error|public|open}1",
37423742
(DeclName, AccessLevel))
37433743

3744-
ERROR(versioned_attr_in_protocol,none,
3744+
WARNING(inlinable_implies_usable_from_inline,none,
3745+
"'@inlinable' declaration is already '@usableFromInline'",())
3746+
3747+
ERROR(usable_from_inline_attr_in_protocol,none,
37453748
"'@usableFromInline' attribute cannot be used in protocols", ())
37463749

3747-
ERROR(versioned_dynamic_not_supported,none,
3750+
ERROR(usable_from_inline_dynamic_not_supported,none,
37483751
"'@usableFromInline' attribute cannot be applied to 'dynamic' declarations", ())
37493752

37503753
#define FRAGILE_FUNC_KIND \

Diff for: lib/AST/Decl.cpp

+10-4
Original file line numberDiff line numberDiff line change
@@ -2106,12 +2106,16 @@ SourceLoc ValueDecl::getAttributeInsertionLoc(bool forModifier) const {
21062106
bool ValueDecl::isUsableFromInline() const {
21072107
assert(getFormalAccess() == AccessLevel::Internal);
21082108

2109-
if (getAttrs().hasAttribute<UsableFromInlineAttr>())
2109+
if (getAttrs().hasAttribute<UsableFromInlineAttr>() ||
2110+
getAttrs().hasAttribute<InlinableAttr>())
21102111
return true;
21112112

2112-
if (auto *accessor = dyn_cast<AccessorDecl>(this))
2113-
if (accessor->getStorage()->getAttrs().hasAttribute<UsableFromInlineAttr>())
2113+
if (auto *accessor = dyn_cast<AccessorDecl>(this)) {
2114+
auto *storage = accessor->getStorage();
2115+
if (storage->getAttrs().hasAttribute<UsableFromInlineAttr>() ||
2116+
storage->getAttrs().hasAttribute<InlinableAttr>())
21142117
return true;
2118+
}
21152119

21162120
if (auto *EED = dyn_cast<EnumElementDecl>(this))
21172121
if (EED->getParentEnum()->getAttrs().hasAttribute<UsableFromInlineAttr>())
@@ -2261,7 +2265,9 @@ void ValueDecl::copyFormalAccessFrom(ValueDecl *source) {
22612265
}
22622266

22632267
// Inherit the @usableFromInline attribute.
2264-
if (source->getAttrs().hasAttribute<UsableFromInlineAttr>()) {
2268+
if (source->getAttrs().hasAttribute<UsableFromInlineAttr>() &&
2269+
!getAttrs().hasAttribute<UsableFromInlineAttr>() &&
2270+
!getAttrs().hasAttribute<InlinableAttr>()) {
22652271
auto &ctx = getASTContext();
22662272
auto *clonedAttr = new (ctx) UsableFromInlineAttr(/*implicit=*/true);
22672273
getAttrs().add(clonedAttr);

Diff for: lib/Sema/CodeSynthesis.cpp

+66-55
Original file line numberDiff line numberDiff line change
@@ -1997,6 +1997,69 @@ static void createStubBody(TypeChecker &tc, ConstructorDecl *ctor) {
19971997
ctor->setStubImplementation(true);
19981998
}
19991999

2000+
static void configureDesignatedInitAttributes(TypeChecker &tc,
2001+
ClassDecl *classDecl,
2002+
ConstructorDecl *ctor,
2003+
ConstructorDecl *superclassCtor) {
2004+
auto &ctx = tc.Context;
2005+
2006+
AccessLevel access = classDecl->getFormalAccess();
2007+
access = std::max(access, AccessLevel::Internal);
2008+
access = std::min(access, superclassCtor->getFormalAccess());
2009+
2010+
ctor->setAccess(access);
2011+
2012+
// Inherit the @inlinable attribute.
2013+
if (superclassCtor->getFormalAccess(/*useDC=*/nullptr,
2014+
/*treatUsableFromInlineAsPublic=*/true)
2015+
>= AccessLevel::Public) {
2016+
if (superclassCtor->getAttrs().hasAttribute<InlinableAttr>()) {
2017+
auto *clonedAttr = new (ctx) InlinableAttr(/*implicit=*/true);
2018+
ctor->getAttrs().add(clonedAttr);
2019+
}
2020+
}
2021+
2022+
// Inherit the @usableFromInline attribute. We need better abstractions
2023+
// for dealing with @usableFromInline.
2024+
if (superclassCtor->getFormalAccess(/*useDC=*/nullptr,
2025+
/*treatUsableFromInlineAsPublic=*/true)
2026+
>= AccessLevel::Public) {
2027+
if (access == AccessLevel::Internal &&
2028+
!superclassCtor->isDynamic() &&
2029+
!ctor->getAttrs().hasAttribute<InlinableAttr>()) {
2030+
auto *clonedAttr = new (ctx) UsableFromInlineAttr(/*implicit=*/true);
2031+
ctor->getAttrs().add(clonedAttr);
2032+
}
2033+
}
2034+
2035+
// Make sure the constructor is only as available as its superclass's
2036+
// constructor.
2037+
AvailabilityInference::applyInferredAvailableAttrs(ctor, superclassCtor, ctx);
2038+
2039+
if (superclassCtor->isObjC()) {
2040+
// Inherit the @objc name from the superclass initializer, if it
2041+
// has one.
2042+
if (auto objcAttr = superclassCtor->getAttrs().getAttribute<ObjCAttr>()) {
2043+
if (objcAttr->hasName()) {
2044+
auto *clonedAttr = objcAttr->clone(ctx);
2045+
clonedAttr->setImplicit(true);
2046+
ctor->getAttrs().add(clonedAttr);
2047+
}
2048+
}
2049+
2050+
auto errorConvention = superclassCtor->getForeignErrorConvention();
2051+
markAsObjC(tc, ctor, ObjCReason::ImplicitlyObjC, errorConvention);
2052+
}
2053+
if (superclassCtor->isRequired())
2054+
ctor->getAttrs().add(new (ctx) RequiredAttr(/*IsImplicit=*/true));
2055+
if (superclassCtor->isDynamic())
2056+
ctor->getAttrs().add(new (ctx) DynamicAttr(/*IsImplicit*/true));
2057+
2058+
// Wire up the overrides.
2059+
ctor->getAttrs().add(new (ctx) OverrideAttr(/*IsImplicit=*/true));
2060+
ctor->setOverriddenDecl(superclassCtor);
2061+
}
2062+
20002063
ConstructorDecl *
20012064
swift::createDesignatedInitOverride(TypeChecker &tc,
20022065
ClassDecl *classDecl,
@@ -2082,66 +2145,14 @@ swift::createDesignatedInitOverride(TypeChecker &tc,
20822145

20832146
ctor->setImplicit();
20842147

2085-
AccessLevel access = classDecl->getFormalAccess();
2086-
access = std::max(access, AccessLevel::Internal);
2087-
access = std::min(access, superclassCtor->getFormalAccess());
2088-
2089-
ctor->setAccess(access);
2090-
2091-
// This is really painful. We need better abstractions for dealing with
2092-
// @usableFromInline.
2093-
if (superclassCtor->getFormalAccess(/*useDC=*/nullptr,
2094-
/*treatUsableFromInlineAsPublic=*/true)
2095-
>= AccessLevel::Public) {
2096-
if (access == AccessLevel::Internal &&
2097-
!superclassCtor->isDynamic()) {
2098-
auto *clonedAttr = new (ctx) UsableFromInlineAttr(/*implicit=*/true);
2099-
ctor->getAttrs().add(clonedAttr);
2100-
}
2101-
}
2102-
2103-
// Inherit the @inlinable attribute.
2104-
if (ctor->getFormalAccess(/*useDC=*/nullptr,
2105-
/*treatUsableFromInlineAsPublic=*/true)
2106-
>= AccessLevel::Public) {
2107-
if (superclassCtor->getAttrs().hasAttribute<InlinableAttr>()) {
2108-
auto *clonedAttr = new (ctx) InlinableAttr(/*implicit=*/true);
2109-
ctor->getAttrs().add(clonedAttr);
2110-
}
2111-
}
2112-
2113-
// Make sure the constructor is only as available as its superclass's
2114-
// constructor.
2115-
AvailabilityInference::applyInferredAvailableAttrs(ctor, superclassCtor, ctx);
2116-
21172148
// Set the interface type of the initializer.
21182149
ctor->setGenericEnvironment(classDecl->getGenericEnvironmentOfContext());
21192150
tc.configureInterfaceType(ctor, ctor->getGenericSignature());
2120-
2121-
if (superclassCtor->isObjC()) {
2122-
// Inherit the @objc name from the superclass initializer, if it
2123-
// has one.
2124-
if (auto objcAttr = superclassCtor->getAttrs().getAttribute<ObjCAttr>()) {
2125-
if (objcAttr->hasName()) {
2126-
auto *clonedAttr = objcAttr->clone(ctx);
2127-
clonedAttr->setImplicit(true);
2128-
ctor->getAttrs().add(clonedAttr);
2129-
}
2130-
}
2131-
2132-
auto errorConvention = superclassCtor->getForeignErrorConvention();
2133-
markAsObjC(tc, ctor, ObjCReason::ImplicitlyObjC, errorConvention);
2134-
}
2135-
if (superclassCtor->isRequired())
2136-
ctor->getAttrs().add(new (tc.Context) RequiredAttr(/*IsImplicit=*/true));
2137-
if (superclassCtor->isDynamic())
2138-
ctor->getAttrs().add(new (tc.Context) DynamicAttr(/*IsImplicit*/true));
2139-
2140-
// Wire up the overrides.
2141-
ctor->getAttrs().add(new (tc.Context) OverrideAttr(/*IsImplicit=*/true));
2142-
ctor->setOverriddenDecl(superclassCtor);
21432151
ctor->setValidationStarted();
21442152

2153+
configureDesignatedInitAttributes(tc, classDecl,
2154+
ctor, superclassCtor);
2155+
21452156
if (kind == DesignatedInitKind::Stub) {
21462157
// Make this a stub implementation.
21472158
createStubBody(tc, ctor);

Diff for: lib/Sema/TypeCheckAttr.cpp

+13-8
Original file line numberDiff line numberDiff line change
@@ -1959,13 +1959,14 @@ void AttributeChecker::visitUsableFromInlineAttr(UsableFromInlineAttr *attr) {
19591959
// FIXME: Once protocols can contain nominal types, do we want to allow
19601960
// these nominal types to have access control (and also @usableFromInline)?
19611961
if (isa<ProtocolDecl>(VD->getDeclContext())) {
1962-
diagnoseAndRemoveAttr(attr, diag::versioned_attr_in_protocol);
1962+
diagnoseAndRemoveAttr(attr, diag::usable_from_inline_attr_in_protocol);
19631963
return;
19641964
}
19651965

19661966
// @usableFromInline can only be applied to internal declarations.
19671967
if (VD->getFormalAccess() != AccessLevel::Internal) {
1968-
diagnoseAndRemoveAttr(attr, diag::versioned_attr_with_explicit_access,
1968+
diagnoseAndRemoveAttr(attr,
1969+
diag::usable_from_inline_attr_with_explicit_access,
19691970
VD->getFullName(),
19701971
VD->getFormalAccess());
19711972
return;
@@ -1974,7 +1975,13 @@ void AttributeChecker::visitUsableFromInlineAttr(UsableFromInlineAttr *attr) {
19741975
// Symbols of dynamically-dispatched declarations are never referenced
19751976
// directly, so marking them as @usableFromInline does not make sense.
19761977
if (VD->isDynamic()) {
1977-
diagnoseAndRemoveAttr(attr, diag::versioned_dynamic_not_supported);
1978+
diagnoseAndRemoveAttr(attr, diag::usable_from_inline_dynamic_not_supported);
1979+
return;
1980+
}
1981+
1982+
// On internal declarations, @inlinable implies @usableFromInline.
1983+
if (VD->getAttrs().hasAttribute<InlinableAttr>()) {
1984+
diagnoseAndRemoveAttr(attr, diag::inlinable_implies_usable_from_inline);
19781985
return;
19791986
}
19801987
}
@@ -2003,11 +2010,9 @@ void AttributeChecker::visitInlinableAttr(InlinableAttr *attr) {
20032010
return;
20042011
}
20052012

2006-
// @inlinable can only be applied to public or @usableFromInline
2007-
// declarations.
2008-
auto access = VD->getFormalAccess(/*useDC=*/nullptr,
2009-
/*treatUsableFromInlineAsPublic=*/true);
2010-
if (access < AccessLevel::Public) {
2013+
// @inlinable can only be applied to public or internal declarations.
2014+
auto access = VD->getFormalAccess();
2015+
if (access < AccessLevel::Internal) {
20112016
diagnoseAndRemoveAttr(attr, diag::inlinable_decl_not_public,
20122017
VD->getBaseName(),
20132018
access);

Diff for: stdlib/public/core/Algorithm.swift

-2
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,6 @@ public struct EnumeratedIterator<Base: IteratorProtocol> {
9898

9999
/// Construct from a `Base` iterator.
100100
@inlinable
101-
@usableFromInline
102101
internal init(_base: Base) {
103102
self._base = _base
104103
self._count = 0
@@ -145,7 +144,6 @@ public struct EnumeratedSequence<Base: Sequence> {
145144

146145
/// Construct from a `Base` sequence.
147146
@inlinable
148-
@usableFromInline
149147
internal init(_base: Base) {
150148
self._base = _base
151149
}

Diff for: stdlib/public/core/AnyHashable.swift

-11
Original file line numberDiff line numberDiff line change
@@ -61,26 +61,22 @@ internal struct _ConcreteHashableBox<Base : Hashable> : _AnyHashableBox {
6161
internal var _baseHashable: Base
6262

6363
@inlinable // FIXME(sil-serialize-all)
64-
@usableFromInline // FIXME(sil-serialize-all)
6564
internal init(_ base: Base) {
6665
self._baseHashable = base
6766
}
6867

6968

7069
@inlinable // FIXME(sil-serialize-all)
71-
@usableFromInline // FIXME(sil-serialize-all)
7270
internal var _typeID: ObjectIdentifier {
7371
return ObjectIdentifier(type(of: self))
7472
}
7573

7674
@inlinable // FIXME(sil-serialize-all)
77-
@usableFromInline // FIXME(sil-serialize-all)
7875
internal func _unbox<T : Hashable>() -> T? {
7976
return (self as _AnyHashableBox as? _ConcreteHashableBox<T>)?._baseHashable
8077
}
8178

8279
@inlinable // FIXME(sil-serialize-all)
83-
@usableFromInline // FIXME(sil-serialize-all)
8480
internal func _isEqual(to rhs: _AnyHashableBox) -> Bool? {
8581
if let rhs: Base = rhs._unbox() {
8682
return _baseHashable == rhs
@@ -89,25 +85,21 @@ internal struct _ConcreteHashableBox<Base : Hashable> : _AnyHashableBox {
8985
}
9086

9187
@inlinable // FIXME(sil-serialize-all)
92-
@usableFromInline // FIXME(sil-serialize-all)
9388
internal var _hashValue: Int {
9489
return _baseHashable.hashValue
9590
}
9691

9792
@inlinable // FIXME(sil-serialize-all)
98-
@usableFromInline // FIXME(sil-serialize-all)
9993
func _hash(_into hasher: inout _Hasher) {
10094
_baseHashable._hash(into: &hasher)
10195
}
10296

10397
@inlinable // FIXME(sil-serialize-all)
104-
@usableFromInline // FIXME(sil-serialize-all)
10598
internal var _base: Any {
10699
return _baseHashable
107100
}
108101

109102
@inlinable // FIXME(sil-serialize-all)
110-
@usableFromInline // FIXME(sil-serialize-all)
111103
internal
112104
func _downCastConditional<T>(into result: UnsafeMutablePointer<T>) -> Bool {
113105
guard let value = _baseHashable as? T else { return false }
@@ -122,7 +114,6 @@ internal struct _ConcreteHashableBox<Base : Hashable> : _AnyHashableBox {
122114
// turns a non-custom representation into a custom one, which is used as
123115
// the lowest-common-denominator for comparisons.
124116
@inlinable // FIXME(sil-serialize-all)
125-
@usableFromInline // FIXME(sil-serialize-all)
126117
internal func _getBridgedCustomAnyHashable<T>(_ value: T) -> AnyHashable? {
127118
let bridgedValue = _bridgeAnythingToObjectiveC(value)
128119
return (bridgedValue as?
@@ -191,7 +182,6 @@ public struct AnyHashable {
191182
}
192183

193184
@inlinable // FIXME(sil-serialize-all)
194-
@usableFromInline // FIXME(sil-serialize-all)
195185
internal init<H : Hashable>(_usingDefaultRepresentationOf base: H) {
196186
self._box = _ConcreteHashableBox(base)
197187
self._usedCustomRepresentation = false
@@ -217,7 +207,6 @@ public struct AnyHashable {
217207
/// This avoids the intermediate re-boxing we would get if we just did
218208
/// a downcast on `base`.
219209
@inlinable // FIXME(sil-serialize-all)
220-
@usableFromInline // FIXME(sil-serialize-all)
221210
internal
222211
func _downCastConditional<T>(into result: UnsafeMutablePointer<T>) -> Bool {
223212
// Attempt the downcast.

0 commit comments

Comments
 (0)