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
This commit is contained in:
Arnold Schwaighofer
2025-12-01 08:27:43 -08:00
committed by GitHub
4 changed files with 250 additions and 3 deletions

View File

@@ -94,6 +94,11 @@ private struct FunctionChecker {
for conf in ie.conformances {
try checkConformance(conf, location: ie.location)
}
} else if instruction is OpenExistentialAddrInst {
// okay in embedded with exitentials
} else {
// not supported even in embedded with exitentials
throw Diagnostic(.embedded_swift_existential_type, instruction.operands[0].value.type, at: instruction.location)
}
case let aeb as AllocExistentialBoxInst:

View File

@@ -1051,8 +1051,7 @@ func isCastSupportedInEmbeddedSwift(from sourceType: Type,
return false
}
// Tuple?
if !destType.isStruct && !destType.isClass && !destType.isEnum {
if !destType.isStruct && !destType.isClass && !destType.isEnum && !destType.isTuple {
return false
}

View File

@@ -216,6 +216,92 @@ func test7(_ p: any Any) {
c.a()
}
class BaseClass {
func foo() { print("BaseClass.foo") }
deinit {
print("BaseClass.deinit")
}
}
class SubClass : BaseClass {
override func foo() { print("SubClass.foo") }
}
func test8(_ p: any Any) {
print("test any as? SubClass")
if let c = p as? SubClass {
print("success")
c.foo()
} else {
print("cast failed")
}
}
func test9(_ p: any Any) {
print("test any as? BaseClass")
if let c = p as? BaseClass {
print("success")
c.foo()
} else {
print("cast failed")
}
}
func test10(_ p: any Any) {
print("test any as! BaseClass")
let c = p as! BaseClass
c.foo()
}
func test11(_ p: any Any) {
print("test any as! SubClass")
let c = p as! SubClass
c.foo()
}
func test12(_ p: any Any) {
print("test any as! (Int, Int, Int, Int)")
if let c = p as? (Int, Int, Int, Int) {
print("success")
print("tuple: \(c.0)")
} else {
print("cast failed")
}
}
protocol Q {
func printit()
}
protocol P4<T> {
associatedtype T: Q
var t: T { get }
}
struct QConformer : Q {
var x = (0, 1, 2,3)
func printit() {
print("QConformer \(x.3)")
}
}
struct P4Conformer : P4 {
var q = QConformer()
var t : QConformer {
get {
return q
}
}
}
func test13(_ p: any P4) {
print("test13")
p.t.printit()
}
@main
struct Main {
static func main() {
@@ -262,7 +348,7 @@ struct Main {
// OUTPUT: deinit called
// OUTPUT: cast failed
// OUTPUT-NOT: deinit called
test5(GenericStructWithClass<Int>())
test5(GenericStructWithClass<Int>())
// OUTPUT: test any as? MyStruct
// OUTPUT: cast failed
// OUTPUT: deinit called
@@ -289,5 +375,53 @@ struct Main {
// OUTPUT: a LargeMyStruct 5
// OUTPUT: deinit called
// OUTPUT-NOT: deinit called
test8(SubClass())
// OUTPUT: success
// OUTPUT: SubClass.foo
// OUTPUT: BaseClass.deinit
// OUTPUT-NOT: deinit
test8(BaseClass())
// OUTPUT: test any as? SubClass
// OUTPUT: cast failed
// OUTPUT: BaseClass.deinit
// OUTPUT-NOT: deinit
test9(SubClass())
// OUTPUT: test any as? BaseClass
// OUTPUT: success
// OUTPUT: SubClass.foo
// OUTPUT: BaseClass.deinit
// OUTPUT-NOT: deinit
test9(BaseClass())
// OUTPUT: test any as? BaseClass
// OUTPUT: success
// OUTPUT: BaseClass.foo
// OUTPUT: BaseClass.deinit
// OUTPUT-NOT: deinit
test9(C())
// OUTPUT: test any as? BaseClass
// OUTPUT: cast failed
// OUTPUT-NOT: deinit
test10(BaseClass())
// OUTPUT: test any as! BaseClass
// OUTPUT: BaseClass.foo
// OUTPUT: BaseClass.deinit
// OUTPUT-NOT: deinit
test10(SubClass())
// OUTPUT: test any as! BaseClass
// OUTPUT: SubClass.foo
// OUTPUT: BaseClass.deinit
// OUTPUT-NOT: deinit
test11(SubClass())
// OUTPUT: test any as! SubClass
// OUTPUT: SubClass.foo
// OUTPUT: BaseClass.deinit
// OUTPUT-NOT: deinit
test12((0, 1, 2, 3))
// OUTPUT: test any as! (Int, Int, Int, Int)
// OUTPUT: success
// OUTPUT: tuple: 0
test13(P4Conformer())
// OUTPUT: test13
// OUTPUT: QConformer 3
}
}

View File

@@ -0,0 +1,109 @@
// RUN: %empty-directory(%t)
// RUN: %target-clang -x c -c %S/Inputs/unbuffered-putchar.c -o %t/unbuffered-putchar.o
// RUN: %target-build-swift -DT1 -enable-experimental-feature Embedded \
// RUN: -parse-as-library -Xlinker %t/unbuffered-putchar.o \
// RUN: -enable-experimental-feature EmbeddedExistentials \
// RUN: -wmo -runtime-compatibility-version none %s -o %t/t1.out
// RUN: not --crash %t/t1.out 2>&1 | %FileCheck %s --check-prefix=CHECK-T1
// RUN: %target-build-swift -DT2 -enable-experimental-feature Embedded \
// RUN: -parse-as-library -Xlinker %t/unbuffered-putchar.o \
// RUN: -enable-experimental-feature EmbeddedExistentials \
// RUN: -wmo -runtime-compatibility-version none %s -o %t/t2.out
// RUN: not --crash %t/t2.out 2>&1 | %FileCheck %s --check-prefix=CHECK-T2
// RUN: %target-build-swift -DT3 -enable-experimental-feature Embedded \
// RUN: -parse-as-library -Xlinker %t/unbuffered-putchar.o \
// RUN: -enable-experimental-feature EmbeddedExistentials \
// RUN: -wmo -runtime-compatibility-version none %s -o %t/t3.out
// RUN: not --crash %t/t3.out 2>&1 | %FileCheck %s --check-prefix=CHECK-T3
// RUN: %target-build-swift -DT4 -enable-experimental-feature Embedded \
// RUN: -parse-as-library -Xlinker %t/unbuffered-putchar.o \
// RUN: -enable-experimental-feature EmbeddedExistentials \
// RUN: -wmo -runtime-compatibility-version none %s -o %t/t4.out
// RUN: not --crash %t/t4.out 2>&1 | %FileCheck %s --check-prefix=CHECK-T4
// REQUIRES: swift_in_compiler
// REQUIRES: executable_test
// REQUIRES: optimized_stdlib
// REQUIRES: swift_feature_Embedded
// REQUIRES: swift_feature_EmbeddedExistentials
// REQUIRES: OS=macosx
class CP {
func foo() { print("foo called") }
deinit {
print("deinit called")
}
}
class C : CP {
override func foo() { print("C.foo called") }
}
class CP2 {
func foo() { print("CP2.foo called") }
deinit {
print("deinit called")
}
}
struct StructWithClass {
var c = C()
}
struct LargeStructWithClass {
var c = C()
var t = (0, 1, 2, 3, 4, 5, 6, 7, 8)
func foo() { c.foo() }
}
struct LargetMyStruct {
var l = LargeStructWithClass()
}
func test1(_ p: any Any) {
print("test any as! CP")
let c = p as! CP
c.foo()
}
func test2(_ p: any Any) {
print("test any as! LargeStructWithClass")
let c = p as! LargeStructWithClass
c.foo()
}
@main
struct Main {
static func main() {
#if T1
test1(StructWithClass())
// CHECK-T1: test any as! CP
// CHECK-T1: failed cast
#endif
#if T2
test1(CP2())
// CHECK-T2: test any as! CP
// CHECK-T2: failed cast
#endif
#if T3
test2(StructWithClass())
// CHECK-T3: test any as! LargeStructWithClass
// CHECK-T3: failed cast
#endif
#if T4
test2(CP2())
// CHECK-T4: test any as! LargeStructWithClass
// CHECK-T4: failed cast
#endif
}
}