// RUN: %target-swift-emit-silgen -Xllvm -sil-print-types -module-name nested_generics -Xllvm -sil-full-demangle -parse-as-library %s | %FileCheck %s // RUN: %target-swift-emit-sil -Xllvm -sil-print-types -module-name nested_generics -Xllvm -sil-full-demangle -parse-as-library %s > /dev/null // RUN: %target-swift-emit-sil -Xllvm -sil-print-types -module-name nested_generics -Xllvm -sil-full-demangle -O -parse-as-library %s > /dev/null // RUN: %target-swift-emit-ir -module-name nested_generics -Xllvm -sil-full-demangle -parse-as-library %s > /dev/null // TODO: // - test generated SIL -- mostly we're just testing mangling here // - class_method calls // - witness_method calls // - inner generic parameters on protocol requirements // - generic parameter list on method in nested type // - types nested inside unconstrained extensions of generic types protocol Pizza : class { associatedtype Topping } protocol HotDog { associatedtype Condiment } protocol CuredMeat {} // Generic nested inside generic struct Lunch where T.Topping : CuredMeat { struct Dinner where U.Condiment == Deli.Mustard { let firstCourse: T let secondCourse: U? var leftovers: T var transformation: (T) -> U func coolCombination(t: T.Topping, u: U.Condiment) { func nestedGeneric(x: X, y: Y) -> (X, Y) { return (x, y) } _ = nestedGeneric(x: t, y: u) } } } // CHECK-LABEL: // nested_generics.Lunch.Dinner.coolCombination(t: A.Topping, u: nested_generics.Deli.Mustard) -> () // CHECK-LABEL: sil hidden [ossa] @$s15nested_generics5LunchV6DinnerV15coolCombination1t1uy7ToppingQz_AA4DeliC7MustardOyAA6PepperV_GtF : $@convention(method) .Mustard> (@in_guaranteed T.Topping, Deli.Mustard, @in_guaranteed Lunch.Dinner) -> () // CHECK-LABEL: // nestedGeneric #1 .Mustard>(x: A2, y: B2) -> (A2, B2) in nested_generics.Lunch.Dinner.coolCombination(t: A.Topping, u: nested_generics.Deli.Mustard) -> () // CHECK-LABEL: sil private [ossa] @$s15nested_generics5LunchV6DinnerV15coolCombination1t1uy7ToppingQz_AA4DeliC7MustardOyAA6PepperV_GtF0A7GenericL_1x1yqd0___qd0_0_tqd0___qd0_0_tAA5PizzaRzAA6HotDogRd__AA9CuredMeatAJRQAQ9CondimentRtd__r__0_lF : $@convention(thin) .Mustard> (@in_guaranteed X, @in_guaranteed Y) -> (@out X, @out Y) // CHECK-LABEL: // nested_generics.Lunch.Dinner.init(firstCourse: A, secondCourse: Swift.Optional, leftovers: A, transformation: (A) -> A1) -> nested_generics.Lunch.Dinner // CHECK-LABEL: sil hidden [ossa] @$s15nested_generics5LunchV6DinnerV11firstCourse06secondF09leftovers14transformationAEyx_qd__Gx_qd__Sgxqd__xctcfC : $@convention(method) .Mustard> (@owned T, @in Optional, @owned T, @owned @callee_guaranteed @substituted <τ_0_0, τ_0_1 where τ_0_0 : AnyObject> (@guaranteed τ_0_0) -> @out τ_0_1 for , @thin Lunch.Dinner.Type) -> @out Lunch.Dinner // Non-generic nested inside generic class Deli : CuredMeat { class Pepperoni : CuredMeat {} struct Sausage : CuredMeat {} enum Mustard { case Yellow case Dijon case DeliStyle(Spices) } } // CHECK-LABEL: // nested_generics.Deli.Pepperoni.init() -> nested_generics.Deli.Pepperoni // CHECK-LABEL: sil hidden [ossa] @$s15nested_generics4DeliC9PepperoniCAEyx_Gycfc : $@convention(method) (@owned Deli.Pepperoni) -> @owned Deli.Pepperoni // Typealiases referencing outer generic parameters struct Pizzas { class NewYork : Pizza { typealias Topping = Deli.Pepperoni } class DeepDish : Pizza { typealias Topping = Deli.Sausage } } class HotDogs { struct Bratwurst : HotDog { typealias Condiment = Deli.Mustard } struct American : HotDog { typealias Condiment = Deli.Mustard } } // Local type in extension of type in another module extension String { func foo() { // CHECK-LABEL: // init(material: A) -> Cheese #1 in (extension in nested_generics):Swift.String.foo() -> () in Cheese #1 in (extension in nested_generics):Swift.String.foo() -> () // CHECK-LABEL: sil private [ossa] @$sSS15nested_genericsE3fooyyF6CheeseL_V8materialADyxGx_tcfC struct Cheese { let material: Milk } let _ = Cheese(material: "cow") } } // Local type in extension of type in same module extension HotDogs { func applyRelish() { // CHECK-LABEL: // init(material: A) -> Relish #1 in nested_generics.HotDogs.applyRelish() -> () in Relish #1 in nested_generics.HotDogs.applyRelish() -> () // CHECK-LABEL: sil private [ossa] @$s15nested_generics7HotDogsC11applyRelishyyF0F0L_V8materialAFyxGx_tcfC struct Relish { let material: Material } let _ = Relish(material: "pickles") } } struct Pepper {} struct ChiliFlakes {} // CHECK-LABEL: // nested_generics.eatDinnerGeneric.Mustard>(d: inout nested_generics.Lunch.Dinner, t: A.Topping, u: nested_generics.Deli.Mustard) -> () // CHECK-LABEL: sil hidden [ossa] @$s15nested_generics16eatDinnerGeneric1d1t1uyAA5LunchV0D0Vyx_q_Gz_7ToppingQzAA4DeliC7MustardOyAA6PepperV_GtAA5PizzaRzAA6HotDogR_AA9CuredMeatALRQAS9CondimentRt_r0_lF : $@convention(thin) .Mustard> (@inout Lunch.Dinner, @in_guaranteed T.Topping, Deli.Mustard) -> () func eatDinnerGeneric(d: inout Lunch.Dinner, t: T.Topping, u: U.Condiment) { // Method call _ = d.coolCombination(t: t, u: u) // Read a let, store into var d.leftovers = d.firstCourse // Read a var let _ = d.secondCourse // Call property of function type _ = d.transformation(d.leftovers) } // Overloading concrete function with different bound generic arguments in parent type // CHECK-LABEL: // nested_generics.eatDinnerConcrete(d: inout nested_generics.Lunch.NewYork>.Dinner, t: nested_generics.Deli.Pepperoni, u: nested_generics.Deli.Mustard) -> () // CHECK-LABEL: sil hidden [ossa] @$s15nested_generics17eatDinnerConcrete1d1t1uyAA5LunchV0D0VyAA6PizzasV7NewYorkCyAA11ChiliFlakesV_G_AA7HotDogsC8AmericanVGz_AA4DeliC9PepperoniCyAO_GAW7MustardOyAA6PepperV_GtF : $@convention(thin) (@inout Lunch.NewYork>.Dinner, @guaranteed Deli.Pepperoni, Deli.Mustard) -> () func eatDinnerConcrete(d: inout Lunch.NewYork>.Dinner, t: Deli.Pepperoni, u: Deli.Mustard) { // Method call _ = d.coolCombination(t: t, u: u) // Read a let, store into var d.leftovers = d.firstCourse // Read a var let _ = d.secondCourse // Call property of function type _ = d.transformation(d.leftovers) } // CHECK-LABEL: // reabstraction thunk helper from @escaping @callee_guaranteed (@guaranteed nested_generics.Pizzas.NewYork) -> (@out nested_generics.HotDogs.American) to @escaping @callee_guaranteed (@guaranteed nested_generics.Pizzas.NewYork) -> (@unowned nested_generics.HotDogs.American) // CHECK-LABEL: sil shared [transparent] [serialized] [reabstraction_thunk] [ossa] @$s15nested_generics6PizzasV7NewYorkCyAA11ChiliFlakesV_GAA7HotDogsC8AmericanVIeggr_AhLIeggd_TR : $@convention(thin) (@guaranteed Pizzas.NewYork, @guaranteed @callee_guaranteed (@guaranteed Pizzas.NewYork) -> @out HotDogs.American) -> HotDogs.American // CHECK-LABEL: // nested_generics.eatDinnerConcrete(d: inout nested_generics.Lunch.NewYork>.Dinner, t: nested_generics.Deli.Pepperoni, u: nested_generics.Deli.Mustard) -> () // CHECK-LABEL: sil hidden [ossa] @$s15nested_generics17eatDinnerConcrete1d1t1uyAA5LunchV0D0VyAA6PizzasV7NewYorkCyAA6PepperV_G_AA7HotDogsC8AmericanVGz_AA4DeliC9PepperoniCyAO_GAW7MustardOyAO_GtF : $@convention(thin) (@inout Lunch.NewYork>.Dinner, @guaranteed Deli.Pepperoni, Deli.Mustard) -> () func eatDinnerConcrete(d: inout Lunch.NewYork>.Dinner, t: Deli.Pepperoni, u: Deli.Mustard) { // Method call _ = d.coolCombination(t: t, u: u) // Read a let, store into var d.leftovers = d.firstCourse // Read a var let _ = d.secondCourse // Call property of function type _ = d.transformation(d.leftovers) } // CHECK-LABEL: // reabstraction thunk helper from @escaping @callee_guaranteed (@guaranteed nested_generics.Pizzas.NewYork) -> (@out nested_generics.HotDogs.American) to @escaping @callee_guaranteed (@guaranteed nested_generics.Pizzas.NewYork) -> (@unowned nested_generics.HotDogs.American) // CHECK-LABEL: sil shared [transparent] [serialized] [reabstraction_thunk] [ossa] @$s15nested_generics6PizzasV7NewYorkCyAA6PepperV_GAA7HotDogsC8AmericanVIeggr_AhLIeggd_TR : $@convention(thin) (@guaranteed Pizzas.NewYork, @guaranteed @callee_guaranteed (@guaranteed Pizzas.NewYork) -> @out HotDogs.American) -> HotDogs.American // CHECK-LABEL: // closure #1 (nested_generics.Pizzas.NewYork) -> nested_generics.HotDogs.American in nested_generics.calls() -> () // CHECK-LABEL: sil private [ossa] @$s15nested_generics5callsyyFAA7HotDogsC8AmericanVAA6PizzasV7NewYorkCyAA6PepperV_GcfU_ : func calls() { let firstCourse = Pizzas.NewYork() let secondCourse = HotDogs.American() var dinner = Lunch.NewYork>.Dinner( firstCourse: firstCourse, secondCourse: secondCourse, leftovers: firstCourse, transformation: { _ in HotDogs.American() }) let topping = Deli.Pepperoni() let condiment1 = Deli.Mustard.Dijon let condiment2 = Deli.Mustard.DeliStyle(Pepper()) eatDinnerGeneric(d: &dinner, t: topping, u: condiment1) eatDinnerConcrete(d: &dinner, t: topping, u: condiment2) } protocol ProtocolWithGenericRequirement { associatedtype T associatedtype U func method(t: T, u: U, v: V) -> (T, U, V) } class OuterRing { class InnerRing : ProtocolWithGenericRequirement { func method(t: T, u: U, v: V) -> (T, U, V) { return (t, u, v) } } } class SubclassOfInner : OuterRing.InnerRing { override func method(t: T, u: U, v: V) -> (T, U, V) { return super.method(t: t, u: u, v: v) } } // Reduced from some code in Doggie. rdar://107642925 struct LocalGenericFunc { var address: UnsafeMutablePointer init(address: UnsafeMutablePointer) { self.address = address } mutating func foo() { func helper(_ newElements: S) where S.Element == Element { let buffer = address } } } // CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s15nested_generics9OuterRingC05InnerD0Cyx_qd__GAA30ProtocolWithGenericRequirementA2aGP6method1t1u1v1TQz_1UQzqd__tAN_APqd__tlFTW : $@convention(witness_method: ProtocolWithGenericRequirement) <τ_0_0><τ_1_0><τ_2_0> (@in_guaranteed τ_0_0, @in_guaranteed τ_1_0, @in_guaranteed τ_2_0, @in_guaranteed OuterRing<τ_0_0>.InnerRing<τ_1_0>) -> (@out τ_0_0, @out τ_1_0, @out τ_2_0) { // CHECK: bb0([[T:%[0-9]+]] : $*τ_0_0, [[U:%[0-9]+]] : $*τ_1_0, [[V:%[0-9]+]] : $*τ_2_0, [[TOut:%[0-9]+]] : $*τ_0_0, [[UOut:%[0-9]+]] : $*τ_1_0, [[VOut:%[0-9]+]] : $*τ_2_0, [[SELF:%[0-9]+]] : $*OuterRing<τ_0_0>.InnerRing<τ_1_0>): // CHECK: [[SELF_COPY_VAL:%[0-9]+]] = load_borrow [[SELF]] : $*OuterRing<τ_0_0>.InnerRing<τ_1_0> // CHECK: [[METHOD:%[0-9]+]] = class_method [[SELF_COPY_VAL]] : $OuterRing<τ_0_0>.InnerRing<τ_1_0>, #OuterRing.InnerRing.method : (OuterRing.InnerRing) -> (T, U, V) -> (T, U, V), $@convention(method) <τ_0_0><τ_1_0><τ_2_0> (@in_guaranteed τ_0_0, @in_guaranteed τ_1_0, @in_guaranteed τ_2_0, @guaranteed OuterRing<τ_0_0>.InnerRing<τ_1_0>) -> (@out τ_0_0, @out τ_1_0, @out τ_2_0) // CHECK: apply [[METHOD]]<τ_0_0, τ_1_0, τ_2_0>([[T]], [[U]], [[V]], [[TOut]], [[UOut]], [[VOut]], [[SELF_COPY_VAL]]) : $@convention(method) <τ_0_0><τ_1_0><τ_2_0> (@in_guaranteed τ_0_0, @in_guaranteed τ_1_0, @in_guaranteed τ_2_0, @guaranteed OuterRing<τ_0_0>.InnerRing<τ_1_0>) -> (@out τ_0_0, @out τ_1_0, @out τ_2_0) // CHECK: [[RESULT:%[0-9]+]] = tuple () // CHECK: end_borrow [[SELF_COPY_VAL]] // CHECK: return [[RESULT]] : $() // CHECK: sil_witness_table hidden Deli.Pepperoni: CuredMeat module nested_generics { // CHECK: } // CHECK: sil_witness_table hidden Deli.Sausage: CuredMeat module nested_generics { // CHECK: } // CHECK: sil_witness_table hidden Deli: CuredMeat module nested_generics { // CHECK: } // CHECK: sil_witness_table hidden Pizzas.NewYork: Pizza module nested_generics { // CHECK: associated_type Topping: Deli.Pepperoni // CHECK: } // CHECK: sil_witness_table hidden Pizzas.DeepDish: Pizza module nested_generics { // CHECK: associated_type Topping: Deli.Sausage // CHECK: } // CHECK: sil_witness_table hidden HotDogs.Bratwurst: HotDog module nested_generics { // CHECK: associated_type Condiment: Deli.Mustard // CHECK: } // CHECK: sil_witness_table hidden HotDogs.American: HotDog module nested_generics { // CHECK: associated_type Condiment: Deli.Mustard // CHECK: }