Skip to content

Commit 0c882d4

Browse files
Merge pull request #85625 from aschwaighofer/wip_embedded_cast_tuples
[embedded] Allow casting to tuples and tighten the check which existentials we support in embedded with existentials
2 parents 27ebe4d + 003273c commit 0c882d4

File tree

4 files changed

+250
-3
lines changed

4 files changed

+250
-3
lines changed

SwiftCompilerSources/Sources/Optimizer/ModulePasses/EmbeddedSwiftDiagnostics.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,11 @@ private struct FunctionChecker {
9494
for conf in ie.conformances {
9595
try checkConformance(conf, location: ie.location)
9696
}
97+
} else if instruction is OpenExistentialAddrInst {
98+
// okay in embedded with exitentials
99+
} else {
100+
// not supported even in embedded with exitentials
101+
throw Diagnostic(.embedded_swift_existential_type, instruction.operands[0].value.type, at: instruction.location)
97102
}
98103

99104
case let aeb as AllocExistentialBoxInst:

SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1051,8 +1051,7 @@ func isCastSupportedInEmbeddedSwift(from sourceType: Type,
10511051
return false
10521052
}
10531053

1054-
// Tuple?
1055-
if !destType.isStruct && !destType.isClass && !destType.isEnum {
1054+
if !destType.isStruct && !destType.isClass && !destType.isEnum && !destType.isTuple {
10561055
return false
10571056
}
10581057

test/embedded/existential.swift

Lines changed: 135 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,92 @@ func test7(_ p: any Any) {
216216
c.a()
217217
}
218218

219+
class BaseClass {
220+
func foo() { print("BaseClass.foo") }
221+
deinit {
222+
print("BaseClass.deinit")
223+
}
224+
}
225+
226+
class SubClass : BaseClass {
227+
override func foo() { print("SubClass.foo") }
228+
}
229+
230+
func test8(_ p: any Any) {
231+
print("test any as? SubClass")
232+
if let c = p as? SubClass {
233+
print("success")
234+
c.foo()
235+
} else {
236+
print("cast failed")
237+
}
238+
}
239+
240+
func test9(_ p: any Any) {
241+
print("test any as? BaseClass")
242+
if let c = p as? BaseClass {
243+
print("success")
244+
c.foo()
245+
} else {
246+
print("cast failed")
247+
}
248+
}
249+
250+
func test10(_ p: any Any) {
251+
print("test any as! BaseClass")
252+
let c = p as! BaseClass
253+
c.foo()
254+
}
255+
256+
func test11(_ p: any Any) {
257+
print("test any as! SubClass")
258+
let c = p as! SubClass
259+
c.foo()
260+
}
261+
262+
func test12(_ p: any Any) {
263+
print("test any as! (Int, Int, Int, Int)")
264+
if let c = p as? (Int, Int, Int, Int) {
265+
print("success")
266+
print("tuple: \(c.0)")
267+
} else {
268+
print("cast failed")
269+
}
270+
}
271+
272+
protocol Q {
273+
func printit()
274+
}
275+
276+
protocol P4<T> {
277+
associatedtype T: Q
278+
279+
var t: T { get }
280+
}
281+
282+
struct QConformer : Q {
283+
var x = (0, 1, 2,3)
284+
285+
func printit() {
286+
print("QConformer \(x.3)")
287+
}
288+
}
289+
290+
struct P4Conformer : P4 {
291+
var q = QConformer()
292+
293+
var t : QConformer {
294+
get {
295+
return q
296+
}
297+
}
298+
}
299+
300+
func test13(_ p: any P4) {
301+
print("test13")
302+
p.t.printit()
303+
}
304+
219305
@main
220306
struct Main {
221307
static func main() {
@@ -262,7 +348,7 @@ struct Main {
262348
// OUTPUT: deinit called
263349
// OUTPUT: cast failed
264350
// OUTPUT-NOT: deinit called
265-
test5(GenericStructWithClass<Int>())
351+
test5(GenericStructWithClass<Int>())
266352
// OUTPUT: test any as? MyStruct
267353
// OUTPUT: cast failed
268354
// OUTPUT: deinit called
@@ -289,5 +375,53 @@ struct Main {
289375
// OUTPUT: a LargeMyStruct 5
290376
// OUTPUT: deinit called
291377
// OUTPUT-NOT: deinit called
378+
test8(SubClass())
379+
// OUTPUT: success
380+
// OUTPUT: SubClass.foo
381+
// OUTPUT: BaseClass.deinit
382+
// OUTPUT-NOT: deinit
383+
test8(BaseClass())
384+
// OUTPUT: test any as? SubClass
385+
// OUTPUT: cast failed
386+
// OUTPUT: BaseClass.deinit
387+
// OUTPUT-NOT: deinit
388+
test9(SubClass())
389+
// OUTPUT: test any as? BaseClass
390+
// OUTPUT: success
391+
// OUTPUT: SubClass.foo
392+
// OUTPUT: BaseClass.deinit
393+
// OUTPUT-NOT: deinit
394+
test9(BaseClass())
395+
// OUTPUT: test any as? BaseClass
396+
// OUTPUT: success
397+
// OUTPUT: BaseClass.foo
398+
// OUTPUT: BaseClass.deinit
399+
// OUTPUT-NOT: deinit
400+
test9(C())
401+
// OUTPUT: test any as? BaseClass
402+
// OUTPUT: cast failed
403+
// OUTPUT-NOT: deinit
404+
test10(BaseClass())
405+
// OUTPUT: test any as! BaseClass
406+
// OUTPUT: BaseClass.foo
407+
// OUTPUT: BaseClass.deinit
408+
// OUTPUT-NOT: deinit
409+
test10(SubClass())
410+
// OUTPUT: test any as! BaseClass
411+
// OUTPUT: SubClass.foo
412+
// OUTPUT: BaseClass.deinit
413+
// OUTPUT-NOT: deinit
414+
test11(SubClass())
415+
// OUTPUT: test any as! SubClass
416+
// OUTPUT: SubClass.foo
417+
// OUTPUT: BaseClass.deinit
418+
// OUTPUT-NOT: deinit
419+
test12((0, 1, 2, 3))
420+
// OUTPUT: test any as! (Int, Int, Int, Int)
421+
// OUTPUT: success
422+
// OUTPUT: tuple: 0
423+
test13(P4Conformer())
424+
// OUTPUT: test13
425+
// OUTPUT: QConformer 3
292426
}
293427
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
// RUN: %empty-directory(%t)
2+
3+
// RUN: %target-clang -x c -c %S/Inputs/unbuffered-putchar.c -o %t/unbuffered-putchar.o
4+
5+
// RUN: %target-build-swift -DT1 -enable-experimental-feature Embedded \
6+
// RUN: -parse-as-library -Xlinker %t/unbuffered-putchar.o \
7+
// RUN: -enable-experimental-feature EmbeddedExistentials \
8+
// RUN: -wmo -runtime-compatibility-version none %s -o %t/t1.out
9+
// RUN: not --crash %t/t1.out 2>&1 | %FileCheck %s --check-prefix=CHECK-T1
10+
11+
// RUN: %target-build-swift -DT2 -enable-experimental-feature Embedded \
12+
// RUN: -parse-as-library -Xlinker %t/unbuffered-putchar.o \
13+
// RUN: -enable-experimental-feature EmbeddedExistentials \
14+
// RUN: -wmo -runtime-compatibility-version none %s -o %t/t2.out
15+
// RUN: not --crash %t/t2.out 2>&1 | %FileCheck %s --check-prefix=CHECK-T2
16+
17+
// RUN: %target-build-swift -DT3 -enable-experimental-feature Embedded \
18+
// RUN: -parse-as-library -Xlinker %t/unbuffered-putchar.o \
19+
// RUN: -enable-experimental-feature EmbeddedExistentials \
20+
// RUN: -wmo -runtime-compatibility-version none %s -o %t/t3.out
21+
// RUN: not --crash %t/t3.out 2>&1 | %FileCheck %s --check-prefix=CHECK-T3
22+
23+
// RUN: %target-build-swift -DT4 -enable-experimental-feature Embedded \
24+
// RUN: -parse-as-library -Xlinker %t/unbuffered-putchar.o \
25+
// RUN: -enable-experimental-feature EmbeddedExistentials \
26+
// RUN: -wmo -runtime-compatibility-version none %s -o %t/t4.out
27+
// RUN: not --crash %t/t4.out 2>&1 | %FileCheck %s --check-prefix=CHECK-T4
28+
29+
// REQUIRES: swift_in_compiler
30+
// REQUIRES: executable_test
31+
// REQUIRES: optimized_stdlib
32+
// REQUIRES: swift_feature_Embedded
33+
// REQUIRES: swift_feature_EmbeddedExistentials
34+
35+
// REQUIRES: OS=macosx
36+
37+
class CP {
38+
func foo() { print("foo called") }
39+
deinit {
40+
print("deinit called")
41+
}
42+
}
43+
44+
class C : CP {
45+
override func foo() { print("C.foo called") }
46+
}
47+
48+
class CP2 {
49+
func foo() { print("CP2.foo called") }
50+
deinit {
51+
print("deinit called")
52+
}
53+
}
54+
55+
struct StructWithClass {
56+
var c = C()
57+
}
58+
59+
60+
struct LargeStructWithClass {
61+
var c = C()
62+
var t = (0, 1, 2, 3, 4, 5, 6, 7, 8)
63+
func foo() { c.foo() }
64+
}
65+
66+
struct LargetMyStruct {
67+
var l = LargeStructWithClass()
68+
}
69+
70+
func test1(_ p: any Any) {
71+
print("test any as! CP")
72+
let c = p as! CP
73+
c.foo()
74+
}
75+
76+
func test2(_ p: any Any) {
77+
print("test any as! LargeStructWithClass")
78+
let c = p as! LargeStructWithClass
79+
c.foo()
80+
}
81+
82+
@main
83+
struct Main {
84+
static func main() {
85+
#if T1
86+
test1(StructWithClass())
87+
// CHECK-T1: test any as! CP
88+
// CHECK-T1: failed cast
89+
#endif
90+
91+
#if T2
92+
test1(CP2())
93+
// CHECK-T2: test any as! CP
94+
// CHECK-T2: failed cast
95+
#endif
96+
97+
#if T3
98+
test2(StructWithClass())
99+
// CHECK-T3: test any as! LargeStructWithClass
100+
// CHECK-T3: failed cast
101+
#endif
102+
103+
#if T4
104+
test2(CP2())
105+
// CHECK-T4: test any as! LargeStructWithClass
106+
// CHECK-T4: failed cast
107+
#endif
108+
}
109+
}

0 commit comments

Comments
 (0)