Skip to content

Commit cfb50a0

Browse files
authored
Merge pull request #75191 from xedin/inlinable-init-accessors
[AST/Sema] Make it possible to use init accessors in inlinable initializers
2 parents cbd68dd + be33968 commit cfb50a0

11 files changed

+277
-24
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6910,8 +6910,8 @@ ERROR(frozen_attr_on_internal_type,
69106910

69116911
ERROR(usable_from_inline_attr_with_explicit_access,
69126912
none, "'@usableFromInline' attribute can only be applied to internal or package "
6913-
"declarations, but %0 is %select{private|fileprivate|%error|package|public|open}1",
6914-
(DeclName, AccessLevel))
6913+
"declarations, but %kind0 is %select{private|fileprivate|%error|package|public|open}1",
6914+
(const ValueDecl *, AccessLevel))
69156915

69166916
WARNING(inlinable_implies_usable_from_inline,none,
69176917
"'@usableFromInline' attribute has no effect on '@inlinable' %kind0",

lib/AST/ASTPrinter.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -353,11 +353,6 @@ PrintOptions PrintOptions::printSwiftInterfaceFile(ModuleDecl *ModuleToPrint,
353353
}
354354
}
355355

356-
if (auto *accessor = dyn_cast<AccessorDecl>(D)) {
357-
if (accessor->isInitAccessor() && !options.PrintForSIL)
358-
return false;
359-
}
360-
361356
return ShouldPrintChecker::shouldPrint(D, options);
362357
}
363358
};

lib/AST/AccessRequests.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ AccessLevelRequest::evaluate(Evaluator &evaluator, ValueDecl *D) const {
6767
return AccessLevel::Private;
6868
case AccessorKind::Init:
6969
// These are only called from within the same module.
70-
return std::min(storage->getFormalAccess(), AccessLevel::Internal);
70+
return AccessLevel::Internal;
7171
}
7272
}
7373

