// RUN: %empty-directory(%t) // RUN: %target-swift-frontend -emit-module -enable-library-evolution -emit-module-path=%t/resilient_protocol.swiftmodule -module-name=resilient_protocol %S/../Inputs/resilient_protocol.swift // RUN: %target-swift-frontend -I %t -emit-ir -Xllvm -sil-disable-pass=Simplification -enable-library-evolution %s | %FileCheck %s -DINT=i%target-ptrsize // RUN: %target-swift-frontend -I %t -emit-ir -Xllvm -sil-disable-pass=Simplification -enable-library-evolution -O %s sil_stage canonical import Builtin import Swift import SwiftShims import resilient_protocol // Protocol conformance descriptor for ResilientConformingType : OtherResilientProtocol // CHECK: @"$s19protocol_resilience23ResilientConformingTypeV010resilient_A005OtherC8ProtocolAAMc" = // CHECK-SAME: i32 131072, // -- number of witness table entries // CHECK-SAME: i16 0, // -- size of private area + 'requires instantiation' bit // CHECK-SAME: i16 1, // -- instantiator function // CHECK-SAME: i32 0 // CHECK-SAME: } // Protocol descriptor for ResilientProtocol // CHECK: [[RESILIENT_PROTOCOL_NAME:@.*]] = private constant [18 x i8] c"ResilientProtocol\00 // CHECK: [[ASSOCIATED_TYPES_T:@.*]] = private constant [2 x i8] c"T\00" // CHECK: @"$s19protocol_resilience17ResilientProtocolMp" = {{(dllexport )?}}{{(protected )?}}constant // CHECK-SAME: i32 196675, // CHECK-SAME: @"$s19protocol_resilienceMXM" // CHECK-SAME: [[RESILIENT_PROTOCOL_NAME]] // CHECK-SAME: i32 1, // CHECK-SAME: i32 8, // CHECK-SAME: [[ASSOCIATED_TYPES_T]] // Requirement signature // CHECK-SAME: i32 128, // CHECK-SAME: @"symbolic 1T_____Qz 19protocol_resilience17ResilientProtocolP" // CHECK-SAME: @"$s19protocol_resilience17ResilientProtocolMp" // Protocol requirements // CHECK-SAME: %swift.protocol_requirement { i32 {{(1797193736)|(8)}}, i32 0 }, // CHECK-SAME: %swift.protocol_requirement { i32 {{(-1947336697)|(7)}}, i32 0 }, // CHECK-SAME: %swift.protocol_requirement { i32 {{(-48627695)|(17)}}, i32 0 }, // CHECK-SAME: %swift.protocol_requirement { i32 {{(-1745420271)|(17)}}, i32 0 }, // CHECK-SAME: %swift.protocol_requirement { i32 {{(-544407535)|(17)}}, // CHECK-SAME: {{(i32( | trunc \(i64 )sub \()?}}[[INT]] ptrtoint (ptr @defaultC to [[INT]]) // CHECK-SAME: }, // CHECK-SAME: %swift.protocol_requirement { i32 {{(1717370897)|(17)}}, // CHECK-SAME: {{(i32( | trunc \(i64 )sub \()?}}[[INT]] ptrtoint (ptr @defaultD to [[INT]]) // CHECK-SAME: }, // CHECK-SAME: %swift.protocol_requirement { i32 {{(297926657)|(1)}}, // CHECK-SAME: {{(i32( | trunc \(i64 )sub \()?}}[[INT]] ptrtoint (ptr @defaultE to [[INT]]) // CHECK-SAME: }, // CHECK-SAME: %swift.protocol_requirement { i32 {{(351797249)|(1)}}, // CHECK-SAME: {{(i32( | trunc \(i64 )sub \()?}}[[INT]] ptrtoint (ptr @defaultF to [[INT]]) // CHECK-SAME: } // CHECK-SAME: } public protocol ResilientProtocol { associatedtype T : OtherResilientProtocol func noDefaultA() func noDefaultB() func defaultC() func defaultD() static func defaultE() static func defaultF() } // Protocol is not public -- doesn't need default witness table // CHECK: @"$s19protocol_resilience16InternalProtocolMp" = hidden constant // CHECK-SAME: i32 65603, // CHECK-SAME: @"$s19protocol_resilienceMXM" // CHECK-SAME: i32 0, // CHECK-SAME: i32 1, // CHECK-SAME: i32 0, // CHECK-SAME: } protocol InternalProtocol { func f() } // No generic witness table pattern for ConformsWithRequirements : ProtocolWithRequirements; it's all resilient // CHECK-NOT: @"$s19protocol_resilience24ConformsWithRequirementsV010resilient_A008ProtocoldE0AAWp" = // No witness table pattern for conformance with resilient associated type // CHECK-NOT: @"$s19protocol_resilience26ConformsWithResilientAssocVAA03HaseF0AAWp" = {{(protected )?}}internal // ConformsWithRequirements protocol conformance descriptor // CHECK: "$s19protocol_resilience24ConformsWithRequirementsV010resilient_A008ProtocoldE0AAMc" = hidden constant { // -- flags // CHECK-SAME: i32 196608, // CHECK-SAME: i32 3, // -- type metadata for associated type // CHECK-SAME: @"{{got.|\\01__imp__?}}$s1T18resilient_protocol24ProtocolWithRequirementsPTl" // CHECK-SAME: @"symbolic Si" // CHECK-SAME: @"{{got.|\\01__imp__?}}$s18resilient_protocol24ProtocolWithRequirementsP5firstyyFTq" // CHECK-SAME: @firstWitness // CHECK-SAME: @"{{got.|\\01__imp__?}}$s18resilient_protocol24ProtocolWithRequirementsP6secondyyFTq" // CHECK-SAME: @secondWitness // -- number of witness table entries // CHECK-SAME: i16 0, // -- size of private area + 'requires instantiation' bit // CHECK-SAME: i16 1, // -- instantiator function // CHECK-SAME: i32 0 // CHECK-SAME: } // CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @defaultC(ptr noalias swiftself %0, ptr %Self, ptr %SelfWitnessTable) // CHECK-NEXT: entry: sil @defaultC : $@convention(witness_method: ResilientProtocol) (@in_guaranteed Self) -> () { bb0(%0 : $*Self): // CHECK-NEXT: %[[SELF:.*]] = alloca ptr // CHECK-NEXT: store ptr %Self, ptr %[[SELF]] // CHECK-NEXT: ret void %result = tuple () return %result : $() } // CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @defaultD(ptr noalias swiftself %0, ptr %Self, ptr %SelfWitnessTable) // CHECK-NEXT: entry: sil @defaultD : $@convention(witness_method: ResilientProtocol) (@in_guaranteed Self) -> () { bb0(%0 : $*Self): // Make sure we can emit direct references to other default implementations // CHECK-NEXT: %[[SELF:.*]] = alloca ptr // CHECK-NEXT: store ptr %Self, ptr %[[SELF]] // CHECK-NEXT: call swiftcc void @defaultC(ptr noalias swiftself %0, ptr %Self, ptr %SelfWitnessTable) %fn1 = function_ref @defaultC : $@convention(witness_method: ResilientProtocol) (@in_guaranteed Self) -> () %ignore1 = apply %fn1(%0) : $@convention(witness_method: ResilientProtocol) (@in_guaranteed Self) -> () // Make sure we can do dynamic dispatch to other protocol requirements // from a default implementation // CHECK-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds ptr, ptr %SelfWitnessTable, i32 5 // CHECK-NEXT: [[WITNESS_FN:%.*]] = load ptr, ptr [[WITNESS_ADDR]] // CHECK: call swiftcc void [[WITNESS_FN]](ptr noalias swiftself %0, ptr %Self, ptr %SelfWitnessTable) %fn2 = witness_method $Self, #ResilientProtocol.defaultC : $@convention(witness_method: ResilientProtocol) (@in_guaranteed Self) -> () %ignore2 = apply %fn2(%0) : $@convention(witness_method: ResilientProtocol) (@in_guaranteed Self) -> () // Make sure we can partially apply a static reference to a default // implementation // CHECK-NEXT: [[CONTEXT:%.*]] = call noalias ptr @swift_allocObject({{.*}}) // CHECK: [[WTABLE_ADDR:%.*]] = getelementptr inbounds <{ %swift.refcounted, [{{4|8}} x i8], ptr }>, ptr [[CONTEXT]], i32 0, i32 2 // CHECK-NEXT: store ptr %SelfWitnessTable, ptr [[WTABLE_ADDR]] %fn3 = function_ref @defaultC : $@convention(witness_method: ResilientProtocol) (@in_guaranteed Self) -> () %ignore3 = partial_apply %fn3() : $@convention(witness_method: ResilientProtocol) (@in_guaranteed Self) -> () // CHECK-NEXT: ret void %result = tuple () return %result : $() } // CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @defaultE(ptr swiftself %0, ptr %Self, ptr %SelfWitnessTable) // CHECK-NEXT: entry: sil @defaultE : $@convention(witness_method: ResilientProtocol) (@thick Self.Type) -> () { bb0(%0 : $@thick Self.Type): // Make sure we can emit direct references to other default implementations // CHECK-NEXT: %[[SELF:.*]] = alloca ptr // CHECK-NEXT: store ptr %Self, ptr %[[SELF]] // CHECK-NEXT: call swiftcc void @defaultF(ptr swiftself %0, ptr %Self, ptr %SelfWitnessTable) %fn1 = function_ref @defaultF : $@convention(witness_method: ResilientProtocol) (@thick Self.Type) -> () %ignore1 = apply %fn1(%0) : $@convention(witness_method: ResilientProtocol) (@thick Self.Type) -> () // Make sure we can do dynamic dispatch to other protocol requirements // from a default implementation // CHECK-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds ptr, ptr %SelfWitnessTable, i32 8 // CHECK-NEXT: [[WITNESS_FN:%.*]] = load ptr, ptr [[WITNESS_ADDR]] // CHECK: call swiftcc void [[WITNESS_FN]](ptr swiftself %0, ptr %Self, ptr %SelfWitnessTable) %fn2 = witness_method $Self, #ResilientProtocol.defaultF : $@convention(witness_method: ResilientProtocol) (@thick Self.Type) -> () %ignore2 = apply %fn2(%0) : $@convention(witness_method: ResilientProtocol) (@thick Self.Type) -> () // Make sure we can partially apply a static reference to a default // implementation // CHECK-NEXT: [[CONTEXT:%.*]] = call noalias ptr @swift_allocObject({{.*}}) // CHECK: [[WTABLE_ADDR:%.*]] = getelementptr inbounds <{ %swift.refcounted, [{{4|8}} x i8], ptr }>, ptr [[CONTEXT]], i32 0, i32 2 // CHECK-NEXT: store ptr %SelfWitnessTable, ptr [[WTABLE_ADDR]] %fn3 = function_ref @defaultF : $@convention(witness_method: ResilientProtocol) (@thick Self.Type) -> () %ignore3 = partial_apply %fn3() : $@convention(witness_method: ResilientProtocol) (@thick Self.Type) -> () // CHECK-NEXT: ret void %result = tuple () return %result : $() } // CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @defaultF(ptr swiftself %0, ptr %Self, ptr %SelfWitnessTable) // CHECK-NEXT: entry: sil @defaultF : $@convention(witness_method: ResilientProtocol) (@thick Self.Type) -> () { bb0(%0 : $@thick Self.Type): // CHECK-NEXT: %[[SELF:.*]] = alloca ptr // CHECK-NEXT: store ptr %Self, ptr %[[SELF]] // CHECK-NEXT: ret void %result = tuple () return %result : $() } sil_default_witness_table ResilientProtocol { no_default no_default no_default no_default method #ResilientProtocol.defaultC: @defaultC method #ResilientProtocol.defaultD: @defaultD method #ResilientProtocol.defaultE: @defaultE method #ResilientProtocol.defaultF: @defaultF } public struct ResilientConformingType : OtherResilientProtocol {} sil_witness_table ResilientConformingType : OtherResilientProtocol module protocol_resilience {} struct ConformingStruct : ResilientProtocol { typealias T = ResilientConformingType func noDefaultA() func noDefaultB() func defaultC() func defaultD() static func defaultE() static func defaultF() } // CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @noDefaultA(ptr noalias nocapture swiftself %0, ptr %Self, ptr %SelfWitnessTable) // CHECK-NEXT: entry: sil @noDefaultA : $@convention(witness_method: ResilientProtocol) (@in_guaranteed ConformingStruct) -> () { bb0(%0 : $*ConformingStruct): // Make sure we can emit direct references to default implementations with a // concrete Self type. // CHECK-NEXT: call swiftcc void @defaultC(ptr noalias swiftself %0, ptr %Self, ptr %SelfWitnessTable) %fn1 = function_ref @defaultC : $@convention(witness_method: ResilientProtocol) (@in_guaranteed Self) -> () %ignore1 = apply %fn1(%0) : $@convention(witness_method: ResilientProtocol) (@in_guaranteed Self) -> () // CHECK-NEXT: ret void %result = tuple () return %result : $() } // CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @noDefaultB(ptr noalias nocapture swiftself %0, ptr %Self, ptr %SelfWitnessTable) // CHECK-NEXT: entry: sil @noDefaultB : $@convention(witness_method: ResilientProtocol) (@in_guaranteed ConformingStruct) -> () { bb0(%0 : $*ConformingStruct): // Make sure we can partially apply direct references to default implementations // CHECK-NEXT: [[CONTEXT:%.*]] = call noalias ptr @swift_allocObject({{.*}}) // CHECK-NEXT: [[WTABLE:%.*]] = getelementptr inbounds <{ %swift.refcounted, ptr }>, ptr [[CONTEXT]], i32 0, i32 1 // CHECK-NEXT: store ptr %SelfWitnessTable, ptr [[WTABLE]] %fn1 = function_ref @defaultC : $@convention(witness_method: ResilientProtocol) (@in_guaranteed Self) -> () %ignore1 = partial_apply %fn1() : $@convention(witness_method: ResilientProtocol) (@in_guaranteed Self) -> () // CHECK-NEXT: ret void %result = tuple () return %result : $() } sil_witness_table ConformingStruct : ResilientProtocol module protocol_resilience { associated_conformance (T: OtherResilientProtocol): ResilientConformingType: OtherResilientProtocol module protocol_resilience associated_type T: ResilientConformingType method #ResilientProtocol.noDefaultA: @noDefaultA method #ResilientProtocol.noDefaultB: @noDefaultB method #ResilientProtocol.defaultC: @defaultC method #ResilientProtocol.defaultD: @defaultD method #ResilientProtocol.defaultE: @defaultE method #ResilientProtocol.defaultF: @defaultF } // // Make sure resilient conformances are accessed with an accessor function // // CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @doSomething(ptr noalias %0, ptr %T, ptr %T.OtherResilientProtocol) sil @doSomething : $@convention(thin) (@in T) -> () { bb0(%0 : $*T): %result = tuple () return %result : $() } // CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @passConformingType(ptr noalias nocapture %0) sil @passConformingType : $@convention(thin) (@in ResilientConformingType) -> () { bb0(%0 : $*ResilientConformingType): // CHECK-NEXT: entry: // CHECK-NEXT: [[WTABLE:%.*]] = call ptr @"$s19protocol_resilience23ResilientConformingTypeVAC010resilient_A005OtherC8ProtocolAAWl"() // CHECK-NEXT: call swiftcc void @doSomething(ptr noalias %0, ptr getelementptr inbounds ({{.*}} @"$s19protocol_resilience23ResilientConformingTypeVMf", i32 0, i32 2), ptr [[WTABLE]]) %fn = function_ref @doSomething : $@convention(thin) (@in T) -> () %ignore = apply %fn(%0) : $@convention(thin) (@in T) -> () // CHECK-NEXT: ret void %result = tuple () return %result : $() } // Caching witness table accessor // CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} linkonce_odr hidden ptr @"$s19protocol_resilience23ResilientConformingTypeVAC010resilient_A005OtherC8ProtocolAAWl"() // CHECK-NEXT: entry: // CHECK-NEXT: [[CACHE:%.*]] = load ptr, ptr @"$s19protocol_resilience23ResilientConformingTypeVAC010resilient_A005OtherC8ProtocolAAWL" // CHECK-NEXT: [[COND:%.*]] = icmp eq ptr [[CACHE]], null // CHECK-NEXT: br i1 [[COND]], label %cacheIsNull, label %cont // CHECK: cacheIsNull: // CHECK: [[WTABLE:%.*]] = call ptr @swift_getWitnessTable // CHECK-NEXT: store atomic ptr [[WTABLE]], ptr @"$s19protocol_resilience23ResilientConformingTypeVAC010resilient_A005OtherC8ProtocolAAWL" release // CHECK-NEXT: br label %cont // CHECK: cont: // CHECK-NEXT: [[RESULT:%.*]] = phi ptr [ [[CCHE:%.*]], %entry ], [ [[WTABLE:%.*]], %cacheIsNull ] // CHECK-NEXT: ret ptr [[RESULT]] // // If a protocol refines a resilient protocol, any conformances are // resilient too // protocol RefinesOtherResilientProtocol : OtherResilientProtocol {} struct AnotherConformingStruct : RefinesOtherResilientProtocol {} sil_witness_table AnotherConformingStruct : RefinesOtherResilientProtocol module protocol_resilience { base_protocol OtherResilientProtocol: AnotherConformingStruct: OtherResilientProtocol module protocol_resilience } sil_witness_table hidden AnotherConformingStruct: OtherResilientProtocol module protocol_resilience { } // CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @doSomethingRefined(ptr noalias %0, ptr %T, ptr %T.RefinesOtherResilientProtocol) sil @doSomethingRefined : $@convention(thin) (@in T) -> () { bb0(%0 : $*T): %result = tuple () return %result : $() } // CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @passConformingTypeRefined(ptr noalias nocapture %0) sil @passConformingTypeRefined : $@convention(thin) (@in AnotherConformingStruct) -> () { bb0(%0 : $*AnotherConformingStruct): // CHECK-NEXT: entry: // CHECK-NEXT: [[WTABLE:%.*]] = call ptr @"$s19protocol_resilience23AnotherConformingStructVAcA29RefinesOtherResilientProtocolAAWl"() // CHECK-NEXT: call swiftcc void @doSomethingRefined(ptr noalias %0, ptr getelementptr inbounds ({{.*}} @"$s19protocol_resilience23AnotherConformingStructVMf", i32 0, i32 2), ptr [[WTABLE]]) %fn = function_ref @doSomethingRefined : $@convention(thin) (@in T) -> () %ignore = apply %fn(%0) : $@convention(thin) (@in T) -> () // CHECK-NEXT: ret void %result = tuple () return %result : $() } // // If an associated type conformance is resilient, the overall // conformance is not necessarily resilient, because we access // the associated type conformance lazily. // protocol HasResilientAssoc { associatedtype T : OtherResilientProtocol } struct ConformsWithResilientAssoc : HasResilientAssoc { typealias T = ResilientConformingType } sil_witness_table ConformsWithResilientAssoc : HasResilientAssoc module protocol_resilience { associated_conformance (T: OtherResilientProtocol): ResilientConformingType: OtherResilientProtocol module protocol_resilience associated_type T: ResilientConformingType } // CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @doSomethingAssoc(ptr noalias %0, ptr %T, ptr %T.HasResilientAssoc) sil @doSomethingAssoc : $@convention(thin) (@in T) -> () { bb0(%0 : $*T): %result = tuple () return %result : $() } // CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @passConformingTypeAssoc(ptr noalias nocapture %0) sil @passConformingTypeAssoc : $@convention(thin) (@in ConformsWithResilientAssoc) -> () { bb0(%0 : $*ConformsWithResilientAssoc): // CHECK-NEXT: entry: // CHECK-NEXT: [[WTABLE:%.*]] = call ptr @"$s19protocol_resilience26ConformsWithResilientAssocVAcA03HaseF0AAWl // CHECK-NEXT: call swiftcc void @doSomethingAssoc(ptr noalias %0, ptr getelementptr inbounds ({{.*}} @"$s19protocol_resilience26ConformsWithResilientAssocVMf", i32 0, i32 2), ptr [[WTABLE]]) %fn = function_ref @doSomethingAssoc : $@convention(thin) (@in T) -> () %ignore = apply %fn(%0) : $@convention(thin) (@in T) -> () // CHECK-NEXT: ret void %result = tuple () return %result : $() } struct ConformsWithRequirements : ProtocolWithRequirements { typealias T = Int func first() {} func second() {} } sil @firstWitness : $@convention(witness_method: ProtocolWithRequirements) (@in_guaranteed ConformsWithRequirements) -> () { bb0(%0 : $*ConformsWithRequirements): unreachable } sil @secondWitness : $@convention(witness_method: ProtocolWithRequirements) (@in_guaranteed ConformsWithRequirements) -> () { bb0(%0 : $*ConformsWithRequirements): unreachable } sil_witness_table ConformsWithRequirements : ProtocolWithRequirements module protocol_resilience { associated_type T: Int method #ProtocolWithRequirements.first: @firstWitness method #ProtocolWithRequirements.second: @secondWitness }