Skip to content

Commit 994ff25

Browse files
authored
Merge pull request #69360 from apple/es-bypass
Tests package types for non-resiliency
2 parents e8761b8 + 63746dd commit 994ff25

File tree

4 files changed

+446
-1
lines changed

4 files changed

+446
-1
lines changed

lib/AST/Decl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4905,7 +4905,7 @@ int TypeDecl::compare(const TypeDecl *type1, const TypeDecl *type2) {
49054905
}
49064906

49074907
bool NominalTypeDecl::isFormallyResilient() const {
4908-
// Private and (unversioned) internal types always have a
4908+
// Private, (unversioned) internal, and package types always have a
49094909
// fixed layout.
49104910
if (!getFormalAccessScope(/*useDC=*/nullptr,
49114911
/*treatUsableFromInlineAsPublic=*/true).isPublic())
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: split-file %s %t
3+
4+
// RUN: %target-swift-frontend -emit-module %t/Utils.swift \
5+
// RUN: -module-name Utils -swift-version 5 -I %t \
6+
// RUN: -package-name mypkg \
7+
// RUN: -enable-library-evolution \
8+
// RUN: -emit-module -emit-module-path %t/Utils.swiftmodule
9+
10+
// RUN: %target-swift-frontend -typecheck %t/Client.swift -I %t -swift-version 5 -package-name mypkg -verify
11+
12+
// RUN: %target-swift-frontend -emit-sil %t/Client.swift -package-name mypkg -I %t > %t/Client.sil
13+
// RUN: %FileCheck %s < %t/Client.sil
14+
15+
16+
//--- Utils.swift
17+
18+
// Resilient; public. Acessed indirectly.
19+
public struct PublicStruct {
20+
public var data: Int
21+
}
22+
23+
// Non-resilient; non-public. Accessed directly.
24+
package struct PkgStruct {
25+
package var data: Int
26+
}
27+
28+
// Non-resilient but accessed indirectly since generic.
29+
package struct PkgStructGeneric<T> {
30+
package var data: T
31+
}
32+
33+
// Non-resilient but accessed indirectly; member is of a resilient type.
34+
package struct PkgStructWithPublicMember {
35+
package var member: PublicStruct
36+
}
37+
38+
// Non-resilient but accessed indirectly; contains existential.
39+
package struct PkgStructWithPublicExistential {
40+
package var member: any PublicProto
41+
}
42+
43+
// Non-resilient but accessed indirectly; contains existential.
44+
package struct PkgStructWithPkgExistential {
45+
package var member: any PkgProto
46+
}
47+
48+
// Resilient; public. Acessed indirectly.
49+
public protocol PublicProto {
50+
var data: Int { get set }
51+
}
52+
53+
// Non-resilient but acessed indirectly; existential.
54+
package protocol PkgProto {
55+
var data: Int { get set }
56+
}
57+
58+
59+
//--- Client.swift
60+
import Utils
61+
62+
package func f(_ arg: PublicStruct) -> Int {
63+
return arg.data
64+
}
65+
66+
// CHECK: // f(_:)
67+
// CHECK-NEXT: sil @$s6Client1fySi5Utils12PublicStructVF : $@convention(thin) (@in_guaranteed PublicStruct) -> Int {
68+
// CHECK-NEXT: // %0 "arg" // users: %3, %1
69+
// CHECK-NEXT: bb0(%0 : $*PublicStruct):
70+
// CHECK-NEXT: debug_value %0 : $*PublicStruct, let, name "arg", argno 1, expr op_deref // id: %1
71+
// CHECK-NEXT: %2 = alloc_stack $PublicStruct // users: %7, %6, %5, %3
72+
// CHECK-NEXT: copy_addr %0 to [init] %2 : $*PublicStruct // id: %3
73+
// CHECK-NEXT: // function_ref PublicStruct.data.getter
74+
// CHECK-NEXT: %4 = function_ref @$s5Utils12PublicStructV4dataSivg : $@convention(method) (@in_guaranteed PublicStruct) -> Int // user: %5
75+
// CHECK-NEXT: %5 = apply %4(%2) : $@convention(method) (@in_guaranteed PublicStruct) -> Int // user: %8
76+
// CHECK-NEXT: destroy_addr %2 : $*PublicStruct // id: %6
77+
// CHECK-NEXT: dealloc_stack %2 : $*PublicStruct // id: %7
78+
// CHECK-NEXT: return %5 : $Int // id: %8
79+
// CHECK-NEXT: } // end sil function '$s6Client1fySi5Utils12PublicStructVF'
80+
81+
82+
package func g(_ arg: PkgStruct) -> Int {
83+
return arg.data
84+
}
85+
86+
// CHECK: // g(_:)
87+
// CHECK-NEXT: sil @$s6Client1gySi5Utils9PkgStructVF : $@convention(thin) (PkgStruct) -> Int {
88+
// CHECK-NEXT: // %0 "arg" // users: %2, %1
89+
// CHECK-NEXT: bb0(%0 : $PkgStruct):
90+
// CHECK-NEXT: debug_value %0 : $PkgStruct, let, name "arg", argno 1 // id: %1
91+
// CHECK-NEXT: %2 = struct_extract %0 : $PkgStruct, #PkgStruct.data // user: %3
92+
// CHECK-NEXT: return %2 : $Int // id: %3
93+
// CHECK-NEXT: } // end sil function '$s6Client1gySi5Utils9PkgStructVF'
94+
95+
package func m<T>(_ arg: PkgStructGeneric<T>) -> T {
96+
return arg.data
97+
}
98+
99+
// CHECK: // m<A>(_:)
100+
// CHECK-NEXT: sil @$s6Client1myx5Utils16PkgStructGenericVyxGlF : $@convention(thin) <T> (@in_guaranteed PkgStructGeneric<T>) -> @out T {
101+
// CHECK-NEXT: // %0 "$return_value" // user: %4
102+
// CHECK-NEXT: // %1 "arg" // users: %3, %2
103+
// CHECK-NEXT: bb0(%0 : $*T, %1 : $*PkgStructGeneric<T>):
104+
// CHECK-NEXT: debug_value %1 : $*PkgStructGeneric<T>, let, name "arg", argno 1, expr op_deref // id: %2
105+
// CHECK-NEXT: %3 = struct_element_addr %1 : $*PkgStructGeneric<T>, #PkgStructGeneric.data // user: %4
106+
// CHECK-NEXT: copy_addr %3 to [init] %0 : $*T // id: %4
107+
// CHECK-NEXT: %5 = tuple () // user: %6
108+
// CHECK-NEXT: return %5 : $() // id: %6
109+
// CHECK-NEXT: } // end sil function '$s6Client1myx5Utils16PkgStructGenericVyxGlF'
110+
111+
package func n(_ arg: PkgStructWithPublicMember) -> Int {
112+
return arg.member.data
113+
}
114+
115+
// CHECK: // n(_:)
116+
// CHECK-NEXT: sil @$s6Client1nySi5Utils25PkgStructWithPublicMemberVF : $@convention(thin) (@in_guaranteed PkgStructWithPublicMember) -> Int {
117+
// CHECK-NEXT: // %0 "arg" // users: %2, %1
118+
// CHECK-NEXT: bb0(%0 : $*PkgStructWithPublicMember):
119+
// CHECK-NEXT: debug_value %0 : $*PkgStructWithPublicMember, let, name "arg", argno 1, expr op_deref // id: %1
120+
// CHECK-NEXT: %2 = struct_element_addr %0 : $*PkgStructWithPublicMember, #PkgStructWithPublicMember.member // user: %4
121+
// CHECK-NEXT: %3 = alloc_stack $PublicStruct // users: %12, %10, %6, %4
122+
// CHECK-NEXT: copy_addr %2 to [init] %3 : $*PublicStruct // id: %4
123+
// CHECK-NEXT: %5 = alloc_stack $PublicStruct // users: %11, %9, %8, %6
124+
// CHECK-NEXT: copy_addr %3 to [init] %5 : $*PublicStruct // id: %6
125+
// CHECK-NEXT: // function_ref PublicStruct.data.getter
126+
// CHECK-NEXT: %7 = function_ref @$s5Utils12PublicStructV4dataSivg : $@convention(method) (@in_guaranteed PublicStruct) -> Int // user: %8
127+
// CHECK-NEXT: %8 = apply %7(%5) : $@convention(method) (@in_guaranteed PublicStruct) -> Int // user: %13
128+
// CHECK-NEXT: destroy_addr %5 : $*PublicStruct // id: %9
129+
// CHECK-NEXT: destroy_addr %3 : $*PublicStruct // id: %10
130+
// CHECK-NEXT: dealloc_stack %5 : $*PublicStruct // id: %11
131+
// CHECK-NEXT: dealloc_stack %3 : $*PublicStruct // id: %12
132+
// CHECK-NEXT: return %8 : $Int // id: %13
133+
// CHECK-NEXT: } // end sil function '$s6Client1nySi5Utils25PkgStructWithPublicMemberVF'
134+
135+
package func p(_ arg: PkgStructWithPublicExistential) -> any PublicProto {
136+
return arg.member
137+
}
138+
139+
// CHECK: // p(_:)
140+
// CHECK-NEXT: sil @$s6Client1py5Utils11PublicProto_pAC013PkgStructWithC11ExistentialVF : $@convention(thin) (@in_guaranteed PkgStructWithPublicExistential) -> @out any PublicProto {
141+
// CHECK-NEXT: // %0 "$return_value" // user: %4
142+
// CHECK-NEXT: // %1 "arg" // users: %3, %2
143+
// CHECK-NEXT: bb0(%0 : $*any PublicProto, %1 : $*PkgStructWithPublicExistential):
144+
// CHECK-NEXT: debug_value %1 : $*PkgStructWithPublicExistential, let, name "arg", argno 1, expr op_deref // id: %2
145+
// CHECK-NEXT: %3 = struct_element_addr %1 : $*PkgStructWithPublicExistential, #PkgStructWithPublicExistential.member // user: %4
146+
// CHECK-NEXT: copy_addr %3 to [init] %0 : $*any PublicProto // id: %4
147+
// CHECK-NEXT: %5 = tuple () // user: %6
148+
// CHECK-NEXT: return %5 : $() // id: %6
149+
// CHECK-NEXT: } // end sil function '$s6Client1py5Utils11PublicProto_pAC013PkgStructWithC11ExistentialVF'
150+
151+
package func q(_ arg: PkgStructWithPkgExistential) -> any PkgProto {
152+
return arg.member
153+
}
154+
155+
// CHECK: // q(_:)
156+
// CHECK-NEXT: sil @$s6Client1qy5Utils8PkgProto_pAC0c10StructWithC11ExistentialVF : $@convention(thin) (@in_guaranteed PkgStructWithPkgExistential) -> @out any PkgProto {
157+
// CHECK-NEXT: // %0 "$return_value" // user: %4
158+
// CHECK-NEXT: // %1 "arg" // users: %3, %2
159+
// CHECK-NEXT: bb0(%0 : $*any PkgProto, %1 : $*PkgStructWithPkgExistential):
160+
// CHECK-NEXT: debug_value %1 : $*PkgStructWithPkgExistential, let, name "arg", argno 1, expr op_deref // id: %2
161+
// CHECK-NEXT: %3 = struct_element_addr %1 : $*PkgStructWithPkgExistential, #PkgStructWithPkgExistential.member // user: %4
162+
// CHECK-NEXT: copy_addr %3 to [init] %0 : $*any PkgProto // id: %4
163+
// CHECK-NEXT: %5 = tuple () // user: %6
164+
// CHECK-NEXT: return %5 : $() // id: %6
165+
// CHECK-NEXT: } // end sil function '$s6Client1qy5Utils8PkgProto_pAC0c10StructWithC11ExistentialVF'
166+
167+
package func r(_ arg: PublicProto) -> Int {
168+
return arg.data
169+
}
170+
171+
// CHECK: // r(_:)
172+
// CHECK-NEXT: sil @$s6Client1rySi5Utils11PublicProto_pF : $@convention(thin) (@in_guaranteed any PublicProto) -> Int {
173+
// CHECK-NEXT: // %0 "arg" // users: %2, %1
174+
// CHECK-NEXT: bb0(%0 : $*any PublicProto):
175+
// CHECK-NEXT: debug_value %0 : $*any PublicProto, let, name "arg", argno 1, expr op_deref // id: %1
176+
// CHECK-NEXT: %2 = open_existential_addr immutable_access %0 : $*any PublicProto
177+
// CHECK-NEXT: %3 = alloc_stack $@opened
178+
// CHECK-NEXT: copy_addr %2 to [init] %3 : $*@opened
179+
// CHECK-NEXT: %5 = witness_method $@opened
180+
// CHECK-NEXT: %6 = apply %5<@opened
181+
// CHECK-NEXT: destroy_addr %3 : $*@opened
182+
// CHECK-NEXT: dealloc_stack %3 : $*@opened
183+
// CHECK-NEXT: return %6 : $Int
184+
// CHECK-NEXT: } // end sil function '$s6Client1rySi5Utils11PublicProto_pF'
185+
186+
package func s(_ arg: PkgProto) -> Int {
187+
return arg.data
188+
}
189+
// CHECK: // s(_:)
190+
// CHECK-NEXT: sil @$s6Client1sySi5Utils8PkgProto_pF : $@convention(thin) (@in_guaranteed any PkgProto) -> Int {
191+
// CHECK-NEXT: // %0 "arg" // users: %2, %1
192+
// CHECK-NEXT: bb0(%0 : $*any PkgProto):
193+
// CHECK-NEXT: debug_value %0 : $*any PkgProto, let, name "arg", argno 1, expr op_deref // id: %1
194+
// CHECK-NEXT: %2 = open_existential_addr immutable_access %0 : $*any PkgProto to $*@opened
195+
// CHECK-NEXT: %3 = alloc_stack $@opened
196+
// CHECK-NEXT: copy_addr %2 to [init] %3 : $*@opened
197+
// CHECK-NEXT: %5 = witness_method $@opened
198+
// CHECK-NEXT: %6 = apply %5<@opened
199+
// CHECK-NEXT: destroy_addr %3 : $*@opened
200+
// CHECK-NEXT: dealloc_stack %3 : $*@opened
201+
// CHECK-NEXT: return %6 : $Int
202+
// CHECK-NEXT: } // end sil function '$s6Client1sySi5Utils8PkgProto_pF'
203+
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: split-file %s %t
3+
4+
// RUN: %target-swift-frontend -emit-module %t/Utils.swift \
5+
// RUN: -module-name Utils -swift-version 5 -I %t \
6+
// RUN: -package-name mypkg \
7+
// RUN: -enable-library-evolution \
8+
// RUN: -emit-module -emit-module-path %t/Utils.swiftmodule
9+
10+
// RUN: %target-swift-frontend -emit-sil %t/Client.swift -package-name mypkg -I %t > %t/Client.sil
11+
// RUN: %FileCheck %s < %t/Client.sil
12+
// RUN: %target-swift-frontend -typecheck %t/Client.swift -I %t -swift-version 5 -package-name mypkg -verify
13+
14+
//--- Utils.swift
15+
16+
// Resilient; public.
17+
// Switch stmt requires @unknown default.
18+
public enum PublicEnum {
19+
case one
20+
case two(Int)
21+
}
22+
23+
// Resilient; public.
24+
public struct PublicStruct {
25+
public var publicVar: Int
26+
}
27+
28+
// Non-resilient; frozen. Accessed directly.
29+
// Switch stmt does not require @unknown default.
30+
@frozen
31+
public enum FrozenPublicEnum {
32+
case one
33+
case two(Int)
34+
}
35+
36+
// Non-resilient; non-public / associated value is also non-resilient (Int is @frozen public).
37+
// Accessed directly.
38+
// Switch stmt does not require @unknown default.
39+
package enum PkgEnum {
40+
case one
41+
case two(Int)
42+
}
43+
44+
// Non-resilient but accessed indirectly since associated value is resilient.
45+
// Passed by address to func as @in_guaranteed in Silgen.
46+
// Switch stmt does not require @unknown default.
47+
package enum PkgEnumWithPublicCase {
48+
case one
49+
case two(PublicStruct)
50+
}
51+
52+
// Non-resilient but accessed indirectly since associated value is resilient (existential).
53+
// Passed by address to func as @in_guaranteed in Silgen.
54+
// Switch stmt does not require @unknown default.
55+
package enum PkgEnumWithExistentialCase {
56+
case one
57+
case two(any StringProtocol)
58+
}
59+
60+
// Resilient since inlinable.
61+
@usableFromInline
62+
package enum UfiPkgEnum {
63+
case one
64+
case two(Int)
65+
}
66+
67+
68+
//--- Client.swift
69+
import Utils
70+
71+
package func f(_ arg: PkgEnum) -> Int {
72+
switch arg { // no-warning
73+
case .one:
74+
return 1
75+
case .two(let val):
76+
return 2 + val
77+
}
78+
}
79+
80+
// CHECK: // f(_:)
81+
// CHECK-NEXT: sil @$s6Client1fySi5Utils7PkgEnumOF : $@convention(thin) (PkgEnum) -> Int {
82+
// CHECK-NEXT: // %0 "arg" // users: %2, %1
83+
// CHECK-NEXT: bb0(%0 : $PkgEnum):
84+
// CHECK-NEXT: debug_value %0 : $PkgEnum, let, name "arg", argno 1 // id: %1
85+
// CHECK-NEXT: switch_enum %0 : $PkgEnum, case #PkgEnum.one!enumelt: bb1, case #PkgEnum.two!enumelt: bb2 // id: %2
86+
87+
package func g1(_ arg: PkgEnumWithPublicCase) -> Int {
88+
switch arg { // no-warning
89+
case .one:
90+
return 1
91+
case .two(let val):
92+
return 2 + val.publicVar
93+
}
94+
}
95+
96+
// CHECK: // g1(_:)
97+
// CHECK-NEXT: sil @$s6Client2g1ySi5Utils21PkgEnumWithPublicCaseOF : $@convention(thin) (@in_guaranteed PkgEnumWithPublicCase) -> Int {
98+
// CHECK-NEXT: // %0 "arg" // users: %3, %1
99+
// CHECK-NEXT: bb0(%0 : $*PkgEnumWithPublicCase):
100+
// CHECK-NEXT: debug_value %0 : $*PkgEnumWithPublicCase, let, name "arg", argno 1, expr op_deref // id: %1
101+
// CHECK-NEXT: %2 = alloc_stack $PkgEnumWithPublicCase // users: %29, %9, %7, %4, %3
102+
// CHECK-NEXT: copy_addr %0 to [init] %2 : $*PkgEnumWithPublicCase // id: %3
103+
// CHECK-NEXT: switch_enum_addr %2 : $*PkgEnumWithPublicCase, case #PkgEnumWithPublicCase.one!enumelt: bb1, case #PkgEnumWithPublicCase.two!enumelt: bb2 // id: %4
104+
105+
package func g2(_ arg: PkgEnumWithExistentialCase) -> any StringProtocol {
106+
switch arg { // no-warning
107+
case .one:
108+
return "1"
109+
case .two(let val):
110+
return val
111+
}
112+
}
113+
114+
// CHECK: // g2(_:)
115+
// CHECK-NEXT: sil @$s6Client2g2ySy_p5Utils26PkgEnumWithExistentialCaseOF : $@convention(thin) (@in_guaranteed PkgEnumWithExistentialCase) -> @out any StringProtocol {
116+
// CHECK-NEXT: // %0 "$return_value" // users: %20, %12
117+
// CHECK-NEXT: // %1 "arg" // users: %4, %2
118+
// CHECK-NEXT: bb0(%0 : $*any StringProtocol, %1 : $*PkgEnumWithExistentialCase):
119+
// CHECK-NEXT: debug_value %1 : $*PkgEnumWithExistentialCase, let, name "arg", argno 1, expr op_deref // id: %2
120+
// CHECK-NEXT: %3 = alloc_stack $PkgEnumWithExistentialCase // users: %23, %16, %14, %5, %4
121+
// CHECK-NEXT: copy_addr %1 to [init] %3 : $*PkgEnumWithExistentialCase // id: %4
122+
// CHECK-NEXT: switch_enum_addr %3 : $*PkgEnumWithExistentialCase, case #PkgEnumWithExistentialCase.one!enumelt: bb1, case #PkgEnumWithExistentialCase.two!enumelt: bb2 // id: %5
123+
124+
125+
@inlinable
126+
package func h(_ arg: UfiPkgEnum) -> Int {
127+
switch arg { // expected-warning {{switch covers known cases, but 'UfiPkgEnum' may have additional unknown values}} {{none}} expected-note {{handle unknown values using "@unknown default"}}
128+
case .one:
129+
return 1
130+
case .two(let val):
131+
return 2 + val
132+
}
133+
}
134+
135+
// CHECK: // h(_:)
136+
// CHECK-NEXT: sil @$s6Client1hySi5Utils10UfiPkgEnumOF : $@convention(thin) (@in_guaranteed UfiPkgEnum) -> Int {
137+
// CHECK-NEXT: // %0 "arg" // users: %3, %1
138+
// CHECK-NEXT: bb0(%0 : $*UfiPkgEnum):
139+
// CHECK-NEXT: debug_value %0 : $*UfiPkgEnum, let, name "arg", argno 1, expr op_deref // id: %1
140+
// CHECK-NEXT: %2 = alloc_stack $UfiPkgEnum // users: %21, %10, %8, %5, %4, %3
141+
// CHECK-NEXT: copy_addr %0 to [init] %2 : $*UfiPkgEnum // id: %3
142+
// CHECK-NEXT: %4 = value_metatype $@thick UfiPkgEnum.Type, %2 : $*UfiPkgEnum // user: %24
143+
// CHECK-NEXT: switch_enum_addr %2 : $*UfiPkgEnum, case #UfiPkgEnum.one!enumelt: bb1, case #UfiPkgEnum.two!enumelt: bb2, default bb3 // id: %5
144+
145+
public func k(_ arg: PublicEnum) -> Int {
146+
switch arg { // expected-warning {{switch covers known cases, but 'PublicEnum' may have additional unknown values}} {{none}} expected-note {{handle unknown values using "@unknown default"}}
147+
case .one:
148+
return 1
149+
case .two(let val):
150+
return 2 + val
151+
}
152+
}
153+
// CHECK: // k(_:)
154+
// CHECK-NEXT: sil @$s6Client1kySi5Utils10PublicEnumOF : $@convention(thin) (@in_guaranteed PublicEnum) -> Int {
155+
// CHECK-NEXT: // %0 "arg" // users: %3, %1
156+
// CHECK-NEXT: bb0(%0 : $*PublicEnum):
157+
// CHECK-NEXT: debug_value %0 : $*PublicEnum, let, name "arg", argno 1, expr op_deref // id: %1
158+
// CHECK-NEXT: %2 = alloc_stack $PublicEnum // users: %21, %10, %8, %5, %4, %3
159+
// CHECK-NEXT: copy_addr %0 to [init] %2 : $*PublicEnum // id: %3
160+
// CHECK-NEXT: %4 = value_metatype $@thick PublicEnum.Type, %2 : $*PublicEnum // user: %24
161+
// CHECK-NEXT: switch_enum_addr %2 : $*PublicEnum, case #PublicEnum.one!enumelt: bb1, case #PublicEnum.two!enumelt: bb2, default bb3 // id: %5
162+
163+
public func m(_ arg: FrozenPublicEnum) -> Int {
164+
switch arg { // no-warning
165+
case .one:
166+
return 1
167+
case .two(let val):
168+
return 2 + val
169+
}
170+
}
171+
172+
// CHECK: // m(_:)
173+
// CHECK-NEXT: sil @$s6Client1mySi5Utils16FrozenPublicEnumOF : $@convention(thin) (FrozenPublicEnum) -> Int {
174+
// CHECK-NEXT: // %0 "arg" // users: %2, %1
175+
// CHECK-NEXT: bb0(%0 : $FrozenPublicEnum):
176+
// CHECK-NEXT: debug_value %0 : $FrozenPublicEnum, let, name "arg", argno 1 // id: %1
177+
// CHECK-NEXT: switch_enum %0 : $FrozenPublicEnum, case #FrozenPublicEnum.one!enumelt: bb1, case #FrozenPublicEnum.two!enumelt: bb2 // id: %2
178+
179+

0 commit comments

Comments
 (0)