lib/Sema/ResilienceDiagnostics.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,17 @@ bool TypeChecker::diagnoseInlinableDeclRefAccess(SourceLoc loc,
6464
auto *DC = where.getDeclContext();
6565
auto &Context = DC->getASTContext();
6666

67+
if (auto *init = dyn_cast<ConstructorDecl>(DC)) {
68+
if (init->isDesignatedInit()) {
69+
auto *storage = dyn_cast<AbstractStorageDecl>(D);
70+
if (storage && storage->hasInitAccessor()) {
71+
if (diagnoseInlinableDeclRefAccess(
72+
loc, storage->getAccessor(AccessorKind::Init), where))
73+
return true;
74+
}
75+
}
76+
}
77+
6778
ImportAccessLevel problematicImport = D->getImportAccessFrom(DC);
6879
if (problematicImport.has_value()) {
6980
auto SF = DC->getParentSourceFile();
@@ -112,7 +123,7 @@ bool TypeChecker::diagnoseInlinableDeclRefAccess(SourceLoc loc,
112123

113124
// Swift 4.2 did not check accessor accessibility.
114125
if (auto accessor = dyn_cast<AccessorDecl>(D)) {
115-
if (!Context.isSwiftVersionAtLeast(5))
126+
if (!accessor->isInitAccessor() && !Context.isSwiftVersionAtLeast(5))
116127
downgradeToWarning = DowngradeToWarning::Yes;
117128
}
118129

lib/Sema/TypeCheckAttr.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3273,7 +3273,7 @@ void AttributeChecker::visitUsableFromInlineAttr(UsableFromInlineAttr *attr) {
32733273
VD->getFormalAccess() != AccessLevel::Package) {
32743274
diagnoseAndRemoveAttr(attr,
32753275
diag::usable_from_inline_attr_with_explicit_access,
3276-
VD->getName(), VD->getFormalAccess());
3276+
VD, VD->getFormalAccess());
32773277
return;
32783278
}
32793279

test/Compatibility/attr_usableFromInline_swift4.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
// RUN: %target-typecheck-verify-swift -enable-testing -swift-version 4 -disable-objc-attr-requires-foundation-module -enable-objc-interop
33

44
@usableFromInline private func privateVersioned() {}
5-
// expected-error@-1 {{'@usableFromInline' attribute can only be applied to internal or package declarations, but 'privateVersioned()' is private}}
5+
// expected-error@-1 {{'@usableFromInline' attribute can only be applied to internal or package declarations, but global function 'privateVersioned()' is private}}
66

77
@usableFromInline fileprivate func fileprivateVersioned() {}
8-
// expected-error@-1 {{'@usableFromInline' attribute can only be applied to internal or package declarations, but 'fileprivateVersioned()' is fileprivate}}
8+
// expected-error@-1 {{'@usableFromInline' attribute can only be applied to internal or package declarations, but global function 'fileprivateVersioned()' is fileprivate}}
99

1010
@usableFromInline internal func internalVersioned() {}
1111
// OK
@@ -14,11 +14,11 @@
1414
// OK
1515

1616
@usableFromInline public func publicVersioned() {}
17-
// expected-error@-1 {{'@usableFromInline' attribute can only be applied to internal or package declarations, but 'publicVersioned()' is public}}
17+
// expected-error@-1 {{'@usableFromInline' attribute can only be applied to internal or package declarations, but global function 'publicVersioned()' is public}}
1818

1919
internal class InternalClass {
2020
@usableFromInline public func publicVersioned() {}
21-
// expected-error@-1 {{'@usableFromInline' attribute can only be applied to internal or package declarations, but 'publicVersioned()' is public}}
21+
// expected-error@-1 {{'@usableFromInline' attribute can only be applied to internal or package declarations, but instance method 'publicVersioned()' is public}}
2222
}
2323

2424
fileprivate class filePrivateClass {

test/Compatibility/attr_usableFromInline_swift42.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
// RUN: %target-typecheck-verify-swift -enable-testing -swift-version 4.2 -disable-objc-attr-requires-foundation-module -enable-objc-interop
33

44
@usableFromInline private func privateVersioned() {}
5-
// expected-error@-1 {{'@usableFromInline' attribute can only be applied to internal or package declarations, but 'privateVersioned()' is private}}
5+
// expected-error@-1 {{'@usableFromInline' attribute can only be applied to internal or package declarations, but global function 'privateVersioned()' is private}}
66

77
@usableFromInline fileprivate func fileprivateVersioned() {}
8-
// expected-error@-1 {{'@usableFromInline' attribute can only be applied to internal or package declarations, but 'fileprivateVersioned()' is fileprivate}}
8+
// expected-error@-1 {{'@usableFromInline' attribute can only be applied to internal or package declarations, but global function 'fileprivateVersioned()' is fileprivate}}
99

1010
@usableFromInline internal func internalVersioned() {}
1111
// OK
@@ -14,12 +14,12 @@
1414
// OK
1515

1616
@usableFromInline public func publicVersioned() {}
17-
// expected-error@-1 {{'@usableFromInline' attribute can only be applied to internal or package declarations, but 'publicVersioned()' is public}}
17+
// expected-error@-1 {{'@usableFromInline' attribute can only be applied to internal or package declarations, but global function 'publicVersioned()' is public}}
1818

1919
internal class InternalClass {
2020
// expected-note@-1 2{{type declared here}}
2121
@usableFromInline public func publicVersioned() {}
22-
// expected-error@-1 {{'@usableFromInline' attribute can only be applied to internal or package declarations, but 'publicVersioned()' is public}}
22+
// expected-error@-1 {{'@usableFromInline' attribute can only be applied to internal or package declarations, but instance method 'publicVersioned()' is public}}
2323
}
2424

2525
fileprivate class filePrivateClass {
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// RUN: %empty-directory(%t/src)
2+
// RUN: split-file %s %t/src
3+
4+
// RUN: %target-build-swift %t/src/Library.swift -swift-version 5 -emit-module -emit-library \
5+
// RUN: -enable-library-evolution \
6+
// RUN: -module-name Library \
7+
// RUN: -o %t/%target-library-name(Library) \
8+
// RUN: -emit-module-interface-path %t/Library.swiftinterface
9+
10+
// RUN: %target-codesign %t/%target-library-name(Library)
11+
12+
// RUN: %target-build-swift -I %t -L %t -l Library %t/src/main.swift %target-rpath(%t) -o %t/main.out
13+
// RUN: %target-codesign %t/main.out
14+
// RUN: %target-run %t/main.out %t/%target-library-name(Library) 2>&1 | %FileCheck %t/src/main.swift
15+
16+
// RUN: rm %t/Library.swiftmodule
17+
18+
// RUN: %target-build-swift -I %t -L %t -l Library %t/src/main.swift %target-rpath(%t) -o %t/main.out
19+
// RUN: %target-codesign %t/main.out
20+
// RUN: %target-run %t/main.out %t/%target-library-name(Library) 2>&1 | %FileCheck %t/src/main.swift
21+
22+
// REQUIRES: executable_test
23+
24+
//--- Library.swift
25+
@frozen
26+
public struct Inlinable {
27+
var _x: Int
28+
29+
public var x: Int {
30+
@usableFromInline
31+
@storageRestrictions(initializes: _x)
32+
init {
33+
self._x = newValue
34+
}
35+
36+
get {
37+
_x
38+
}
39+
}
40+
41+
@inlinable
42+
public init(x: Int) {
43+
self.x = x
44+
}
45+
}
46+
47+
@frozen
48+
public struct Transparent {
49+
@usableFromInline
50+
var _x: Int
51+
52+
public var x: Int {
53+
@_alwaysEmitIntoClient
54+
@storageRestrictions(initializes: _x)
55+
init {
56+
self._x = newValue
57+
}
58+
59+
get {
60+
_x
61+
}
62+
}
63+
64+
@_alwaysEmitIntoClient
65+
public init(x: Int) {
66+
self.x = x
67+
}
68+
}
69+
70+
//--- main.swift
71+
import Library
72+
73+
let inlinable = Inlinable(x: 42)
74+
print("Inlinable.x = \(inlinable.x)")
75+
// CHECK: Inlinable.x = 42
76+
77+
let transparent = Transparent(x: -1)
78+
print("Transparent.x = \(transparent.x)")
79+
// CHECK: Transparent.x = -1
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
// RUN: %empty-directory(%t/src)
2+
// RUN: split-file %s %t/src
3+
4+
/// Build the library A
5+
// RUN: %target-swift-frontend -emit-module %t/src/A.swift \
6+
// RUN: -module-name A -swift-version 5 -enable-library-evolution \
7+
// RUN: -emit-module-path %t/A.swiftmodule \
8+
// RUN: -emit-module-interface-path %t/A.swiftinterface
9+
10+
// RUN: %FileCheck %t/src/A.swift < %t/A.swiftinterface
11+
12+
// Build the client using module
13+
// RUN: %target-swift-emit-sil -verify -module-name Client -I %t %t/src/Client.swift | %FileCheck %t/src/Client.swift
14+
15+
// RUN: rm %t/A.swiftmodule
16+
17+
// Re-build the client using interface
18+
// RUN: %target-swift-emit-sil -verify -module-name Client -I %t %t/src/Client.swift | %FileCheck %t/src/Client.swift
19+
20+
// REQUIRES: asserts
21+
22+
//--- A.swift
23+
@frozen
24+
public struct Inlinable {
25+
var _x: Int
26+
27+
// CHECK: public var x: Swift.Int {
28+
// CHECK-NEXT: @usableFromInline
29+
// CHECK-NEXT: @storageRestrictions(initializes: _x) init
30+
// CHECK-NEXT: get
31+
// CHECK-NEXT }
32+
33+
public var x: Int {
34+
@usableFromInline
35+
@storageRestrictions(initializes: _x)
36+
init {
37+
self._x = newValue
38+
}
39+
40+
get {
41+
_x
42+
}
43+
}
44+
45+
@inlinable
46+
public init(x: Int) {
47+
self.x = x
48+
}
49+
}
50+
51+
public struct Internal {
52+
// CHECK: public var y: Swift.Int {
53+
// CHECK-NEXT: get
54+
// CHECK-NEXT: }
55+
56+
public var y: Int {
57+
init {
58+
}
59+
60+
get { 0 }
61+
}
62+
63+
init(y: Int) {
64+
self.y = y
65+
}
66+
}
67+
68+
@frozen
69+
public struct Transparent {
70+
@usableFromInline
71+
var _x: Int
72+
73+
// CHECK: public var x: Swift.Int {
74+
// CHECK-NEXT: @_alwaysEmitIntoClient @storageRestrictions(initializes: _x) init {
75+
// CHECK-NEXT: self._x = newValue
76+
// CHECK-NEXT: }
77+
// CHECK-NEXT: get
78+
// CHECK-NEXT }
79+
80+
public var x: Int {
81+
@_alwaysEmitIntoClient
82+
@storageRestrictions(initializes: _x)
83+
init {
84+
self._x = newValue
85+
}
86+
87+
get {
88+
_x
89+
}
90+
}
91+
92+
@_alwaysEmitIntoClient
93+
public init(x: Int) {
94+
self.x = x
95+
}
96+
}
97+
98+
//--- Client.swift
99+
import A
100+
101+
// CHECK-LABEL: sil hidden @$s6Client15testTransparentyyF : $@convention(thin) () -> ()
102+
// CHECK: [[X:%.*]] = struct $Int (%1 : $Builtin.Int64)
103+
// CHECK-NEXT: // function_ref Transparent.init(x:)
104+
// CHECK-NEXT: [[TRANSPARENT_REF:%.*]] = function_ref @$s1A11TransparentV1xACSi_tcfC : $@convention(method) (Int, @thin Transparent.Type) -> Transparent
105+
// CHECK-NEXT: apply [[TRANSPARENT_REF]]([[X]], %0) : $@convention(method) (Int, @thin Transparent.Type) -> Transparent
106+
func testTransparent() {
107+
_ = Transparent(x: 42)
108+
}
109+
110+
// CHECK-LABEL: sil shared @$s1A11TransparentV1xACSi_tcfC : $@convention(method) (Int, @thin Transparent.Type) -> Transparent
111+
112+
// CHECK-LABEL: sil hidden @$s6Client13testInlinableyyF : $@convention(thin) () -> ()
113+
// CHECK: [[X:%.*]] = struct $Int (%1 : $Builtin.Int64)
114+
// CHECK-NEXT: // function_ref Inlinable.init(x:)
115+
// CHECK-NEXT: [[INLINABLE_REF:%.*]] = function_ref @$s1A9InlinableV1xACSi_tcfC : $@convention(method) (Int, @thin Inlinable.Type) -> Inlinable
116+
// CHECK-NEXT: apply [[INLINABLE_REF]]([[X]], %0) : $@convention(method) (Int, @thin Inlinable.Type) -> Inlinable
117+
func testInlinable() {
118+
_ = Inlinable(x: 42)
119+
}
120+
121+
// CHECK-LABEL: sil @$s1A9InlinableV1xACSi_tcfC : $@convention(method) (Int, @thin Inlinable.Type) -> Inlinable
122+
123+
// CHECK-LABEL: sil shared @$s1A11TransparentV1xSivi : $@convention(thin) (Int, @thin Transparent.Type) -> @out Int

test/attr/attr_alwaysEmitIntoClient.swift

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,31 @@ public func publicFunction() {}
1515
internalFunction() // expected-error {{global function 'internalFunction()' is internal and cannot be referenced from an '@_alwaysEmitIntoClient' function}}
1616
versionedFunction()
1717
publicFunction()
18-
}
18+
}
19+
20+
public struct TestInitAccessors {
21+
var _x: Int
22+
23+
public var x: Int {
24+
@storageRestrictions(initializes: _x)
25+
init { // expected-note 2 {{init acecssor for property 'x' is not '@usableFromInline' or public}}
26+
self._x = newValue
27+
}
28+
29+
get {
30+
self._x
31+
}
32+
33+
set {}
34+
}
35+
36+
@_alwaysEmitIntoClient
37+
public init(x: Int) {
38+
self.x = 0 // expected-error {{init acecssor for property 'x' is internal and cannot be referenced from an '@_alwaysEmitIntoClient' function}}
39+
}
40+
41+
@inlinable
42+
public init() {
43+
self.x = 0 // expected-error {{init acecssor for property 'x' is internal and cannot be referenced from an '@inlinable' function}}
44+
}
45+
}

0 commit comments

Comments
 (0)