diff --git a/SwiftCompilerSources/Sources/AST/Declarations.swift b/SwiftCompilerSources/Sources/AST/Declarations.swift index 2041d32fd22de..780ed1aa23314 100644 --- a/SwiftCompilerSources/Sources/AST/Declarations.swift +++ b/SwiftCompilerSources/Sources/AST/Declarations.swift @@ -76,6 +76,7 @@ final public class ClassDecl: NominalTypeDecl { final public class ProtocolDecl: NominalTypeDecl { public var requiresClass: Bool { bridged.ProtocolDecl_requiresClass() } + public var isMarkerProtocol: Bool { bridged.ProtocolDecl_isMarkerProtocol() } } final public class BuiltinTupleDecl: NominalTypeDecl {} diff --git a/SwiftCompilerSources/Sources/Optimizer/ModulePasses/EmbeddedSwiftDiagnostics.swift b/SwiftCompilerSources/Sources/Optimizer/ModulePasses/EmbeddedSwiftDiagnostics.swift index ed1432bb01359..48870708273fa 100644 --- a/SwiftCompilerSources/Sources/Optimizer/ModulePasses/EmbeddedSwiftDiagnostics.swift +++ b/SwiftCompilerSources/Sources/Optimizer/ModulePasses/EmbeddedSwiftDiagnostics.swift @@ -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: diff --git a/SwiftCompilerSources/Sources/Optimizer/ModulePasses/MandatoryPerformanceOptimizations.swift b/SwiftCompilerSources/Sources/Optimizer/ModulePasses/MandatoryPerformanceOptimizations.swift index 11616d84335bb..b62f6c5d8c180 100644 --- a/SwiftCompilerSources/Sources/Optimizer/ModulePasses/MandatoryPerformanceOptimizations.swift +++ b/SwiftCompilerSources/Sources/Optimizer/ModulePasses/MandatoryPerformanceOptimizations.swift @@ -143,6 +143,14 @@ private func optimize(function: Function, _ context: FunctionPassContext, _ modu } } + case let initExAddr as InitExistentialAddrInst: + if context.options.enableEmbeddedSwift { + for c in initExAddr.conformances where c.isConcrete && !c.protocol.isMarkerProtocol { + specializeWitnessTable(for: c, moduleContext) + worklist.addWitnessMethods(of: c, moduleContext) + } + } + case let bi as BuiltinInst: switch bi.id { case .BuildOrdinaryTaskExecutorRef, diff --git a/SwiftCompilerSources/Sources/Optimizer/Utilities/GenericSpecialization.swift b/SwiftCompilerSources/Sources/Optimizer/Utilities/GenericSpecialization.swift index ef8dbc679afc8..d402190c05a4a 100644 --- a/SwiftCompilerSources/Sources/Optimizer/Utilities/GenericSpecialization.swift +++ b/SwiftCompilerSources/Sources/Optimizer/Utilities/GenericSpecialization.swift @@ -148,7 +148,7 @@ func specializeWitnessTable(for conformance: Conformance, _ context: ModulePassC guard !methodSubs.conformances.contains(where: {!$0.isValid}), context.loadFunction(function: origMethod, loadCalleesRecursively: true), let specializedMethod = context.specialize(function: origMethod, for: methodSubs, - convertIndirectToDirect: true, isMandatory: true) + convertIndirectToDirect: false, isMandatory: true) else { return origEntry } @@ -215,7 +215,7 @@ private func specializeDefaultMethods(for conformance: Conformance, guard !methodSubs.conformances.contains(where: {!$0.isValid}), context.loadFunction(function: origMethod, loadCalleesRecursively: true), let specializedMethod = context.specialize(function: origMethod, for: methodSubs, - convertIndirectToDirect: true, isMandatory: true) + convertIndirectToDirect: false, isMandatory: true) else { return origEntry } diff --git a/SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift b/SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift index 216a4a3d33d43..64b10f5928844 100644 --- a/SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift +++ b/SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift @@ -1010,8 +1010,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 } diff --git a/SwiftCompilerSources/Sources/SIL/Instruction.swift b/SwiftCompilerSources/Sources/SIL/Instruction.swift index 8057aeb6d7266..e7484232c58c7 100644 --- a/SwiftCompilerSources/Sources/SIL/Instruction.swift +++ b/SwiftCompilerSources/Sources/SIL/Instruction.swift @@ -883,6 +883,10 @@ class InitExistentialAddrInst : SingleValueInstruction, UnaryInstruction { public var conformances: ConformanceArray { ConformanceArray(bridged: bridged.InitExistentialAddrInst_getConformances()) } + + public var formalConcreteType: CanonicalType { + CanonicalType(bridged: bridged.InitExistentialAddrInst_getFormalConcreteType()) + } } final public diff --git a/include/swift/AST/ASTBridging.h b/include/swift/AST/ASTBridging.h index e529082f034a8..8a692d52aa65a 100644 --- a/include/swift/AST/ASTBridging.h +++ b/include/swift/AST/ASTBridging.h @@ -335,6 +335,7 @@ struct BridgedDeclObj { SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedASTType Class_getSuperclass() const; SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedDeclObj Class_getDestructor() const; BRIDGED_INLINE bool ProtocolDecl_requiresClass() const; + BRIDGED_INLINE bool ProtocolDecl_isMarkerProtocol() const; BRIDGED_INLINE bool AbstractFunction_isOverridden() const; BRIDGED_INLINE bool Destructor_isIsolated() const; BRIDGED_INLINE bool EnumElementDecl_hasAssociatedValues() const; diff --git a/include/swift/AST/ASTBridgingImpl.h b/include/swift/AST/ASTBridgingImpl.h index aa2bf1dbbd9fd..d892c89e2388b 100644 --- a/include/swift/AST/ASTBridgingImpl.h +++ b/include/swift/AST/ASTBridgingImpl.h @@ -222,6 +222,10 @@ bool BridgedDeclObj::ProtocolDecl_requiresClass() const { return getAs()->requiresClass(); } +bool BridgedDeclObj::ProtocolDecl_isMarkerProtocol() const { + return getAs()->isMarkerProtocol(); +} + bool BridgedDeclObj::AbstractFunction_isOverridden() const { return getAs()->isOverridden(); } diff --git a/include/swift/SIL/SILBridging.h b/include/swift/SIL/SILBridging.h index a3445fe32f6cb..f15ae2db9f79d 100644 --- a/include/swift/SIL/SILBridging.h +++ b/include/swift/SIL/SILBridging.h @@ -798,6 +798,7 @@ struct BridgedInstruction { SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedConformanceArray InitExistentialRefInst_getConformances() const; SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedCanType InitExistentialRefInst_getFormalConcreteType() const; SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedConformanceArray InitExistentialAddrInst_getConformances() const; + SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedCanType InitExistentialAddrInst_getFormalConcreteType() const; BRIDGED_INLINE bool OpenExistentialAddr_isImmutable() const; SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedGlobalVar GlobalAccessInst_getGlobal() const; SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedGlobalVar AllocGlobalInst_getGlobal() const; diff --git a/include/swift/SIL/SILBridgingImpl.h b/include/swift/SIL/SILBridgingImpl.h index 750c53e38b45f..523aba833fc0a 100644 --- a/include/swift/SIL/SILBridgingImpl.h +++ b/include/swift/SIL/SILBridgingImpl.h @@ -1252,6 +1252,11 @@ BridgedCanType BridgedInstruction::InitExistentialRefInst_getFormalConcreteType( BridgedConformanceArray BridgedInstruction::InitExistentialAddrInst_getConformances() const { return {getAs()->getConformances()}; } + +BridgedCanType BridgedInstruction::InitExistentialAddrInst_getFormalConcreteType() const { + return getAs()->getFormalConcreteType(); +} + bool BridgedInstruction::OpenExistentialAddr_isImmutable() const { switch (getAs()->getAccessKind()) { case swift::OpenedExistentialAccess::Immutable: return true; diff --git a/include/swift/SILOptimizer/Utils/Generics.h b/include/swift/SILOptimizer/Utils/Generics.h index 8b320ce92da27..11c914d46c8d6 100644 --- a/include/swift/SILOptimizer/Utils/Generics.h +++ b/include/swift/SILOptimizer/Utils/Generics.h @@ -216,7 +216,9 @@ class ReabstractionInfo { ReabstractionInfo(CanSILFunctionType substitutedType, SILDeclRef methodDecl, + bool convertIndirectToDirect, SILModule &M) : + ConvertIndirectToDirect(convertIndirectToDirect), SubstitutedType(substitutedType), methodDecl(methodDecl), M(&M), isWholeModule(M.isWholeModule()) {} diff --git a/lib/IRGen/GenProto.cpp b/lib/IRGen/GenProto.cpp index 4824098395ade..7be207a615d2a 100644 --- a/lib/IRGen/GenProto.cpp +++ b/lib/IRGen/GenProto.cpp @@ -1751,6 +1751,10 @@ class AccessorConformanceInfo : public ConformanceInfo { #endif auto typeWitness = Conformance.getTypeWitness(assocType); + if (langOpts.hasFeature(Feature::EmbeddedExistentials) && + SILWT->isSpecialized()) { + typeWitness = entry.getAssociatedTypeWitness().Witness; + } if (IGM.Context.LangOpts.hasFeature(Feature::EmbeddedExistentials)) { // In Embedded Swift associated type witness point to the metadata. diff --git a/lib/SILOptimizer/Utils/Generics.cpp b/lib/SILOptimizer/Utils/Generics.cpp index 9ef5e942708cf..b12bf8c36a0b8 100644 --- a/lib/SILOptimizer/Utils/Generics.cpp +++ b/lib/SILOptimizer/Utils/Generics.cpp @@ -2413,7 +2413,8 @@ bool swift::specializeClassMethodInst(ClassMethodInst *cm) { SILType substitutedType = funcTy.substGenericArgs(m, subs, TypeExpansionContext::minimal()); - ReabstractionInfo reInfo(substitutedType.getAs(), cm->getMember(), m); + ReabstractionInfo reInfo(substitutedType.getAs(), cm->getMember(), + /*convertIndirectToDirect=*/ true, m); reInfo.createSubstitutedAndSpecializedTypes(); CanSILFunctionType finalFuncTy = reInfo.getSpecializedType(); SILType finalSILTy = SILType::getPrimitiveObjectType(finalFuncTy); @@ -2465,7 +2466,8 @@ bool swift::specializeWitnessMethodInst(WitnessMethodInst *wm) { SILType substitutedType = funcTy.substGenericArgs(m, subs, TypeExpansionContext::minimal()); - ReabstractionInfo reInfo(substitutedType.getAs(), wm->getMember(), m); + ReabstractionInfo reInfo(substitutedType.getAs(), wm->getMember(), + /*convertIndirectToDirect=*/ false, m); reInfo.createSubstitutedAndSpecializedTypes(); CanSILFunctionType finalFuncTy = reInfo.getSpecializedType(); SILType finalSILTy = SILType::getPrimitiveObjectType(finalFuncTy); diff --git a/test/embedded/existential.swift b/test/embedded/existential.swift index 004e29c987136..e1f6cc2314668 100644 --- a/test/embedded/existential.swift +++ b/test/embedded/existential.swift @@ -216,6 +216,133 @@ 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 { + 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() +} + +struct GenericConformer : ValuePrinter { + var t: T? + var l = (0, 1, 2, 3) + + init(_ t: T) { self.t = t } + + func printValue() { + print("GenericConformer \(l.0) \(l.1) \(l.2) \(l.3)") + } + + mutating func mutate() { + l = (4, 5, 6, 7) + } +} + +struct GenericConformerWithAssoc : WithAssoc { + var g : GenericConformer + + init( _ g: T) { + self.g = GenericConformer(g) + } + + func a() -> GenericConformer { + return g + } +} + +func test14(_ p: any ValuePrinter) { + print("test any ValuePrinter") + p.printValue() + var p2 = p + p2.mutate() + p2.printValue() +} + +func test15(_ p: any WithAssoc) { + print("test any WithAssoc") + let l = p.a() + l.printValue() +} + @main struct Main { static func main() { @@ -262,7 +389,7 @@ struct Main { // OUTPUT: deinit called // OUTPUT: cast failed // OUTPUT-NOT: deinit called - test5(GenericStructWithClass()) + test5(GenericStructWithClass()) // OUTPUT: test any as? MyStruct // OUTPUT: cast failed // OUTPUT: deinit called @@ -289,5 +416,61 @@ 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 +// OUTPUT-NOT: deinit + test14(GenericConformer(1)) +// OUTPUT: test any ValuePrinter +// OUTPUT: GenericConformer 0 1 2 3 +// OUTPUT: GenericConformer 4 5 6 7 + test15(GenericConformerWithAssoc(1)) +// OUTPUT: test any WithAssoc +// OUTPUT: GenericConformer 0 1 2 3 } } diff --git a/test/embedded/existential_cast_fails.swift b/test/embedded/existential_cast_fails.swift new file mode 100644 index 0000000000000..f8f5a8ff2990b --- /dev/null +++ b/test/embedded/existential_cast_fails.swift @@ -0,0 +1,107 @@ +// 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 + +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 + } +} diff --git a/test/embedded/general-existentials1.swift b/test/embedded/general-existentials1.swift new file mode 100644 index 0000000000000..fb62a0aa9edcc --- /dev/null +++ b/test/embedded/general-existentials1.swift @@ -0,0 +1,298 @@ +// RUN: %target-run-simple-swift(-enable-experimental-feature Embedded -enable-experimental-feature EmbeddedExistentials -parse-as-library -wmo) | %FileCheck %s +// RUN: %target-run-simple-swift(-enable-experimental-feature Embedded -enable-experimental-feature EmbeddedExistentials -parse-as-library -wmo -O) | %FileCheck %s +// RUN: %target-run-simple-swift(-enable-experimental-feature Embedded -enable-experimental-feature EmbeddedExistentials -parse-as-library -wmo -Osize) | %FileCheck %s + +// REQUIRES: swift_in_compiler +// REQUIRES: executable_test +// REQUIRES: optimized_stdlib +// REQUIRES: swift_feature_Embedded +// REQUIRES: swift_feature_EmbeddedExistentials + +protocol P { + func foo() + func bar() + func predicate() -> Bool +} + +extension P { + public func predicate() -> Bool { true } +} + +struct MyStruct : P { + var i: Int + + func foo() { print("MyStruct.foo: \(i)") } + func bar() { print("MyStruct.bar: \(i)") } +} + +struct LargeStruct : P { + var a: Int + var b: Int + var c: Int + var d: Int + + func foo() { print("LargeStruct.foo: \(a), \(b), \(c), \(d)") } + func bar() { print("LargeStruct.bar: \(a), \(b), \(c), \(d)") } +} + +struct GenericStruct : P { + var t: T + + func foo() { print("GenericStruct.foo: \(t)") } + func bar() { print("GenericStruct.bar: \(t)") } +} + +func test(existential: any P) { + existential.foo() + existential.bar() +} + +public protocol ProtoWithAssocType { + associatedtype T + func foo(t: T) +} + +final public class GenClass: ProtoWithAssocType { + public func foo(t: T) { + print(t) + } +} + +public func createExWithAssocType() -> any ProtoWithAssocType { + return GenClass() +} + +public func callExWithAssocType(_ p: any ProtoWithAssocType) { + p.foo(t: 27) +} + +public protocol Q { + func bar() +} + +public protocol ProtoWithAssocConf { + associatedtype A: Q + func foo() -> A +} + +public class GenClass2: Q { + final var t: T + + init(t : T) { self.t = t } + + public func bar() { + print("bar") + } +} + +public class DerivedFromGenClass2: GenClass2 { + init() { super.init(t: 42) } + + public override func bar() { + print("derived-bar") + } +} + +final public class GenClass3: ProtoWithAssocConf { + public func foo() -> GenClass2 { + print("foo") + return GenClass2(t: 27) + } +} + +final public class OtherClass: ProtoWithAssocConf { + public func foo() -> GenClass2 { + print("other-foo") + return DerivedFromGenClass2() + } +} + + +public func createExWithAssocConf() -> any ProtoWithAssocConf { + return GenClass3() +} + +public func callExWithAssocConf(_ p: any ProtoWithAssocConf) { + let x = p.foo() + x.bar() +} + +public class Base: P { + public func foo() { print("Base.foo()") } + public func bar() { print("Base.bar()") } +} + +public class Derived1: Base { + public override func foo() { print("Derived1.foo()") } + public override func bar() { print("Derived1.bar()") } +} + +public class Derived2: Base { + public override func foo() { print("Derived2.foo()") } + public override func bar() { print("Derived2.bar()") } +} + +public func takes_p1(_ p: P1) { + p.normal() +} + +public protocol P1 { + func normal() +} + +public protocol P2 { + func foo() +} + +public class ConditionalConformanceBase { + final var a: A + + init(a: A) { self.a = a } +} + +extension ConditionalConformanceBase: P1 where A: P2 { + public func normal() { + a.foo() + } +} + +public class ConditionalConformanceDerived: ConditionalConformanceBase { + init(t: T) { super.init(a: t) } +} + + +public func testConditionalConformance(t: T) { + takes_p1(ConditionalConformanceDerived(t: t)) +} + + +struct S: P2 { + var i: Int + + func foo() { + print(i) + } +} + +protocol Q3 { + func bar() +} + +protocol P3 { + associatedtype T: Q3 + + var t: T { get } + + func foo() +} + +extension P3 { + func foo() { + t.bar() + } +} + +struct C3: P3 { + var t: T + + + init(t: T) { self.t = t } +} + +struct S3: Q3 { + var x: I + + func bar() { + print(x) + } +} + +@inline(never) +func testP3() -> any P3 { + return C3(t: S3(x: 102)) +} + +protocol P4 { + associatedtype T: Q + + var t: T { get } + + func foo() +} + +extension P4 { + func foo() { + t.bar() + } +} + +struct C4: P4 { + var t: T + + + init(t: T) { self.t = t } +} + +struct K4: Q { + var x: I + + init(x: I) { self.x = x } + + func bar() { + print(x) + } +} + +@inline(never) +func testP4() -> any P4 { + return C4(t: K4(x: 437)) +} + +@main +struct Main { + static func main() { + test(existential: MyStruct(i: 27)) + // CHECK: MyStruct.foo: 27 + // CHECK: MyStruct.bar: 27 + + test(existential: LargeStruct(a: 10, b: 11, c: 12, d: 13)) + // CHECK: LargeStruct.foo: 10, 11, 12, 13 + // CHECK: LargeStruct.bar: 10, 11, 12, 13 + + test(existential: GenericStruct(t: 28)) + // CHECK: GenericStruct.foo: 28 + // CHECK: GenericStruct.bar: 28 + + callExWithAssocType(createExWithAssocType()) + // CHECK: 27 + + callExWithAssocConf(createExWithAssocConf()) + // CHECK: foo + // CHECK: bar + + callExWithAssocConf(OtherClass()) + // CHECK: other-foo + // CHECK: derived-bar + + test(existential: Derived1()) + // CHECK: Derived1.foo() + // CHECK: Derived1.bar() + + + test(existential: Derived2()) + // CHECK: Derived2.foo() + // CHECK: Derived2.bar() + + + testConditionalConformance(t: S(i: 27)) + // CHECK: 27 + + testP3().foo() + // CHECK: 102 + + testP4().foo() + // CHECK: 437 + } +} + +