slidenumber: true autoscale: true
- SE-0309: Unlock existentials for all protocols
- SE-0328: Structural opaque result types
- SE-0335: Introduce existential any
- SE-0341: Opaque Parameter Declarations
- SE-0346: Lightweight same-type requirements for primary associated types
- SE-0352: Implicitly Opened Existentials
- SE-0353: Constrained Existential Types
- SE-0309: Unlock existentials for all protocols1
- SE-0328: Structural opaque result types2
- SE-0335: Introduce existential any3
- SE-0341: Opaque Parameter Declarations4
- SE-0346: Lightweight same-type requirements for primary associated types5
- SE-0352: Implicitly Opened Existentials6
- SE-0353: Constrained Existential Types7
- 新しい言語機能の文法、意味、実装を理解する
- 歴史
- 既存機能の復習
- 新機能の紹介
Generics in Swift8
Swiftのジェネリクスの初期設計書。
Self Type, Associated Type, Explicit Conformance, Retroactive Conformance, Constraints, Existential などの主要な特徴が提唱されている。
Generics Manifesto9
Swiftのジェネリクスの将来の方向性を示す文書。 Swift 3の頃に公開され、かなり先端的な機能にも言及している。
Swift 4で軽微なものは実現されたが、 高度なものは Swift 5 時代にあまり進捗は無かった。
Improving the UI of generics10
Swiftが今後集中していくジェネリクスの方向性を示すフォーラムの書き込み。 Swift 5の頃に公開され、マニフェストの一部の内容を掘り下げている。
Swift 6に向けてここで言及された内容が導入されそう。
-
型の機能を宣言する
-
ジェネリックパラメータに制約(Constraint)を与える
-
Existentialを作る
protocol P {
associatedtype A
func f(a: A)
static func s() -> Self
}
struct S: P { ... }
- Pは型 ではなく あくまでも型の機能の宣言
Self typeは機能上はassociated typeと近い。 準拠(conform)する側で自身を割り当てる事が強いられているだけ。
protocol P {
associatedtype CustomSelf
}
struct S: P {
typealias CustomSelf = S
}
static memberはmetatypeに対するmember定義と捉えられる。
protocol P {
associatedtype A
static func s(a: A) -> Self
}
struct S: P { ... }
func foo(type: P.Type) { ... }
func main() {
foo(type: S.self)
}
protocol P {
associatedtype A
static func s(a: A) -> Self
}
// 以下のような気持ち
protocol PMetatype {
associatedtype A
associatedtype P
func s(a: A) -> P
}
まず制約を与えない場合を確認する
func foo<T>(t: T) -> T { ... }
- 型
<T>
について定義された関数
; a.foo<A>(t: A) -> A
define hidden swiftcc void @"$s1a3foo1txx_tlF"(
; T型の返り値がopaqueなポインタ引数になる
%swift.opaque* noalias nocapture sret(%swift.opaque) %0,
; T型の引数はopaqueなポインタ
%swift.opaque* noalias nocapture %1,
; Tの真の型
%swift.type* %T
) #0 { ... }
Value Witness Table11
-
メタタイプ(
%swift.type*
) からは Value Witness Table が取り出せる。 -
ジェネリックな型
<T>
の値(value)に対する基本操作が入った関数テーブル。 -
init, copy, destroy, sizeなど。
-
呼び出す側が
<T>
の真の型S
のメタタイプ(とVWT)をセットで渡す。
func foo<T: P>(t: P) -> T { ... }
- 型
<T>
がP
に準拠(conform)するという制約(constraint)を追加
; a.foo<A where A: a.P>(t: A) -> A
define hidden swiftcc void @"$s1a3foo1txx_tAA1PRzlF"(
; T型の返り値
%swift.opaque* noalias nocapture sret(%swift.opaque) %0,
; T型の引数
%swift.opaque* noalias nocapture %1,
; Tの真の型
%swift.type* %T,
; TのPへの準拠(Protocol Witness Table)
i8** %T.P
) #0 { ... }
Protocol Witness Table12
-
型
<T>
がP
に準拠するための操作が入った関数テーブル。 -
その内容は
P
の定義とほぼ同じ形になる。 -
呼び出す側が
<T>
の真の型S
のP
へのPWTをセットで渡す。
protocol P {
associatedtype A
func foo(a: A)
static func s() -> Self
}
struct S: P {
typealias A = Int
func foo(a: Int) { }
static func s() -> S { S() }
}
; protocol witness table for a.S : a.P in a
@"$s1a1SVAA1PAAWP" = hidden global [4 x i8*] [
; protocol conformance descriptor
i8* bitcast (%swift.protocol_conformance_descriptor* @"$s1a1SVAA1PAAMc" to i8*),
; A = Swift.Int
i8* getelementptr inbounds (
<{ [2 x i8], i8 }>, <{ [2 x i8], i8 }>* @"symbolic Si", i32 0, i32 0, i64 1
),
; func foo
i8* bitcast (void (%TSi*, %T1a1SV*, %swift.type*, i8**)* @"$s1a1SVAA1PA2aDP3fooAAy1AQz_tFTW" to i8*),
; static func s
i8* bitcast (void (%T1a1SV*, %swift.type*, %swift.type*, i8**)* @"$s1a1SVAA1PA2aDP1sxyFZTW" to i8*)
], align 8
protocol Q {}
protocol P {
associatedtype A: Q
func foo(a: A)
static func s() -> Self
}
; protocol witness table for a.S : a.P in a
@"$s1a1SVAA1PAAWP" = hidden global [5 x i8*] [
; protocol conformance descriptor
i8* bitcast (%swift.protocol_conformance_descriptor* @"$s1a1SVAA1PAAMc" to i8*),
; SのP準拠におけるS.AのQ準拠の情報
i8* getelementptr (
i8,
i8* getelementptr inbounds (
<{ i8, i8, i32, i8 }>,
<{ i8, i8, i32, i8 }>* @"associated conformance 1a1SVAA1PAA1AAaDP_AA1Q",
i32 0, i32 0
),
i64 1
),
; A = Swift.Int
i8* getelementptr inbounds (<{ [2 x i8], i8 }>, <{ [2 x i8], i8 }>* @"symbolic Si", i32 0, i32 0, i64 1),
; func foo
i8* bitcast (void (%TSi*, %T1a1SV*, %swift.type*, i8**)* @"$s1a1SVAA1PA2aDP3fooAAy1AQz_tFTW" to i8*),
; static func s
i8* bitcast (void (%T1a1SV*, %swift.type*, %swift.type*, i8**)* @"$s1a1SVAA1PA2aDP1sxyFZTW" to i8*)
], align 8
-
ジェネリックな型に対して行える操作をプロトコルで制約する事で宣言する
-
呼び出すときの真の型はコンパイル時に決定する
-
calleeは、値をopaqueなポインタ、基本操作のためのVWT、プロトコルとしての操作のためのPWTを受け取り、 それらのテーブルの関数を通して値を操作する
-
callerは、渡そうとしている真の型の専用のVWTとPWTを一緒に渡す
protocol P {
func foo()
}
func makeFoo() -> P { ... }
func callFoo(_ p: P) { ... }
func main() {
let p: P = makeFoo()
callFoo(p)
}
struct S: P {}
func makeFoo() -> P {
// S を P に格納
return S()
}
func callFoo(_ p: P) {
// P から <T: P> を取り出す
p.foo()
}
Existential Container12
// 気持ち表現
struct PContainer {
var value<T: P>: T
func foo() { value.foo() }
}
-
🙅♂️ プロトコルを型として使える
-
🙆♂️
<T: P>
を保持できるコンテナ型を使える
func useMetatype(type: P.Type) {}
func callUseMetatype(p: P) {
useMetatype(type: type(of: p))
}
func main() {
useMetatype(type: S.self)
callUseMetatype(p: S())
}
P
に準拠する型T
のメタタイプのコンテナ
func useExistentialContainerMetatype(type: P.Protocol) {}
func main() {
useExistentialContainerMetatype(type: P.self)
}
- Existential Containerのメタタイプ
protocol P {
associatedtype A
}
// error: protocol 'P' can only be used as a generic constraint
// because it has Self or associated type requirements
func useP(p: P) {}
もし使えたとすると問題が生じる。
func useP(p: P) {
// P.Aがコンパイル時に決定できない
func f(a: P.A) {}
}
Any型を使ってもcontravariantな場合にうまくいかない。
protocol P {
associatedtype A
func useA(a: A)
}
struct S: P {
func useA(a: Int) {}
}
func useP(p: P) {
// useA(a: Any) ?
p.useA(a: "string")
}
protocol P {
func foo(_ a: Self)
}
// error: protocol 'P' can only be used as a generic constraint
// because it has Self or associated type requirements
func useP(p: P) {}
もし使えたとすると問題が生じる。
func makeP() -> P { ... }
func useP(p: P) {
// pの真の型とmakePが返す真の型が同一とは限らない
p.foo(makeP())
}
protocol P {
func s() -> Self
func os() -> Self?
func fs() -> () -> Self
func ts() -> (Self, Self)
func ffs() -> ((Self) -> Void) -> Void
}
// OK
func useFoo(p: P) {}
Self = existenal P とラップするだけ
protocol P {}
// error: protocol 'P' as a type cannot
// conform to the protocol itself
func useGenericP<T: P>(p: P) {}
func useExistentialP(p: P) {
useGenericP(p: p)
}
Pのexistentialはprotocol Pに準拠していない
protocol P {
associatedtype A
}
P.A
は真の型によって異なる
protocol P {
func foo(p: Self)
}
Self
は真の型によって異なる
protocol P {
static func s()
}
func main() {
// error: static member 's' cannot be used
// on protocol metatype 'P.Protocol'
P.s()
}
@objc protocol P {
func foo()
}
func useGenericP<T: P>(p: T) {}
func useExistentialP(p: P) {
useGenericP(p: p)
}
- static memberが無い場合のみ
- associatedtypeはそもそも禁止
- Selfはあってもよい(?)
import Foundation
@objc protocol P {
// contravariance Self ?
func foo(_ p: Self)
}
@objc class S: NSObject, P {
var x: String = "s"
func foo(_ s: S) {
print("expected: s, actual: \(s.s())")
}
func s() -> String { x }
}
@objc class K: NSObject, P {
var y: Int = 2
func foo(_ k: K) {
print("expected: 2, actual: \(k.k())")
}
func k() -> Int { y }
}
func makeSP() -> P { S() }
func makeKP() -> P { K() }
func useP<T: P>(p1: T, p2: T) {
p1.foo(p2)
}
// Segmentation fault: 11
useP(p1: makeSP(), p2: makeKP())
func useGenericError<T: Error>(error: T) {}
func useError(error: Error) {
useGenericError(error: error)
}
- 超特別待遇
- メンバは何もないので問題はない
P
から <T: P>
を取り出す事を open と呼ぶ
func callFoo(p: P) {
// ここでopenしている
p.foo()
}
func proc<T: P>(_ t: T) { print(t) }
func useP(p: P) {
// error: protocol 'P' as a type cannot
// conform to the protocol itself
proc(p)
}
P
が手元にあるけど <T: P>
がほしい事がある
extension P {
func callProc() {
// let self: <Self: P>
proc(self)
}
}
func useP(p: P) {
p.callProc()
}
protocol extensionのメソッドのselfはopenされた型 <Self: P>
になっている。
protocol P {
func foo()
}
func useP(p: P) {
p.foo()
}
- Opaque Existential Containers12
struct OpaqueExistentialContainer {
void *fixedSizeBuffer[3];
Metadata *type;
WitnessTable *witnessTables[NUM_WITNESS_TABLES];
};
%T1b1PP = type { [24 x i8], %swift.type*, i8** }
%__opaque_existential_type_1 = type { [24 x i8], %swift.type*, i8** }
define hidden swiftcc void @"$s1b4useP1pyAA1P_p_tF"(
%T1b1PP* noalias nocapture dereferenceable(40) %0
) #0 {
entry:
%p.debug = alloca %T1b1PP*, align 8
%1 = bitcast %T1b1PP** %p.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %1, i8 0, i64 8, i1 false)
store %T1b1PP* %0, %T1b1PP** %p.debug, align 8
%2 = getelementptr inbounds %T1b1PP, %T1b1PP* %0, i32 0, i32 1
%3 = load %swift.type*, %swift.type** %2, align 8
%4 = getelementptr inbounds %T1b1PP, %T1b1PP* %0, i32 0, i32 2
%5 = load i8**, i8*** %4, align 8
%6 = bitcast %T1b1PP* %0 to %__opaque_existential_type_1*
%7 = call %swift.opaque* @__swift_project_boxed_opaque_existential_1(
%__opaque_existential_type_1* %6, %swift.type* %3
) #3
%8 = getelementptr inbounds i8*, i8** %5, i32 1
%9 = load i8*, i8** %8, align 8, !invariant.load !22
%10 = bitcast i8* %9 to void (%swift.opaque*, %swift.type*, i8**)*
call swiftcc void %10(%swift.opaque* noalias nocapture swiftself %7, %swift.type* %3, i8** %5)
ret void
}
型の取り出し
[.code-highlight: 1, 13-14]
%T1b1PP = type { [24 x i8], %swift.type*, i8** }
%__opaque_existential_type_1 = type { [24 x i8], %swift.type*, i8** }
define hidden swiftcc void @"$s1b4useP1pyAA1P_p_tF"(
%T1b1PP* noalias nocapture dereferenceable(40) %0
) #0 {
entry:
%p.debug = alloca %T1b1PP*, align 8
%1 = bitcast %T1b1PP** %p.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %1, i8 0, i64 8, i1 false)
store %T1b1PP* %0, %T1b1PP** %p.debug, align 8
%2 = getelementptr inbounds %T1b1PP, %T1b1PP* %0, i32 0, i32 1
%3 = load %swift.type*, %swift.type** %2, align 8
%4 = getelementptr inbounds %T1b1PP, %T1b1PP* %0, i32 0, i32 2
%5 = load i8**, i8*** %4, align 8
%6 = bitcast %T1b1PP* %0 to %__opaque_existential_type_1*
%7 = call %swift.opaque* @__swift_project_boxed_opaque_existential_1(
%__opaque_existential_type_1* %6, %swift.type* %3
) #3
%8 = getelementptr inbounds i8*, i8** %5, i32 1
%9 = load i8*, i8** %8, align 8, !invariant.load !22
%10 = bitcast i8* %9 to void (%swift.opaque*, %swift.type*, i8**)*
call swiftcc void %10(%swift.opaque* noalias nocapture swiftself %7, %swift.type* %3, i8** %5)
ret void
}
PWTとその中の関数の取り出し
[.code-highlight: 1, 15-16, 21-23]
%T1b1PP = type { [24 x i8], %swift.type*, i8** }
%__opaque_existential_type_1 = type { [24 x i8], %swift.type*, i8** }
define hidden swiftcc void @"$s1b4useP1pyAA1P_p_tF"(
%T1b1PP* noalias nocapture dereferenceable(40) %0
) #0 {
entry:
%p.debug = alloca %T1b1PP*, align 8
%1 = bitcast %T1b1PP** %p.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %1, i8 0, i64 8, i1 false)
store %T1b1PP* %0, %T1b1PP** %p.debug, align 8
%2 = getelementptr inbounds %T1b1PP, %T1b1PP* %0, i32 0, i32 1
%3 = load %swift.type*, %swift.type** %2, align 8
%4 = getelementptr inbounds %T1b1PP, %T1b1PP* %0, i32 0, i32 2
%5 = load i8**, i8*** %4, align 8
%6 = bitcast %T1b1PP* %0 to %__opaque_existential_type_1*
%7 = call %swift.opaque* @__swift_project_boxed_opaque_existential_1(
%__opaque_existential_type_1* %6, %swift.type* %3
) #3
%8 = getelementptr inbounds i8*, i8** %5, i32 1
%9 = load i8*, i8** %8, align 8, !invariant.load !22
%10 = bitcast i8* %9 to void (%swift.opaque*, %swift.type*, i8**)*
call swiftcc void %10(%swift.opaque* noalias nocapture swiftself %7, %swift.type* %3, i8** %5)
ret void
}
値の取り出し
[.code-highlight: 1, 17-20]
%T1b1PP = type { [24 x i8], %swift.type*, i8** }
%__opaque_existential_type_1 = type { [24 x i8], %swift.type*, i8** }
define hidden swiftcc void @"$s1b4useP1pyAA1P_p_tF"(
%T1b1PP* noalias nocapture dereferenceable(40) %0
) #0 {
entry:
%p.debug = alloca %T1b1PP*, align 8
%1 = bitcast %T1b1PP** %p.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %1, i8 0, i64 8, i1 false)
store %T1b1PP* %0, %T1b1PP** %p.debug, align 8
%2 = getelementptr inbounds %T1b1PP, %T1b1PP* %0, i32 0, i32 1
%3 = load %swift.type*, %swift.type** %2, align 8
%4 = getelementptr inbounds %T1b1PP, %T1b1PP* %0, i32 0, i32 2
%5 = load i8**, i8*** %4, align 8
%6 = bitcast %T1b1PP* %0 to %__opaque_existential_type_1*
%7 = call %swift.opaque* @__swift_project_boxed_opaque_existential_1(
%__opaque_existential_type_1* %6, %swift.type* %3
) #3
%8 = getelementptr inbounds i8*, i8** %5, i32 1
%9 = load i8*, i8** %8, align 8, !invariant.load !22
%10 = bitcast i8* %9 to void (%swift.opaque*, %swift.type*, i8**)*
call swiftcc void %10(%swift.opaque* noalias nocapture swiftself %7, %swift.type* %3, i8** %5)
ret void
}
取り出した関数に、値、型、PWTを渡して呼び出す
[.code-highlight: 14, 16, 23, 24]
%T1b1PP = type { [24 x i8], %swift.type*, i8** }
%__opaque_existential_type_1 = type { [24 x i8], %swift.type*, i8** }
define hidden swiftcc void @"$s1b4useP1pyAA1P_p_tF"(
%T1b1PP* noalias nocapture dereferenceable(40) %0
) #0 {
entry:
%p.debug = alloca %T1b1PP*, align 8
%1 = bitcast %T1b1PP** %p.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %1, i8 0, i64 8, i1 false)
store %T1b1PP* %0, %T1b1PP** %p.debug, align 8
%2 = getelementptr inbounds %T1b1PP, %T1b1PP* %0, i32 0, i32 1
%3 = load %swift.type*, %swift.type** %2, align 8
%4 = getelementptr inbounds %T1b1PP, %T1b1PP* %0, i32 0, i32 2
%5 = load i8**, i8*** %4, align 8
%6 = bitcast %T1b1PP* %0 to %__opaque_existential_type_1*
%7 = call %swift.opaque* @__swift_project_boxed_opaque_existential_1(
%__opaque_existential_type_1* %6, %swift.type* %3
) #3
%8 = getelementptr inbounds i8*, i8** %5, i32 1
%9 = load i8*, i8** %8, align 8, !invariant.load !22
%10 = bitcast i8* %9 to void (%swift.opaque*, %swift.type*, i8**)*
call swiftcc void %10(%swift.opaque* noalias nocapture swiftself %7, %swift.type* %3, i8** %5)
ret void
}
- Existential Containerは、真の値、その型、PWTをまとめたもの。
- PWTから取り出した関数を呼び出す形式は、ジェネリック関数における
<T: P>
の操作と全く同じで、openしていると言える。
- Existentialは
<T: P>
を保持するコンテナ - メソッド呼び出しによるopenで
<T: P>
を取り出せる - associated type, Self typeはvarianceの問題を含む
- 実装では、真の値、その型、PWTを持っていて、これはGeneric関数を呼び出すときの引数と同じもの
func foo<T: P>(t: T) -> T {
var u: T = t
// NG
// u = S()
return u
}
<T>
はそのコンテキストにおける、ある特定の型であり、
たとえ実行時にそうだったとしても、型チェックにおいては S
でも K
でもない。
引数で渡した t: T
と、そのコピーの u: T
や返り値の T
は同じ型であり、実行時においても渡した型が返ってくる。
func foo(p: P) -> P {
var u: P = p
// OK
u = S()
return u
}
P
は <T: P>
を格納できるコンテナで、中身の型は動的に変化しうる。
引数で渡した p: P
からコピーした u: P
に対して、
既存の中身とは無関係に S
を代入したり、それを返したりできる。
associated typeと自己準拠に対応したexistentialのようなものを自作する事があり、Type Erasureと呼ばれる。
標準ライブラリでは AnySequence<Element>
, AnyHashable
, KeyedDecodingContainer<K>
などがある。
言語機能ではなく単なる実装パターンなので実装は割愛。
Improving the UI of generics の内容を受けて Swift 5.1 で実装された。
protocol P {
func foo()
}
struct S: P {
func foo() {}
}
func makeP() -> some P {
S()
}
ORTは callee 側が決定する Generic Parameter Type と言える。 Reverse Genericsという架空の構文を考えると理解しやすい。
// ORT
func makeP() -> some P { S() }
// Reverse Generics
func makeP() -> <T: P> T { S() }
protocol P {
associatedtype A
func a() -> A
func useA(a: A)
}
func main() {
let p = makeP()
let a = p.a()
p.useA(a: a)
}
ORTはExistentialではなくGenericsなので、associatedtypeが使える。
makePの呼び出しが、型パラメータを導入し、決定していると考えるとわかりやすいかもしれない。
func main<T>() {
// ↑このTの真の型は
// ↓このmakePが決める
let p: T = makeP()
let a: T.A = p.a()
p.useA(a: a)
}
func main() {
let p = makeP()
let p2 = makeP()
let a = p2.a()
p.useA(a: a)
}
p
と p2
は異なる変数だが、同じ 「makeP
の返り値の型」なので、
同じ型であり、associatedtypeも同じ型。
型パラメータを書くとこう捉えられる。
func main<T>() {
// ↑このTは「makePの返り値の型」
let p: T = makeP()
let p2: T = makeP()
let a: T.A = p2.a()
p.useA(a: a)
}
外側にパラメータが露出しているのが気になるなら、こう考えても良い。
func main() {
func body<T: P>(p: T) {
let p: T = p
let p2: T = makeP()
let a: T.A = p2.a()
p.useA(a: a)
}
body(p: makeP())
}
真の型はその関数ごとに定まるので、たとえ実際には同じ型になるとしても、異なる some P
は別の型として扱われる。
func makeP() -> some P { S() }
func makeP2() -> some P { S() }
func main() {
let p = makeP()
let p2 = makeP2()
let a = p2.a()
// error: cannot convert value of type
// '(some b.P).A' (associated type of protocol 'P')
// to expected argument type
// '(some b.P).A' (associated type of protocol 'P')
p.useA(a: a)
}
これもパラメータ表示するとすぐわかる。
func main<T1, T2>() {
let p: T1 = makeP()
let p2: T2 = makeP2()
let a: T2.A = p2.a()
// T2.A は T1.A として渡せない
p.useA(a: a)
}
// c.swift
public protocol P {
func foo() -> Int
}
struct S: P {
func foo() -> Int { 1 }
}
public func makeP() -> some P {
S()
}
// b.swift
import c
func main() {
let p = makeP()
p.foo()
}
define hidden swiftcc void @"$s1b4mainyyF"() #0 {
entry:
%p.debug = alloca i8*, align 8
%0 = bitcast i8** %p.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %0, i8 0, i64 8, i1 false)
%1 = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s1c5makePQryFQOyQo_MD") #7
%2 = bitcast %swift.type* %1 to i8***
%3 = getelementptr inbounds i8**, i8*** %2, i64 -1
%.valueWitnesses = load i8**, i8*** %3, align 8, !invariant.load !18, !dereferenceable !19
%4 = bitcast i8** %.valueWitnesses to %swift.vwtable*
%5 = getelementptr inbounds %swift.vwtable, %swift.vwtable* %4, i32 0, i32 8
%size = load i64, i64* %5, align 8, !invariant.load !18
%6 = alloca i8, i64 %size, align 16
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %6)
%7 = bitcast i8* %6 to %swift.opaque*
store i8* %6, i8** %p.debug, align 8
call swiftcc void @"$s1c5makePQryF"(%swift.opaque* noalias nocapture sret(%swift.opaque) %7)
%8 = call swiftcc i8** @swift_getOpaqueTypeConformance(i8* undef, %swift.type_descriptor* @"$s1c5makePQryFQOMQ", i64 1) #8
%9 = getelementptr inbounds i8*, i8** %8, i32 1
%10 = load i8*, i8** %9, align 8, !invariant.load !18
%11 = bitcast i8* %10 to i64 (%swift.opaque*, %swift.type*, i8**)*
%12 = call swiftcc i64 %11(%swift.opaque* noalias nocapture swiftself %7, %swift.type* %1, i8** %8)
%13 = getelementptr inbounds i8*, i8** %.valueWitnesses, i32 1
%14 = load i8*, i8** %13, align 8, !invariant.load !18
%destroy = bitcast i8* %14 to void (%swift.opaque*, %swift.type*)*
call void %destroy(%swift.opaque* noalias %7, %swift.type* %1) #9
%15 = bitcast %swift.opaque* %7 to i8*
call void @llvm.lifetime.end.p0i8(i64 -1, i8* %15)
ret void
}
makeP
の返り値の真の型の取り出し
[.code-highlight: 1-2, 9]
; $s1c5makePQryFQOyQo_MD --->
; demangling cache variable for type metadata for <<opaque return type of c.makeP() -> some>>.0
define hidden swiftcc void @"$s1b4mainyyF"() #0 {
entry:
%p.debug = alloca i8*, align 8
%0 = bitcast i8** %p.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %0, i8 0, i64 8, i1 false)
%1 = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s1c5makePQryFQOyQo_MD") #7
%2 = bitcast %swift.type* %1 to i8***
%3 = getelementptr inbounds i8**, i8*** %2, i64 -1
%.valueWitnesses = load i8**, i8*** %3, align 8, !invariant.load !18, !dereferenceable !19
%4 = bitcast i8** %.valueWitnesses to %swift.vwtable*
%5 = getelementptr inbounds %swift.vwtable, %swift.vwtable* %4, i32 0, i32 8
%size = load i64, i64* %5, align 8, !invariant.load !18
%6 = alloca i8, i64 %size, align 16
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %6)
%7 = bitcast i8* %6 to %swift.opaque*
store i8* %6, i8** %p.debug, align 8
call swiftcc void @"$s1c5makePQryF"(%swift.opaque* noalias nocapture sret(%swift.opaque) %7)
%8 = call swiftcc i8** @swift_getOpaqueTypeConformance(i8* undef, %swift.type_descriptor* @"$s1c5makePQryFQOMQ", i64 1) #8
%9 = getelementptr inbounds i8*, i8** %8, i32 1
%10 = load i8*, i8** %9, align 8, !invariant.load !18
%11 = bitcast i8* %10 to i64 (%swift.opaque*, %swift.type*, i8**)*
%12 = call swiftcc i64 %11(%swift.opaque* noalias nocapture swiftself %7, %swift.type* %1, i8** %8)
%13 = getelementptr inbounds i8*, i8** %.valueWitnesses, i32 1
%14 = load i8*, i8** %13, align 8, !invariant.load !18
%destroy = bitcast i8* %14 to void (%swift.opaque*, %swift.type*)*
call void %destroy(%swift.opaque* noalias %7, %swift.type* %1) #9
%15 = bitcast %swift.opaque* %7 to i8*
call void @llvm.lifetime.end.p0i8(i64 -1, i8* %15)
ret void
}
真の型、VWT、型のサイズを取り出してローカル変数をスタックに確保する
[.code-highlight: 7-13, 15]
define hidden swiftcc void @"$s1b4mainyyF"() #0 {
entry:
%p.debug = alloca i8*, align 8
%0 = bitcast i8** %p.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %0, i8 0, i64 8, i1 false)
%1 = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s1c5makePQryFQOyQo_MD") #7
%2 = bitcast %swift.type* %1 to i8***
%3 = getelementptr inbounds i8**, i8*** %2, i64 -1
%.valueWitnesses = load i8**, i8*** %3, align 8, !invariant.load !18, !dereferenceable !19
%4 = bitcast i8** %.valueWitnesses to %swift.vwtable*
%5 = getelementptr inbounds %swift.vwtable, %swift.vwtable* %4, i32 0, i32 8
%size = load i64, i64* %5, align 8, !invariant.load !18
%6 = alloca i8, i64 %size, align 16
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %6)
%7 = bitcast i8* %6 to %swift.opaque*
store i8* %6, i8** %p.debug, align 8
call swiftcc void @"$s1c5makePQryF"(%swift.opaque* noalias nocapture sret(%swift.opaque) %7)
%8 = call swiftcc i8** @swift_getOpaqueTypeConformance(i8* undef, %swift.type_descriptor* @"$s1c5makePQryFQOMQ", i64 1) #8
%9 = getelementptr inbounds i8*, i8** %8, i32 1
%10 = load i8*, i8** %9, align 8, !invariant.load !18
%11 = bitcast i8* %10 to i64 (%swift.opaque*, %swift.type*, i8**)*
%12 = call swiftcc i64 %11(%swift.opaque* noalias nocapture swiftself %7, %swift.type* %1, i8** %8)
%13 = getelementptr inbounds i8*, i8** %.valueWitnesses, i32 1
%14 = load i8*, i8** %13, align 8, !invariant.load !18
%destroy = bitcast i8* %14 to void (%swift.opaque*, %swift.type*)*
call void %destroy(%swift.opaque* noalias %7, %swift.type* %1) #9
%15 = bitcast %swift.opaque* %7 to i8*
call void @llvm.lifetime.end.p0i8(i64 -1, i8* %15)
ret void
}
makeP
の呼び出し。返り値を第1引数のopaque pointerで受け取る。
[.code-highlight: 17]
define hidden swiftcc void @"$s1b4mainyyF"() #0 {
entry:
%p.debug = alloca i8*, align 8
%0 = bitcast i8** %p.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %0, i8 0, i64 8, i1 false)
%1 = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s1c5makePQryFQOyQo_MD") #7
%2 = bitcast %swift.type* %1 to i8***
%3 = getelementptr inbounds i8**, i8*** %2, i64 -1
%.valueWitnesses = load i8**, i8*** %3, align 8, !invariant.load !18, !dereferenceable !19
%4 = bitcast i8** %.valueWitnesses to %swift.vwtable*
%5 = getelementptr inbounds %swift.vwtable, %swift.vwtable* %4, i32 0, i32 8
%size = load i64, i64* %5, align 8, !invariant.load !18
%6 = alloca i8, i64 %size, align 16
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %6)
%7 = bitcast i8* %6 to %swift.opaque*
store i8* %6, i8** %p.debug, align 8
call swiftcc void @"$s1c5makePQryF"(%swift.opaque* noalias nocapture sret(%swift.opaque) %7)
%8 = call swiftcc i8** @swift_getOpaqueTypeConformance(i8* undef, %swift.type_descriptor* @"$s1c5makePQryFQOMQ", i64 1) #8
%9 = getelementptr inbounds i8*, i8** %8, i32 1
%10 = load i8*, i8** %9, align 8, !invariant.load !18
%11 = bitcast i8* %10 to i64 (%swift.opaque*, %swift.type*, i8**)*
%12 = call swiftcc i64 %11(%swift.opaque* noalias nocapture swiftself %7, %swift.type* %1, i8** %8)
%13 = getelementptr inbounds i8*, i8** %.valueWitnesses, i32 1
%14 = load i8*, i8** %13, align 8, !invariant.load !18
%destroy = bitcast i8* %14 to void (%swift.opaque*, %swift.type*)*
call void %destroy(%swift.opaque* noalias %7, %swift.type* %1) #9
%15 = bitcast %swift.opaque* %7 to i8*
call void @llvm.lifetime.end.p0i8(i64 -1, i8* %15)
ret void
}
真の型の P
の PWT を取得
[.code-highlight: 1, 20]
; $s1c5makePQryFQOMQ ---> opaque type descriptor for <<opaque return type of c.makeP() -> some>>
define hidden swiftcc void @"$s1b4mainyyF"() #0 {
entry:
%p.debug = alloca i8*, align 8
%0 = bitcast i8** %p.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %0, i8 0, i64 8, i1 false)
%1 = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s1c5makePQryFQOyQo_MD") #7
%2 = bitcast %swift.type* %1 to i8***
%3 = getelementptr inbounds i8**, i8*** %2, i64 -1
%.valueWitnesses = load i8**, i8*** %3, align 8, !invariant.load !18, !dereferenceable !19
%4 = bitcast i8** %.valueWitnesses to %swift.vwtable*
%5 = getelementptr inbounds %swift.vwtable, %swift.vwtable* %4, i32 0, i32 8
%size = load i64, i64* %5, align 8, !invariant.load !18
%6 = alloca i8, i64 %size, align 16
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %6)
%7 = bitcast i8* %6 to %swift.opaque*
store i8* %6, i8** %p.debug, align 8
call swiftcc void @"$s1c5makePQryF"(%swift.opaque* noalias nocapture sret(%swift.opaque) %7)
%8 = call swiftcc i8** @swift_getOpaqueTypeConformance(i8* undef, %swift.type_descriptor* @"$s1c5makePQryFQOMQ", i64 1) #8
%9 = getelementptr inbounds i8*, i8** %8, i32 1
%10 = load i8*, i8** %9, align 8, !invariant.load !18
%11 = bitcast i8* %10 to i64 (%swift.opaque*, %swift.type*, i8**)*
%12 = call swiftcc i64 %11(%swift.opaque* noalias nocapture swiftself %7, %swift.type* %1, i8** %8)
%13 = getelementptr inbounds i8*, i8** %.valueWitnesses, i32 1
%14 = load i8*, i8** %13, align 8, !invariant.load !18
%destroy = bitcast i8* %14 to void (%swift.opaque*, %swift.type*)*
call void %destroy(%swift.opaque* noalias %7, %swift.type* %1) #9
%15 = bitcast %swift.opaque* %7 to i8*
call void @llvm.lifetime.end.p0i8(i64 -1, i8* %15)
ret void
}
PWTから取り出した関数を呼び出す
[.code-highlight: 19-22]
define hidden swiftcc void @"$s1b4mainyyF"() #0 {
entry:
%p.debug = alloca i8*, align 8
%0 = bitcast i8** %p.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %0, i8 0, i64 8, i1 false)
%1 = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s1c5makePQryFQOyQo_MD") #7
%2 = bitcast %swift.type* %1 to i8***
%3 = getelementptr inbounds i8**, i8*** %2, i64 -1
%.valueWitnesses = load i8**, i8*** %3, align 8, !invariant.load !18, !dereferenceable !19
%4 = bitcast i8** %.valueWitnesses to %swift.vwtable*
%5 = getelementptr inbounds %swift.vwtable, %swift.vwtable* %4, i32 0, i32 8
%size = load i64, i64* %5, align 8, !invariant.load !18
%6 = alloca i8, i64 %size, align 16
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %6)
%7 = bitcast i8* %6 to %swift.opaque*
store i8* %6, i8** %p.debug, align 8
call swiftcc void @"$s1c5makePQryF"(%swift.opaque* noalias nocapture sret(%swift.opaque) %7)
%8 = call swiftcc i8** @swift_getOpaqueTypeConformance(i8* undef, %swift.type_descriptor* @"$s1c5makePQryFQOMQ", i64 1) #8
%9 = getelementptr inbounds i8*, i8** %8, i32 1
%10 = load i8*, i8** %9, align 8, !invariant.load !18
%11 = bitcast i8* %10 to i64 (%swift.opaque*, %swift.type*, i8**)*
%12 = call swiftcc i64 %11(%swift.opaque* noalias nocapture swiftself %7, %swift.type* %1, i8** %8)
%13 = getelementptr inbounds i8*, i8** %.valueWitnesses, i32 1
%14 = load i8*, i8** %13, align 8, !invariant.load !18
%destroy = bitcast i8* %14 to void (%swift.opaque*, %swift.type*)*
call void %destroy(%swift.opaque* noalias %7, %swift.type* %1) #9
%15 = bitcast %swift.opaque* %7 to i8*
call void @llvm.lifetime.end.p0i8(i64 -1, i8* %15)
ret void
}
VWTのdestroyでローカル変数を削除する
[.code-highlight: 23-26]
define hidden swiftcc void @"$s1b4mainyyF"() #0 {
entry:
%p.debug = alloca i8*, align 8
%0 = bitcast i8** %p.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %0, i8 0, i64 8, i1 false)
%1 = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s1c5makePQryFQOyQo_MD") #7
%2 = bitcast %swift.type* %1 to i8***
%3 = getelementptr inbounds i8**, i8*** %2, i64 -1
%.valueWitnesses = load i8**, i8*** %3, align 8, !invariant.load !18, !dereferenceable !19
%4 = bitcast i8** %.valueWitnesses to %swift.vwtable*
%5 = getelementptr inbounds %swift.vwtable, %swift.vwtable* %4, i32 0, i32 8
%size = load i64, i64* %5, align 8, !invariant.load !18
%6 = alloca i8, i64 %size, align 16
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %6)
%7 = bitcast i8* %6 to %swift.opaque*
store i8* %6, i8** %p.debug, align 8
call swiftcc void @"$s1c5makePQryF"(%swift.opaque* noalias nocapture sret(%swift.opaque) %7)
%8 = call swiftcc i8** @swift_getOpaqueTypeConformance(i8* undef, %swift.type_descriptor* @"$s1c5makePQryFQOMQ", i64 1) #8
%9 = getelementptr inbounds i8*, i8** %8, i32 1
%10 = load i8*, i8** %9, align 8, !invariant.load !18
%11 = bitcast i8* %10 to i64 (%swift.opaque*, %swift.type*, i8**)*
%12 = call swiftcc i64 %11(%swift.opaque* noalias nocapture swiftself %7, %swift.type* %1, i8** %8)
%13 = getelementptr inbounds i8*, i8** %.valueWitnesses, i32 1
%14 = load i8*, i8** %13, align 8, !invariant.load !18
%destroy = bitcast i8* %14 to void (%swift.opaque*, %swift.type*)*
call void %destroy(%swift.opaque* noalias %7, %swift.type* %1) #9
%15 = bitcast %swift.opaque* %7 to i8*
call void @llvm.lifetime.end.p0i8(i64 -1, i8* %15)
ret void
}
__swift_instantiateConcreteTypeFromMangledName
は swift_getTypeByMangledNameInContext
のキャッシュ付きラッパー。
define linkonce_odr hidden %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* %0) #1 {
entry:
%1 = bitcast { i32, i32 }* %0 to i64*
%2 = load atomic i64, i64* %1 monotonic, align 8
%3 = icmp slt i64 %2, 0
%4 = call i1 @llvm.expect.i1(i1 %3, i1 false)
br i1 %4, label %8, label %5
5: ; preds = %8, %entry
%6 = phi i64 [ %2, %entry ], [ %17, %8 ]
%7 = inttoptr i64 %6 to %swift.type*
ret %swift.type* %7
8: ; preds = %entry
%9 = ashr i64 %2, 32
%10 = sub i64 0, %9
%11 = trunc i64 %2 to i32
%12 = sext i32 %11 to i64
%13 = ptrtoint { i32, i32 }* %0 to i64
%14 = add i64 %13, %12
%15 = inttoptr i64 %14 to i8*
%16 = call swiftcc %swift.type* @swift_getTypeByMangledNameInContext(i8* %15, i64 %10, %swift.type_descriptor* null, i8** null) #7
%17 = ptrtoint %swift.type* %16 to i64
store atomic i64 %17, i64* %1 monotonic, align 8
br label %5
}
- インターフェースはGenericsと同じopaque pointerを使うが、真の型やPWTは渡さない。
- ORTの真の型とPWTは、そのdescriptorをランタイム関数に渡すことで、呼び出し側で取得できるようになっている。
protocol P {}
func useP(_ p: any P) {}
Existentialの型名が any P
になった事で、<T: P>
と別の概念であることが直感的にわかりやすくなる
func useAny(_ a: Any) {}
func useAnyObject(_ a: AnyObject) {}
すでに名前に Any
の文字が付いていてわかりやすい
func useMetatype(_ p: any P.Type) {}
useMetatype(S.self)
P
に準拠する型のメタタイプの型は any P.Type
と表記する。
any
は P.Type
に対してかかっている。
従来は P.Type
と書いていた。
func useExistentialMetatype(_ p: (any P).Type) {}
useExistentialMetatype((any P).self)
Existential Containerのメタタイプは (any P).Type
と表記する。
値は (any P).self
で生成できる。
従来な P.Protocol
と P.self
と書いていた。
func useExistential(_ e: any P & Q) {}
func useMetatype(_ t: any (P & Q).Type) {}
func useExistentialMetatype(_ t: (any P & Q).Type) {}
useExistential(S())
useMetatype(S.self)
useExistentialMetatype((any P & Q).self)
protocol P {
associatedtype A
}
func useP(_ p: any P) {}
あらゆるプロトコルが Existential を構成できるようになった
protocol P {
associatedtype A
func a() -> A
func useA(_ a: A)
}
func useP(_ p: any P) {
// ok
p.a()
// error: member 'useA' cannot be used on value of type 'any P';
// consider using a generic constraint instead
p.useA(1)
}
protocol P {
func p() -> Self
func useP(_ p: Self)
}
func useP(_ p: any P) {
// ok
p.p()
// error: member 'useP' cannot be used on value of type 'any P';
// consider using a generic constraint instead
p.useP(p)
}
protocol BP {}
protocol P {
associatedtype A
associatedtype B: BP
func p() -> Self
func a() -> A
func b() -> B
}
func useP(_ p: any P) {
let p2: any P = p.p()
let a: Any = p.a()
let b: any BP = p.b()
}
この upper boundなexistential型の生成は全く新しいロジック
protocol P {
func passSelf(_ f: (Self) -> Void)
}
func useP(_ p: any P) {
p.passSelf { (p: any P) in
}
}
protocol P {
associatedtype A
func a() -> A
func useA(_ a: A)
}
protocol Q: P where Self.A == Int {}
func useQ(q: any Q) {
let a: Int = q.a()
q.useA(1)
}
protocol P {
associatedtype A
}
class C: P {
typealias A = Int
}
protocol Q: P {
func a() -> A
func useA(_ a: A)
}
func useQ(q: any Q & C) {
let a: Int = q.a()
q.useA(1)
}
protocol BP {}
protocol P {
associatedtype A
associatedtype B: BP
func p() -> Self
func a() -> A
func b() -> B
}
func callP(_ p: any P) -> any P {
p.p()
}
Existential Containerの形は特に変わらない
%T1d1PP = type { [24 x i8], %swift.type*, i8** }
define hidden swiftcc void @"$s1d5callPyAA1P_pAaC_pF"(
%T1d1PP* noalias nocapture sret(%T1d1PP) %0,
%T1d1PP* noalias nocapture dereferenceable(40) %1
) #0 {
entry:
%p.debug = alloca %T1d1PP*, align 8
%2 = bitcast %T1d1PP** %p.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %2, i8 0, i64 8, i1 false)
store %T1d1PP* %1, %T1d1PP** %p.debug, align 8
%3 = getelementptr inbounds %T1d1PP, %T1d1PP* %1, i32 0, i32 1
%4 = load %swift.type*, %swift.type** %3, align 8
%5 = getelementptr inbounds %T1d1PP, %T1d1PP* %1, i32 0, i32 2
%6 = load i8**, i8*** %5, align 8
%7 = bitcast %T1d1PP* %1 to %__opaque_existential_type_1*
%8 = call %swift.opaque* @__swift_project_boxed_opaque_existential_1(%__opaque_existential_type_1* %7, %swift.type* %4) #4
%9 = getelementptr inbounds i8*, i8** %6, i32 4
%10 = load i8*, i8** %9, align 8, !invariant.load !39
%11 = bitcast i8* %10 to void (%swift.opaque*, %swift.opaque*, %swift.type*, i8**)*
%12 = getelementptr inbounds %T1d1PP, %T1d1PP* %0, i32 0, i32 1
store %swift.type* %4, %swift.type** %12, align 8
%13 = getelementptr inbounds %T1d1PP, %T1d1PP* %0, i32 0, i32 2
store i8** %6, i8*** %13, align 8
%14 = getelementptr inbounds %T1d1PP, %T1d1PP* %0, i32 0, i32 0
%15 = getelementptr inbounds %T1d1PP, %T1d1PP* %0, i32 0, i32 0
%16 = bitcast %T1d1PP* %0 to %__opaque_existential_type_1*
%17 = call %swift.opaque* @__swift_allocate_boxed_opaque_existential_1(%__opaque_existential_type_1* %16) #4
call swiftcc void %11(
%swift.opaque* noalias nocapture sret(%swift.opaque) %17,
%swift.opaque* noalias nocapture swiftself %8, %swift.type* %4, i8** %6
)
ret void
}
引数のopenとwitnessメソッド取り出し
[.code-highlight: 3, 10-18]
define hidden swiftcc void @"$s1d5callPyAA1P_pAaC_pF"(
%T1d1PP* noalias nocapture sret(%T1d1PP) %0,
%T1d1PP* noalias nocapture dereferenceable(40) %1
) #0 {
entry:
%p.debug = alloca %T1d1PP*, align 8
%2 = bitcast %T1d1PP** %p.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %2, i8 0, i64 8, i1 false)
store %T1d1PP* %1, %T1d1PP** %p.debug, align 8
%3 = getelementptr inbounds %T1d1PP, %T1d1PP* %1, i32 0, i32 1
%4 = load %swift.type*, %swift.type** %3, align 8
%5 = getelementptr inbounds %T1d1PP, %T1d1PP* %1, i32 0, i32 2
%6 = load i8**, i8*** %5, align 8
%7 = bitcast %T1d1PP* %1 to %__opaque_existential_type_1*
%8 = call %swift.opaque* @__swift_project_boxed_opaque_existential_1(%__opaque_existential_type_1* %7, %swift.type* %4) #4
%9 = getelementptr inbounds i8*, i8** %6, i32 4
%10 = load i8*, i8** %9, align 8, !invariant.load !39
%11 = bitcast i8* %10 to void (%swift.opaque*, %swift.opaque*, %swift.type*, i8**)*
%12 = getelementptr inbounds %T1d1PP, %T1d1PP* %0, i32 0, i32 1
store %swift.type* %4, %swift.type** %12, align 8
%13 = getelementptr inbounds %T1d1PP, %T1d1PP* %0, i32 0, i32 2
store i8** %6, i8*** %13, align 8
%14 = getelementptr inbounds %T1d1PP, %T1d1PP* %0, i32 0, i32 0
%15 = getelementptr inbounds %T1d1PP, %T1d1PP* %0, i32 0, i32 0
%16 = bitcast %T1d1PP* %0 to %__opaque_existential_type_1*
%17 = call %swift.opaque* @__swift_allocate_boxed_opaque_existential_1(%__opaque_existential_type_1* %16) #4
call swiftcc void %11(
%swift.opaque* noalias nocapture sret(%swift.opaque) %17,
%swift.opaque* noalias nocapture swiftself %8, %swift.type* %4, i8** %6
)
ret void
}
返り値の any P
への型とwitness tableの書き込み
[.code-highlight: 2, 19-24]
define hidden swiftcc void @"$s1d5callPyAA1P_pAaC_pF"(
%T1d1PP* noalias nocapture sret(%T1d1PP) %0,
%T1d1PP* noalias nocapture dereferenceable(40) %1
) #0 {
entry:
%p.debug = alloca %T1d1PP*, align 8
%2 = bitcast %T1d1PP** %p.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %2, i8 0, i64 8, i1 false)
store %T1d1PP* %1, %T1d1PP** %p.debug, align 8
%3 = getelementptr inbounds %T1d1PP, %T1d1PP* %1, i32 0, i32 1
%4 = load %swift.type*, %swift.type** %3, align 8
%5 = getelementptr inbounds %T1d1PP, %T1d1PP* %1, i32 0, i32 2
%6 = load i8**, i8*** %5, align 8
%7 = bitcast %T1d1PP* %1 to %__opaque_existential_type_1*
%8 = call %swift.opaque* @__swift_project_boxed_opaque_existential_1(%__opaque_existential_type_1* %7, %swift.type* %4) #4
%9 = getelementptr inbounds i8*, i8** %6, i32 4
%10 = load i8*, i8** %9, align 8, !invariant.load !39
%11 = bitcast i8* %10 to void (%swift.opaque*, %swift.opaque*, %swift.type*, i8**)*
%12 = getelementptr inbounds %T1d1PP, %T1d1PP* %0, i32 0, i32 1
store %swift.type* %4, %swift.type** %12, align 8
%13 = getelementptr inbounds %T1d1PP, %T1d1PP* %0, i32 0, i32 2
store i8** %6, i8*** %13, align 8
%14 = getelementptr inbounds %T1d1PP, %T1d1PP* %0, i32 0, i32 0
%15 = getelementptr inbounds %T1d1PP, %T1d1PP* %0, i32 0, i32 0
%16 = bitcast %T1d1PP* %0 to %__opaque_existential_type_1*
%17 = call %swift.opaque* @__swift_allocate_boxed_opaque_existential_1(%__opaque_existential_type_1* %16) #4
call swiftcc void %11(
%swift.opaque* noalias nocapture sret(%swift.opaque) %17,
%swift.opaque* noalias nocapture swiftself %8, %swift.type* %4, i8** %6
)
ret void
}
返り値 any P
の値部分のポインタの取り出し
[.code-highlight: 25-26]
define hidden swiftcc void @"$s1d5callPyAA1P_pAaC_pF"(
%T1d1PP* noalias nocapture sret(%T1d1PP) %0,
%T1d1PP* noalias nocapture dereferenceable(40) %1
) #0 {
entry:
%p.debug = alloca %T1d1PP*, align 8
%2 = bitcast %T1d1PP** %p.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %2, i8 0, i64 8, i1 false)
store %T1d1PP* %1, %T1d1PP** %p.debug, align 8
%3 = getelementptr inbounds %T1d1PP, %T1d1PP* %1, i32 0, i32 1
%4 = load %swift.type*, %swift.type** %3, align 8
%5 = getelementptr inbounds %T1d1PP, %T1d1PP* %1, i32 0, i32 2
%6 = load i8**, i8*** %5, align 8
%7 = bitcast %T1d1PP* %1 to %__opaque_existential_type_1*
%8 = call %swift.opaque* @__swift_project_boxed_opaque_existential_1(%__opaque_existential_type_1* %7, %swift.type* %4) #4
%9 = getelementptr inbounds i8*, i8** %6, i32 4
%10 = load i8*, i8** %9, align 8, !invariant.load !39
%11 = bitcast i8* %10 to void (%swift.opaque*, %swift.opaque*, %swift.type*, i8**)*
%12 = getelementptr inbounds %T1d1PP, %T1d1PP* %0, i32 0, i32 1
store %swift.type* %4, %swift.type** %12, align 8
%13 = getelementptr inbounds %T1d1PP, %T1d1PP* %0, i32 0, i32 2
store i8** %6, i8*** %13, align 8
%14 = getelementptr inbounds %T1d1PP, %T1d1PP* %0, i32 0, i32 0
%15 = getelementptr inbounds %T1d1PP, %T1d1PP* %0, i32 0, i32 0
%16 = bitcast %T1d1PP* %0 to %__opaque_existential_type_1*
%17 = call %swift.opaque* @__swift_allocate_boxed_opaque_existential_1(%__opaque_existential_type_1* %16) #4
call swiftcc void %11(
%swift.opaque* noalias nocapture sret(%swift.opaque) %17,
%swift.opaque* noalias nocapture swiftself %8, %swift.type* %4, i8** %6
)
ret void
}
witnessメソッドのpの呼び出し
[.code-highlight: 27-30, 18, 26, 15, 13, 11]
define hidden swiftcc void @"$s1d5callPyAA1P_pAaC_pF"(
%T1d1PP* noalias nocapture sret(%T1d1PP) %0,
%T1d1PP* noalias nocapture dereferenceable(40) %1
) #0 {
entry:
%p.debug = alloca %T1d1PP*, align 8
%2 = bitcast %T1d1PP** %p.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %2, i8 0, i64 8, i1 false)
store %T1d1PP* %1, %T1d1PP** %p.debug, align 8
%3 = getelementptr inbounds %T1d1PP, %T1d1PP* %1, i32 0, i32 1
%4 = load %swift.type*, %swift.type** %3, align 8
%5 = getelementptr inbounds %T1d1PP, %T1d1PP* %1, i32 0, i32 2
%6 = load i8**, i8*** %5, align 8
%7 = bitcast %T1d1PP* %1 to %__opaque_existential_type_1*
%8 = call %swift.opaque* @__swift_project_boxed_opaque_existential_1(%__opaque_existential_type_1* %7, %swift.type* %4) #4
%9 = getelementptr inbounds i8*, i8** %6, i32 4
%10 = load i8*, i8** %9, align 8, !invariant.load !39
%11 = bitcast i8* %10 to void (%swift.opaque*, %swift.opaque*, %swift.type*, i8**)*
%12 = getelementptr inbounds %T1d1PP, %T1d1PP* %0, i32 0, i32 1
store %swift.type* %4, %swift.type** %12, align 8
%13 = getelementptr inbounds %T1d1PP, %T1d1PP* %0, i32 0, i32 2
store i8** %6, i8*** %13, align 8
%14 = getelementptr inbounds %T1d1PP, %T1d1PP* %0, i32 0, i32 0
%15 = getelementptr inbounds %T1d1PP, %T1d1PP* %0, i32 0, i32 0
%16 = bitcast %T1d1PP* %0 to %__opaque_existential_type_1*
%17 = call %swift.opaque* @__swift_allocate_boxed_opaque_existential_1(%__opaque_existential_type_1* %16) #4
call swiftcc void %11(
%swift.opaque* noalias nocapture sret(%swift.opaque) %17,
%swift.opaque* noalias nocapture swiftself %8, %swift.type* %4, i8** %6
)
ret void
}
func callA(_ p: any P) -> Any {
p.a()
}
define hidden swiftcc void @"$s1d5callAyypAA1P_pF"(
%Any* noalias nocapture sret(%Any) %0,
%T1d1PP* noalias nocapture dereferenceable(40) %1
) #0 {
entry:
%p.debug = alloca %T1d1PP*, align 8
%2 = bitcast %T1d1PP** %p.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %2, i8 0, i64 8, i1 false)
store %T1d1PP* %1, %T1d1PP** %p.debug, align 8
%3 = getelementptr inbounds %T1d1PP, %T1d1PP* %1, i32 0, i32 1
%4 = load %swift.type*, %swift.type** %3, align 8
%5 = getelementptr inbounds %T1d1PP, %T1d1PP* %1, i32 0, i32 2
%6 = load i8**, i8*** %5, align 8
%7 = bitcast %T1d1PP* %1 to %__opaque_existential_type_1*
%8 = call %swift.opaque* @__swift_project_boxed_opaque_existential_1(%__opaque_existential_type_1* %7, %swift.type* %4) #4
%9 = getelementptr inbounds i8*, i8** %6, i32 5
%10 = load i8*, i8** %9, align 8, !invariant.load !39
%11 = bitcast i8* %10 to void (%swift.opaque*, %swift.opaque*, %swift.type*, i8**)*
%12 = call swiftcc %swift.metadata_response @swift_getAssociatedTypeWitness(
i64 0, i8** %6, %swift.type* %4,
%swift.protocol_requirement* getelementptr (
%swift.protocol_requirement, %swift.protocol_requirement* getelementptr inbounds (
<{ ... }>, <{ ... }>* @"$s1d1PMp", i32 0, i32 9
), i32 -1
),
%swift.protocol_requirement* getelementptr inbounds (
<{ ... }>, <{ ... }>* @"$s1d1PMp", i32 0, i32 10
)
) #9
%13 = extractvalue %swift.metadata_response %12, 0
%14 = getelementptr inbounds %Any, %Any* %0, i32 0, i32 1
store %swift.type* %13, %swift.type** %14, align 8
%15 = getelementptr inbounds %Any, %Any* %0, i32 0, i32 0
%16 = getelementptr inbounds %Any, %Any* %0, i32 0, i32 0
%17 = bitcast %Any* %0 to %__opaque_existential_type_0*
%18 = call %swift.opaque* @__swift_allocate_boxed_opaque_existential_0(%__opaque_existential_type_0* %17) #4
call swiftcc void %11(%swift.opaque* noalias nocapture sret(%swift.opaque) %18, %swift.opaque* noalias nocapture swiftself %8, %swift.type* %4, i8** %6)
ret void
}
返り値の Any
は witness table を持たないexistentialの形をしている
[.code-highlight: 1, 4]
%Any = type { [24 x i8], %swift.type* }
define hidden swiftcc void @"$s1d5callAyypAA1P_pF"(
%Any* noalias nocapture sret(%Any) %0,
%T1d1PP* noalias nocapture dereferenceable(40) %1
) #0 {
entry:
%p.debug = alloca %T1d1PP*, align 8
%2 = bitcast %T1d1PP** %p.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %2, i8 0, i64 8, i1 false)
store %T1d1PP* %1, %T1d1PP** %p.debug, align 8
%3 = getelementptr inbounds %T1d1PP, %T1d1PP* %1, i32 0, i32 1
%4 = load %swift.type*, %swift.type** %3, align 8
%5 = getelementptr inbounds %T1d1PP, %T1d1PP* %1, i32 0, i32 2
%6 = load i8**, i8*** %5, align 8
%7 = bitcast %T1d1PP* %1 to %__opaque_existential_type_1*
%8 = call %swift.opaque* @__swift_project_boxed_opaque_existential_1(%__opaque_existential_type_1* %7, %swift.type* %4) #4
%9 = getelementptr inbounds i8*, i8** %6, i32 5
%10 = load i8*, i8** %9, align 8, !invariant.load !39
%11 = bitcast i8* %10 to void (%swift.opaque*, %swift.opaque*, %swift.type*, i8**)*
%12 = call swiftcc %swift.metadata_response @swift_getAssociatedTypeWitness(
i64 0, i8** %6, %swift.type* %4,
%swift.protocol_requirement* getelementptr (
%swift.protocol_requirement, %swift.protocol_requirement* getelementptr inbounds (
<{ ... }>, <{ ... }>* @"$s1d1PMp", i32 0, i32 9
), i32 -1
),
%swift.protocol_requirement* getelementptr inbounds (
<{ ... }>, <{ ... }>* @"$s1d1PMp", i32 0, i32 10
)
) #9
%13 = extractvalue %swift.metadata_response %12, 0
%14 = getelementptr inbounds %Any, %Any* %0, i32 0, i32 1
store %swift.type* %13, %swift.type** %14, align 8
%15 = getelementptr inbounds %Any, %Any* %0, i32 0, i32 0
%16 = getelementptr inbounds %Any, %Any* %0, i32 0, i32 0
%17 = bitcast %Any* %0 to %__opaque_existential_type_0*
%18 = call %swift.opaque* @__swift_allocate_boxed_opaque_existential_0(%__opaque_existential_type_0* %17) #4
call swiftcc void %11(%swift.opaque* noalias nocapture sret(%swift.opaque) %18, %swift.opaque* noalias nocapture swiftself %8, %swift.type* %4, i8** %6)
ret void
}
引数の any P
から真の型とWTの取り出し
[.code-highlight: 3, 10-13]
define hidden swiftcc void @"$s1d5callAyypAA1P_pF"(
%Any* noalias nocapture sret(%Any) %0,
%T1d1PP* noalias nocapture dereferenceable(40) %1
) #0 {
entry:
%p.debug = alloca %T1d1PP*, align 8
%2 = bitcast %T1d1PP** %p.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %2, i8 0, i64 8, i1 false)
store %T1d1PP* %1, %T1d1PP** %p.debug, align 8
%3 = getelementptr inbounds %T1d1PP, %T1d1PP* %1, i32 0, i32 1
%4 = load %swift.type*, %swift.type** %3, align 8
%5 = getelementptr inbounds %T1d1PP, %T1d1PP* %1, i32 0, i32 2
%6 = load i8**, i8*** %5, align 8
%7 = bitcast %T1d1PP* %1 to %__opaque_existential_type_1*
%8 = call %swift.opaque* @__swift_project_boxed_opaque_existential_1(%__opaque_existential_type_1* %7, %swift.type* %4) #4
%9 = getelementptr inbounds i8*, i8** %6, i32 5
%10 = load i8*, i8** %9, align 8, !invariant.load !39
%11 = bitcast i8* %10 to void (%swift.opaque*, %swift.opaque*, %swift.type*, i8**)*
%12 = call swiftcc %swift.metadata_response @swift_getAssociatedTypeWitness(
i64 0, i8** %6, %swift.type* %4,
%swift.protocol_requirement* getelementptr (
%swift.protocol_requirement, %swift.protocol_requirement* getelementptr inbounds (
<{ ... }>, <{ ... }>* @"$s1d1PMp", i32 0, i32 9
), i32 -1
),
%swift.protocol_requirement* getelementptr inbounds (
<{ ... }>, <{ ... }>* @"$s1d1PMp", i32 0, i32 10
)
) #9
%13 = extractvalue %swift.metadata_response %12, 0
%14 = getelementptr inbounds %Any, %Any* %0, i32 0, i32 1
store %swift.type* %13, %swift.type** %14, align 8
%15 = getelementptr inbounds %Any, %Any* %0, i32 0, i32 0
%16 = getelementptr inbounds %Any, %Any* %0, i32 0, i32 0
%17 = bitcast %Any* %0 to %__opaque_existential_type_0*
%18 = call %swift.opaque* @__swift_allocate_boxed_opaque_existential_0(%__opaque_existential_type_0* %17) #4
call swiftcc void %11(%swift.opaque* noalias nocapture sret(%swift.opaque) %18, %swift.opaque* noalias nocapture swiftself %8, %swift.type* %4, i8** %6)
ret void
}
ランタイム関数で associatedtype A の真の型を取り出し
[.code-highlight: 11, 13, 19-30]
define hidden swiftcc void @"$s1d5callAyypAA1P_pF"(
%Any* noalias nocapture sret(%Any) %0,
%T1d1PP* noalias nocapture dereferenceable(40) %1
) #0 {
entry:
%p.debug = alloca %T1d1PP*, align 8
%2 = bitcast %T1d1PP** %p.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %2, i8 0, i64 8, i1 false)
store %T1d1PP* %1, %T1d1PP** %p.debug, align 8
%3 = getelementptr inbounds %T1d1PP, %T1d1PP* %1, i32 0, i32 1
%4 = load %swift.type*, %swift.type** %3, align 8
%5 = getelementptr inbounds %T1d1PP, %T1d1PP* %1, i32 0, i32 2
%6 = load i8**, i8*** %5, align 8
%7 = bitcast %T1d1PP* %1 to %__opaque_existential_type_1*
%8 = call %swift.opaque* @__swift_project_boxed_opaque_existential_1(%__opaque_existential_type_1* %7, %swift.type* %4) #4
%9 = getelementptr inbounds i8*, i8** %6, i32 5
%10 = load i8*, i8** %9, align 8, !invariant.load !39
%11 = bitcast i8* %10 to void (%swift.opaque*, %swift.opaque*, %swift.type*, i8**)*
%12 = call swiftcc %swift.metadata_response @swift_getAssociatedTypeWitness(
i64 0, i8** %6, %swift.type* %4,
%swift.protocol_requirement* getelementptr (
%swift.protocol_requirement, %swift.protocol_requirement* getelementptr inbounds (
<{ ... }>, <{ ... }>* @"$s1d1PMp", i32 0, i32 9
), i32 -1
),
%swift.protocol_requirement* getelementptr inbounds (
<{ ... }>, <{ ... }>* @"$s1d1PMp", i32 0, i32 10
)
) #9
%13 = extractvalue %swift.metadata_response %12, 0
%14 = getelementptr inbounds %Any, %Any* %0, i32 0, i32 1
store %swift.type* %13, %swift.type** %14, align 8
%15 = getelementptr inbounds %Any, %Any* %0, i32 0, i32 0
%16 = getelementptr inbounds %Any, %Any* %0, i32 0, i32 0
%17 = bitcast %Any* %0 to %__opaque_existential_type_0*
%18 = call %swift.opaque* @__swift_allocate_boxed_opaque_existential_0(%__opaque_existential_type_0* %17) #4
call swiftcc void %11(%swift.opaque* noalias nocapture sret(%swift.opaque) %18, %swift.opaque* noalias nocapture swiftself %8, %swift.type* %4, i8** %6)
ret void
}
取り出した型を返り値の型としてセット、他同様
[.code-highlight: 30-32]
define hidden swiftcc void @"$s1d5callAyypAA1P_pF"(
%Any* noalias nocapture sret(%Any) %0,
%T1d1PP* noalias nocapture dereferenceable(40) %1
) #0 {
entry:
%p.debug = alloca %T1d1PP*, align 8
%2 = bitcast %T1d1PP** %p.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %2, i8 0, i64 8, i1 false)
store %T1d1PP* %1, %T1d1PP** %p.debug, align 8
%3 = getelementptr inbounds %T1d1PP, %T1d1PP* %1, i32 0, i32 1
%4 = load %swift.type*, %swift.type** %3, align 8
%5 = getelementptr inbounds %T1d1PP, %T1d1PP* %1, i32 0, i32 2
%6 = load i8**, i8*** %5, align 8
%7 = bitcast %T1d1PP* %1 to %__opaque_existential_type_1*
%8 = call %swift.opaque* @__swift_project_boxed_opaque_existential_1(%__opaque_existential_type_1* %7, %swift.type* %4) #4
%9 = getelementptr inbounds i8*, i8** %6, i32 5
%10 = load i8*, i8** %9, align 8, !invariant.load !39
%11 = bitcast i8* %10 to void (%swift.opaque*, %swift.opaque*, %swift.type*, i8**)*
%12 = call swiftcc %swift.metadata_response @swift_getAssociatedTypeWitness(
i64 0, i8** %6, %swift.type* %4,
%swift.protocol_requirement* getelementptr (
%swift.protocol_requirement, %swift.protocol_requirement* getelementptr inbounds (
<{ ... }>, <{ ... }>* @"$s1d1PMp", i32 0, i32 9
), i32 -1
),
%swift.protocol_requirement* getelementptr inbounds (
<{ ... }>, <{ ... }>* @"$s1d1PMp", i32 0, i32 10
)
) #9
%13 = extractvalue %swift.metadata_response %12, 0
%14 = getelementptr inbounds %Any, %Any* %0, i32 0, i32 1
store %swift.type* %13, %swift.type** %14, align 8
%15 = getelementptr inbounds %Any, %Any* %0, i32 0, i32 0
%16 = getelementptr inbounds %Any, %Any* %0, i32 0, i32 0
%17 = bitcast %Any* %0 to %__opaque_existential_type_0*
%18 = call %swift.opaque* @__swift_allocate_boxed_opaque_existential_0(%__opaque_existential_type_0* %17) #4
call swiftcc void %11(%swift.opaque* noalias nocapture sret(%swift.opaque) %18, %swift.opaque* noalias nocapture swiftself %8, %swift.type* %4, i8** %6)
ret void
}
func callB(_ p: any P) -> any BP {
p.b()
}
define hidden swiftcc void @"$s1d5callByAA2BP_pAA1P_pF"(
%T1d2BPP* noalias nocapture sret(%T1d2BPP) %0,
%T1d1PP* noalias nocapture dereferenceable(40) %1) #0 {
entry:
%p.debug = alloca %T1d1PP*, align 8
%2 = bitcast %T1d1PP** %p.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %2, i8 0, i64 8, i1 false)
store %T1d1PP* %1, %T1d1PP** %p.debug, align 8
%3 = getelementptr inbounds %T1d1PP, %T1d1PP* %1, i32 0, i32 1
%4 = load %swift.type*, %swift.type** %3, align 8
%5 = getelementptr inbounds %T1d1PP, %T1d1PP* %1, i32 0, i32 2
%6 = load i8**, i8*** %5, align 8
%7 = bitcast %T1d1PP* %1 to %__opaque_existential_type_1*
%8 = call %swift.opaque* @__swift_project_boxed_opaque_existential_1(%__opaque_existential_type_1* %7, %swift.type* %4) #4
%9 = getelementptr inbounds i8*, i8** %6, i32 6
%10 = load i8*, i8** %9, align 8, !invariant.load !39
%11 = bitcast i8* %10 to void (%swift.opaque*, %swift.opaque*, %swift.type*, i8**)*
%12 = call swiftcc %swift.metadata_response @swift_getAssociatedTypeWitness(
i64 0, i8** %6, %swift.type* %4,
%swift.protocol_requirement* getelementptr (
%swift.protocol_requirement, %swift.protocol_requirement* getelementptr inbounds (
<{ ... }>, <{ ... }>* @"$s1d1PMp", i32 0, i32 9
),
i32 -1
),
%swift.protocol_requirement* getelementptr inbounds (
<{ ... }>, <{ ... }>* @"$s1d1PMp", i32 0, i32 11
)
) #9
%13 = extractvalue %swift.metadata_response %12, 0
%14 = getelementptr inbounds %T1d2BPP, %T1d2BPP* %0, i32 0, i32 1
store %swift.type* %13, %swift.type** %14, align 8
%15 = call swiftcc i8** @swift_getAssociatedConformanceWitness(
i8** %6, %swift.type* %4, %swift.type* %13,
%swift.protocol_requirement* getelementptr (
%swift.protocol_requirement, %swift.protocol_requirement* getelementptr inbounds (
<{ ... }>, <{ ... }>* @"$s1d1PMp", i32 0, i32 9
),
i32 -1
),
%swift.protocol_requirement* getelementptr inbounds (
<{ ... }>, <{ ... }>* @"$s1d1PMp", i32 0, i32 9
)
) #9
%16 = getelementptr inbounds %T1d2BPP, %T1d2BPP* %0, i32 0, i32 2
store i8** %15, i8*** %16, align 8
%17 = getelementptr inbounds %T1d2BPP, %T1d2BPP* %0, i32 0, i32 0
%18 = getelementptr inbounds %T1d2BPP, %T1d2BPP* %0, i32 0, i32 0
%19 = bitcast %T1d2BPP* %0 to %__opaque_existential_type_1*
%20 = call %swift.opaque* @__swift_allocate_boxed_opaque_existential_1(%__opaque_existential_type_1* %19) #4
call swiftcc void %11(
%swift.opaque* noalias nocapture sret(%swift.opaque) %20,
%swift.opaque* noalias nocapture swiftself %8, %swift.type* %4, i8** %6
)
ret void
}
ランタイム関数で associatedtype B の真の型の取り出し
[.code-highlight: 18-29]
define hidden swiftcc void @"$s1d5callByAA2BP_pAA1P_pF"(
%T1d2BPP* noalias nocapture sret(%T1d2BPP) %0,
%T1d1PP* noalias nocapture dereferenceable(40) %1) #0 {
entry:
%p.debug = alloca %T1d1PP*, align 8
%2 = bitcast %T1d1PP** %p.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %2, i8 0, i64 8, i1 false)
store %T1d1PP* %1, %T1d1PP** %p.debug, align 8
%3 = getelementptr inbounds %T1d1PP, %T1d1PP* %1, i32 0, i32 1
%4 = load %swift.type*, %swift.type** %3, align 8
%5 = getelementptr inbounds %T1d1PP, %T1d1PP* %1, i32 0, i32 2
%6 = load i8**, i8*** %5, align 8
%7 = bitcast %T1d1PP* %1 to %__opaque_existential_type_1*
%8 = call %swift.opaque* @__swift_project_boxed_opaque_existential_1(%__opaque_existential_type_1* %7, %swift.type* %4) #4
%9 = getelementptr inbounds i8*, i8** %6, i32 6
%10 = load i8*, i8** %9, align 8, !invariant.load !39
%11 = bitcast i8* %10 to void (%swift.opaque*, %swift.opaque*, %swift.type*, i8**)*
%12 = call swiftcc %swift.metadata_response @swift_getAssociatedTypeWitness(
i64 0, i8** %6, %swift.type* %4,
%swift.protocol_requirement* getelementptr (
%swift.protocol_requirement, %swift.protocol_requirement* getelementptr inbounds (
<{ ... }>, <{ ... }>* @"$s1d1PMp", i32 0, i32 9
),
i32 -1
),
%swift.protocol_requirement* getelementptr inbounds (
<{ ... }>, <{ ... }>* @"$s1d1PMp", i32 0, i32 11
)
) #9
%13 = extractvalue %swift.metadata_response %12, 0
%14 = getelementptr inbounds %T1d2BPP, %T1d2BPP* %0, i32 0, i32 1
store %swift.type* %13, %swift.type** %14, align 8
%15 = call swiftcc i8** @swift_getAssociatedConformanceWitness(
i8** %6, %swift.type* %4, %swift.type* %13,
%swift.protocol_requirement* getelementptr (
%swift.protocol_requirement, %swift.protocol_requirement* getelementptr inbounds (
<{ ... }>, <{ ... }>* @"$s1d1PMp", i32 0, i32 9
),
i32 -1
),
%swift.protocol_requirement* getelementptr inbounds (
<{ ... }>, <{ ... }>* @"$s1d1PMp", i32 0, i32 9
)
) #9
%16 = getelementptr inbounds %T1d2BPP, %T1d2BPP* %0, i32 0, i32 2
store i8** %15, i8*** %16, align 8
%17 = getelementptr inbounds %T1d2BPP, %T1d2BPP* %0, i32 0, i32 0
%18 = getelementptr inbounds %T1d2BPP, %T1d2BPP* %0, i32 0, i32 0
%19 = bitcast %T1d2BPP* %0 to %__opaque_existential_type_1*
%20 = call %swift.opaque* @__swift_allocate_boxed_opaque_existential_1(%__opaque_existential_type_1* %19) #4
call swiftcc void %11(
%swift.opaque* noalias nocapture sret(%swift.opaque) %20,
%swift.opaque* noalias nocapture swiftself %8, %swift.type* %4, i8** %6
)
ret void
}
ランタイム関数で associatedtype B の PB の PWT を取り出し、以下同様
[.code-highlight: 33-44]
define hidden swiftcc void @"$s1d5callByAA2BP_pAA1P_pF"(
%T1d2BPP* noalias nocapture sret(%T1d2BPP) %0,
%T1d1PP* noalias nocapture dereferenceable(40) %1) #0 {
entry:
%p.debug = alloca %T1d1PP*, align 8
%2 = bitcast %T1d1PP** %p.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %2, i8 0, i64 8, i1 false)
store %T1d1PP* %1, %T1d1PP** %p.debug, align 8
%3 = getelementptr inbounds %T1d1PP, %T1d1PP* %1, i32 0, i32 1
%4 = load %swift.type*, %swift.type** %3, align 8
%5 = getelementptr inbounds %T1d1PP, %T1d1PP* %1, i32 0, i32 2
%6 = load i8**, i8*** %5, align 8
%7 = bitcast %T1d1PP* %1 to %__opaque_existential_type_1*
%8 = call %swift.opaque* @__swift_project_boxed_opaque_existential_1(%__opaque_existential_type_1* %7, %swift.type* %4) #4
%9 = getelementptr inbounds i8*, i8** %6, i32 6
%10 = load i8*, i8** %9, align 8, !invariant.load !39
%11 = bitcast i8* %10 to void (%swift.opaque*, %swift.opaque*, %swift.type*, i8**)*
%12 = call swiftcc %swift.metadata_response @swift_getAssociatedTypeWitness(
i64 0, i8** %6, %swift.type* %4,
%swift.protocol_requirement* getelementptr (
%swift.protocol_requirement, %swift.protocol_requirement* getelementptr inbounds (
<{ ... }>, <{ ... }>* @"$s1d1PMp", i32 0, i32 9
),
i32 -1
),
%swift.protocol_requirement* getelementptr inbounds (
<{ ... }>, <{ ... }>* @"$s1d1PMp", i32 0, i32 11
)
) #9
%13 = extractvalue %swift.metadata_response %12, 0
%14 = getelementptr inbounds %T1d2BPP, %T1d2BPP* %0, i32 0, i32 1
store %swift.type* %13, %swift.type** %14, align 8
%15 = call swiftcc i8** @swift_getAssociatedConformanceWitness(
i8** %6, %swift.type* %4, %swift.type* %13,
%swift.protocol_requirement* getelementptr (
%swift.protocol_requirement, %swift.protocol_requirement* getelementptr inbounds (
<{ ... }>, <{ ... }>* @"$s1d1PMp", i32 0, i32 9
),
i32 -1
),
%swift.protocol_requirement* getelementptr inbounds (
<{ ... }>, <{ ... }>* @"$s1d1PMp", i32 0, i32 9
)
) #9
%16 = getelementptr inbounds %T1d2BPP, %T1d2BPP* %0, i32 0, i32 2
store i8** %15, i8*** %16, align 8
%17 = getelementptr inbounds %T1d2BPP, %T1d2BPP* %0, i32 0, i32 0
%18 = getelementptr inbounds %T1d2BPP, %T1d2BPP* %0, i32 0, i32 0
%19 = bitcast %T1d2BPP* %0 to %__opaque_existential_type_1*
%20 = call %swift.opaque* @__swift_allocate_boxed_opaque_existential_1(%__opaque_existential_type_1* %19) #4
call swiftcc void %11(
%swift.opaque* noalias nocapture sret(%swift.opaque) %20,
%swift.opaque* noalias nocapture swiftself %8, %swift.type* %4, i8** %6
)
ret void
}
- どんなprotocolでもexistentialに使えるようになった
- 困るvarianceのメンバは使用不能にした
- covarianceではupper boundに包んだ
- existentialの型の部分を先に埋めると、値の部分は通常のGenericsとABI互換性がある
- associated typeの情報はランタイム関数で取り出せる
func ortOptional() -> (some P)? { S() }
func ortTuple() -> (some P, some Q) { (S(), S()) }
func ortArray() -> [some P] { [S(), S()] }
func ortGeneric() -> C<some P> { C<S>() }
some
が返り値の型パラメータ部分で使える
func ortArray() -> [some P] { ... }
// 気持ち
func ortArray() -> <T: P> [T] { ... }
配列であれば、要素の型は全て同一。
実装漏れ13
func ortFunc() -> () -> some P { { S() } }
提案書によるとこれもできるはずらしい
func ortFuncParam() -> (some P) -> () { ... }
caller側で取得した関数が受け取る some P
を作る方法が無い。14
func ortTuple() -> (some P, some Q) { (S(), S()) }
func main() {
let t = ortTuple()
}
SILを見ておく
// ortTuple()
sil @$s1e8ortTupleQr_QR_tyF : $@convention(thin) @substituted <τ_0_0, τ_0_1> ()
-> (@out τ_0_0, @out τ_0_1) for <
@_opaqueReturnTypeOf("$s1e8ortTupleQr_QR_tyF", 0) __,
@_opaqueReturnTypeOf("$s1e8ortTupleQr_QR_tyF", 1) __
>
{
...
}
define hidden swiftcc void @"$s1f4mainyyF"() #0 {
entry:
%t.debug = alloca i8*, align 8
%0 = bitcast i8** %t.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %0, i8 0, i64 8, i1 false)
%1 = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName(
{ i32, i32 }* @"$s1e8ortTupleQr_QR_tyFQOyQo__AaBQr_QR_tyFQOyQo0_tMD"
) #8
%2 = bitcast %swift.type* %1 to i8***
%3 = getelementptr inbounds i8**, i8*** %2, i64 -1
%.valueWitnesses = load i8**, i8*** %3, align 8, !invariant.load !19, !dereferenceable !20
%4 = bitcast i8** %.valueWitnesses to %swift.vwtable*
%5 = getelementptr inbounds %swift.vwtable, %swift.vwtable* %4, i32 0, i32 8
%size = load i64, i64* %5, align 8, !invariant.load !19
%t = alloca i8, i64 %size, align 16
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %t)
%6 = bitcast i8* %t to <{}>*
store i8* %t, i8** %t.debug, align 8
%.elt = bitcast <{}>* %6 to %swift.opaque*
%7 = bitcast %swift.type* %1 to %swift.tuple_type*
%8 = getelementptr inbounds %swift.tuple_type, %swift.tuple_type* %7, i64 0, i32 3, i64 1, i32 1
%.1.offset = load i32, i32* %8, align 8
%9 = bitcast <{}>* %6 to i8*
%10 = getelementptr inbounds i8, i8* %9, i32 %.1.offset
%.elt1 = bitcast i8* %10 to %swift.opaque*
call swiftcc void @"$s1e8ortTupleQr_QR_tyF"(%swift.opaque* noalias nocapture %.elt, %swift.opaque* noalias nocapture %.elt1)
%11 = call <{}>* @"$s1e8ortTupleQr_QR_tyFQOyQo__AaBQr_QR_tyFQOyQo0_tWOh"(<{}>* %6)
%12 = bitcast <{}>* %6 to i8*
call void @llvm.lifetime.end.p0i8(i64 -1, i8* %12)
ret void
}
返り値のメタタイプを取得
[.code-highlight: 1-5, 12-14]
; $s1e8ortTupleQr_QR_tyFQOyQo__AaBQr_QR_tyFQOyQo0_tMD --->
; demangling cache variable for type metadata for (
; <<opaque return type of e.ortTuple() -> (some, some)>>.0,
; <<opaque return type of e.ortTuple() -> (some, some)>>.1
; )
define hidden swiftcc void @"$s1f4mainyyF"() #0 {
entry:
%t.debug = alloca i8*, align 8
%0 = bitcast i8** %t.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %0, i8 0, i64 8, i1 false)
%1 = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName(
{ i32, i32 }* @"$s1e8ortTupleQr_QR_tyFQOyQo__AaBQr_QR_tyFQOyQo0_tMD"
) #8
%2 = bitcast %swift.type* %1 to i8***
%3 = getelementptr inbounds i8**, i8*** %2, i64 -1
%.valueWitnesses = load i8**, i8*** %3, align 8, !invariant.load !19, !dereferenceable !20
%4 = bitcast i8** %.valueWitnesses to %swift.vwtable*
%5 = getelementptr inbounds %swift.vwtable, %swift.vwtable* %4, i32 0, i32 8
%size = load i64, i64* %5, align 8, !invariant.load !19
%t = alloca i8, i64 %size, align 16
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %t)
%6 = bitcast i8* %t to <{}>*
store i8* %t, i8** %t.debug, align 8
%.elt = bitcast <{}>* %6 to %swift.opaque*
%7 = bitcast %swift.type* %1 to %swift.tuple_type*
%8 = getelementptr inbounds %swift.tuple_type, %swift.tuple_type* %7, i64 0, i32 3, i64 1, i32 1
%.1.offset = load i32, i32* %8, align 8
%9 = bitcast <{}>* %6 to i8*
%10 = getelementptr inbounds i8, i8* %9, i32 %.1.offset
%.elt1 = bitcast i8* %10 to %swift.opaque*
call swiftcc void @"$s1e8ortTupleQr_QR_tyF"(%swift.opaque* noalias nocapture %.elt, %swift.opaque* noalias nocapture %.elt1)
%11 = call <{}>* @"$s1e8ortTupleQr_QR_tyFQOyQo__AaBQr_QR_tyFQOyQo0_tWOh"(<{}>* %6)
%12 = bitcast <{}>* %6 to i8*
call void @llvm.lifetime.end.p0i8(i64 -1, i8* %12)
ret void
}
VWTを取り出して返り値のタプルのメモリ領域を確保
[.code-highlight: 9-15]
define hidden swiftcc void @"$s1f4mainyyF"() #0 {
entry:
%t.debug = alloca i8*, align 8
%0 = bitcast i8** %t.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %0, i8 0, i64 8, i1 false)
%1 = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName(
{ i32, i32 }* @"$s1e8ortTupleQr_QR_tyFQOyQo__AaBQr_QR_tyFQOyQo0_tMD"
) #8
%2 = bitcast %swift.type* %1 to i8***
%3 = getelementptr inbounds i8**, i8*** %2, i64 -1
%.valueWitnesses = load i8**, i8*** %3, align 8, !invariant.load !19, !dereferenceable !20
%4 = bitcast i8** %.valueWitnesses to %swift.vwtable*
%5 = getelementptr inbounds %swift.vwtable, %swift.vwtable* %4, i32 0, i32 8
%size = load i64, i64* %5, align 8, !invariant.load !19
%t = alloca i8, i64 %size, align 16
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %t)
%6 = bitcast i8* %t to <{}>*
store i8* %t, i8** %t.debug, align 8
%.elt = bitcast <{}>* %6 to %swift.opaque*
%7 = bitcast %swift.type* %1 to %swift.tuple_type*
%8 = getelementptr inbounds %swift.tuple_type, %swift.tuple_type* %7, i64 0, i32 3, i64 1, i32 1
%.1.offset = load i32, i32* %8, align 8
%9 = bitcast <{}>* %6 to i8*
%10 = getelementptr inbounds i8, i8* %9, i32 %.1.offset
%.elt1 = bitcast i8* %10 to %swift.opaque*
call swiftcc void @"$s1e8ortTupleQr_QR_tyF"(%swift.opaque* noalias nocapture %.elt, %swift.opaque* noalias nocapture %.elt1)
%11 = call <{}>* @"$s1e8ortTupleQr_QR_tyFQOyQo__AaBQr_QR_tyFQOyQo0_tWOh"(<{}>* %6)
%12 = bitcast <{}>* %6 to i8*
call void @llvm.lifetime.end.p0i8(i64 -1, i8* %12)
ret void
}
タプルの0番要素のポインタを取得
[.code-highlight: 17, 19]
define hidden swiftcc void @"$s1f4mainyyF"() #0 {
entry:
%t.debug = alloca i8*, align 8
%0 = bitcast i8** %t.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %0, i8 0, i64 8, i1 false)
%1 = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName(
{ i32, i32 }* @"$s1e8ortTupleQr_QR_tyFQOyQo__AaBQr_QR_tyFQOyQo0_tMD"
) #8
%2 = bitcast %swift.type* %1 to i8***
%3 = getelementptr inbounds i8**, i8*** %2, i64 -1
%.valueWitnesses = load i8**, i8*** %3, align 8, !invariant.load !19, !dereferenceable !20
%4 = bitcast i8** %.valueWitnesses to %swift.vwtable*
%5 = getelementptr inbounds %swift.vwtable, %swift.vwtable* %4, i32 0, i32 8
%size = load i64, i64* %5, align 8, !invariant.load !19
%t = alloca i8, i64 %size, align 16
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %t)
%6 = bitcast i8* %t to <{}>*
store i8* %t, i8** %t.debug, align 8
%.elt = bitcast <{}>* %6 to %swift.opaque*
%7 = bitcast %swift.type* %1 to %swift.tuple_type*
%8 = getelementptr inbounds %swift.tuple_type, %swift.tuple_type* %7, i64 0, i32 3, i64 1, i32 1
%.1.offset = load i32, i32* %8, align 8
%9 = bitcast <{}>* %6 to i8*
%10 = getelementptr inbounds i8, i8* %9, i32 %.1.offset
%.elt1 = bitcast i8* %10 to %swift.opaque*
call swiftcc void @"$s1e8ortTupleQr_QR_tyF"(%swift.opaque* noalias nocapture %.elt, %swift.opaque* noalias nocapture %.elt1)
%11 = call <{}>* @"$s1e8ortTupleQr_QR_tyFQOyQo__AaBQr_QR_tyFQOyQo0_tWOh"(<{}>* %6)
%12 = bitcast <{}>* %6 to i8*
call void @llvm.lifetime.end.p0i8(i64 -1, i8* %12)
ret void
}
タプルの1番要素のオフセットを取得して、ポインタを計算
[.code-highlight: 20-25]
define hidden swiftcc void @"$s1f4mainyyF"() #0 {
entry:
%t.debug = alloca i8*, align 8
%0 = bitcast i8** %t.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %0, i8 0, i64 8, i1 false)
%1 = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName(
{ i32, i32 }* @"$s1e8ortTupleQr_QR_tyFQOyQo__AaBQr_QR_tyFQOyQo0_tMD"
) #8
%2 = bitcast %swift.type* %1 to i8***
%3 = getelementptr inbounds i8**, i8*** %2, i64 -1
%.valueWitnesses = load i8**, i8*** %3, align 8, !invariant.load !19, !dereferenceable !20
%4 = bitcast i8** %.valueWitnesses to %swift.vwtable*
%5 = getelementptr inbounds %swift.vwtable, %swift.vwtable* %4, i32 0, i32 8
%size = load i64, i64* %5, align 8, !invariant.load !19
%t = alloca i8, i64 %size, align 16
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %t)
%6 = bitcast i8* %t to <{}>*
store i8* %t, i8** %t.debug, align 8
%.elt = bitcast <{}>* %6 to %swift.opaque*
%7 = bitcast %swift.type* %1 to %swift.tuple_type*
%8 = getelementptr inbounds %swift.tuple_type, %swift.tuple_type* %7, i64 0, i32 3, i64 1, i32 1
%.1.offset = load i32, i32* %8, align 8
%9 = bitcast <{}>* %6 to i8*
%10 = getelementptr inbounds i8, i8* %9, i32 %.1.offset
%.elt1 = bitcast i8* %10 to %swift.opaque*
call swiftcc void @"$s1e8ortTupleQr_QR_tyF"(%swift.opaque* noalias nocapture %.elt, %swift.opaque* noalias nocapture %.elt1)
%11 = call <{}>* @"$s1e8ortTupleQr_QR_tyFQOyQo__AaBQr_QR_tyFQOyQo0_tWOh"(<{}>* %6)
%12 = bitcast <{}>* %6 to i8*
call void @llvm.lifetime.end.p0i8(i64 -1, i8* %12)
ret void
}
タプルの2つの要素のポインタを引数で渡して返り値を取得
[.code-highlight: 19, 25, 26]
define hidden swiftcc void @"$s1f4mainyyF"() #0 {
entry:
%t.debug = alloca i8*, align 8
%0 = bitcast i8** %t.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %0, i8 0, i64 8, i1 false)
%1 = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName(
{ i32, i32 }* @"$s1e8ortTupleQr_QR_tyFQOyQo__AaBQr_QR_tyFQOyQo0_tMD"
) #8
%2 = bitcast %swift.type* %1 to i8***
%3 = getelementptr inbounds i8**, i8*** %2, i64 -1
%.valueWitnesses = load i8**, i8*** %3, align 8, !invariant.load !19, !dereferenceable !20
%4 = bitcast i8** %.valueWitnesses to %swift.vwtable*
%5 = getelementptr inbounds %swift.vwtable, %swift.vwtable* %4, i32 0, i32 8
%size = load i64, i64* %5, align 8, !invariant.load !19
%t = alloca i8, i64 %size, align 16
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %t)
%6 = bitcast i8* %t to <{}>*
store i8* %t, i8** %t.debug, align 8
%.elt = bitcast <{}>* %6 to %swift.opaque*
%7 = bitcast %swift.type* %1 to %swift.tuple_type*
%8 = getelementptr inbounds %swift.tuple_type, %swift.tuple_type* %7, i64 0, i32 3, i64 1, i32 1
%.1.offset = load i32, i32* %8, align 8
%9 = bitcast <{}>* %6 to i8*
%10 = getelementptr inbounds i8, i8* %9, i32 %.1.offset
%.elt1 = bitcast i8* %10 to %swift.opaque*
call swiftcc void @"$s1e8ortTupleQr_QR_tyF"(%swift.opaque* noalias nocapture %.elt, %swift.opaque* noalias nocapture %.elt1)
%11 = call <{}>* @"$s1e8ortTupleQr_QR_tyFQOyQo__AaBQr_QR_tyFQOyQo0_tWOh"(<{}>* %6)
%12 = bitcast <{}>* %6 to i8*
call void @llvm.lifetime.end.p0i8(i64 -1, i8* %12)
ret void
}
取得したタプルを削除
[.code-highlight: 1-5, 33]
; $s1e8ortTupleQr_QR_tyFQOyQo__AaBQr_QR_tyFQOyQo0_tWOh --->
; outlined destroy of (
; <<opaque return type of e.ortTuple() -> (some, some)>>.0,
; <<opaque return type of e.ortTuple() -> (some, some)>>.1
; )
define hidden swiftcc void @"$s1f4mainyyF"() #0 {
entry:
%t.debug = alloca i8*, align 8
%0 = bitcast i8** %t.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %0, i8 0, i64 8, i1 false)
%1 = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName(
{ i32, i32 }* @"$s1e8ortTupleQr_QR_tyFQOyQo__AaBQr_QR_tyFQOyQo0_tMD"
) #8
%2 = bitcast %swift.type* %1 to i8***
%3 = getelementptr inbounds i8**, i8*** %2, i64 -1
%.valueWitnesses = load i8**, i8*** %3, align 8, !invariant.load !19, !dereferenceable !20
%4 = bitcast i8** %.valueWitnesses to %swift.vwtable*
%5 = getelementptr inbounds %swift.vwtable, %swift.vwtable* %4, i32 0, i32 8
%size = load i64, i64* %5, align 8, !invariant.load !19
%t = alloca i8, i64 %size, align 16
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %t)
%6 = bitcast i8* %t to <{}>*
store i8* %t, i8** %t.debug, align 8
%.elt = bitcast <{}>* %6 to %swift.opaque*
%7 = bitcast %swift.type* %1 to %swift.tuple_type*
%8 = getelementptr inbounds %swift.tuple_type, %swift.tuple_type* %7, i64 0, i32 3, i64 1, i32 1
%.1.offset = load i32, i32* %8, align 8
%9 = bitcast <{}>* %6 to i8*
%10 = getelementptr inbounds i8, i8* %9, i32 %.1.offset
%.elt1 = bitcast i8* %10 to %swift.opaque*
call swiftcc void @"$s1e8ortTupleQr_QR_tyF"(%swift.opaque* noalias nocapture %.elt, %swift.opaque* noalias nocapture %.elt1)
%11 = call <{}>* @"$s1e8ortTupleQr_QR_tyFQOyQo__AaBQr_QR_tyFQOyQo0_tWOh"(<{}>* %6)
%12 = bitcast <{}>* %6 to i8*
call void @llvm.lifetime.end.p0i8(i64 -1, i8* %12)
ret void
}
削除関数
define linkonce_odr hidden <{}>* @"$s1e8ortTupleQr_QR_tyFQOyQo__AaBQr_QR_tyFQOyQo0_tWOh"(<{}>* %0) #7 {
entry:
%.elt = bitcast <{}>* %0 to %swift.opaque*
%1 = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s1e8ortTupleQr_QR_tyFQOyQo_MD") #8
%2 = bitcast %swift.type* %1 to i8***
%3 = getelementptr inbounds i8**, i8*** %2, i64 -1
%.valueWitnesses = load i8**, i8*** %3, align 8, !invariant.load !19, !dereferenceable !20
%4 = getelementptr inbounds i8*, i8** %.valueWitnesses, i32 1
%5 = load i8*, i8** %4, align 8, !invariant.load !19
%destroy = bitcast i8* %5 to void (%swift.opaque*, %swift.type*)*
call void %destroy(%swift.opaque* noalias %.elt, %swift.type* %1) #9
%6 = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s1e8ortTupleQr_QR_tyFQOyQo__AaBQr_QR_tyFQOyQo0_tMD") #8
%7 = bitcast %swift.type* %6 to %swift.tuple_type*
%8 = getelementptr inbounds %swift.tuple_type, %swift.tuple_type* %7, i64 0, i32 3, i64 1, i32 1
%.1.offset = load i32, i32* %8, align 8
%9 = bitcast <{}>* %0 to i8*
%10 = getelementptr inbounds i8, i8* %9, i32 %.1.offset
%.elt1 = bitcast i8* %10 to %swift.opaque*
%11 = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s1e8ortTupleQr_QR_tyFQOyQo0_MD") #8
%12 = bitcast %swift.type* %11 to i8***
%13 = getelementptr inbounds i8**, i8*** %12, i64 -1
%.valueWitnesses2 = load i8**, i8*** %13, align 8, !invariant.load !19, !dereferenceable !20
%14 = getelementptr inbounds i8*, i8** %.valueWitnesses2, i32 1
%15 = load i8*, i8** %14, align 8, !invariant.load !19
%destroy3 = bitcast i8* %15 to void (%swift.opaque*, %swift.type*)*
call void %destroy3(%swift.opaque* noalias %.elt1, %swift.type* %11) #9
ret <{}>* %0
}
返り値のタプルの0番要素の型を取得
[.code-highlight: 4]
define linkonce_odr hidden <{}>* @"$s1e8ortTupleQr_QR_tyFQOyQo__AaBQr_QR_tyFQOyQo0_tWOh"(<{}>* %0) #7 {
entry:
%.elt = bitcast <{}>* %0 to %swift.opaque*
%1 = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s1e8ortTupleQr_QR_tyFQOyQo_MD") #8
%2 = bitcast %swift.type* %1 to i8***
%3 = getelementptr inbounds i8**, i8*** %2, i64 -1
%.valueWitnesses = load i8**, i8*** %3, align 8, !invariant.load !19, !dereferenceable !20
%4 = getelementptr inbounds i8*, i8** %.valueWitnesses, i32 1
%5 = load i8*, i8** %4, align 8, !invariant.load !19
%destroy = bitcast i8* %5 to void (%swift.opaque*, %swift.type*)*
call void %destroy(%swift.opaque* noalias %.elt, %swift.type* %1) #9
%6 = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s1e8ortTupleQr_QR_tyFQOyQo__AaBQr_QR_tyFQOyQo0_tMD") #8
%7 = bitcast %swift.type* %6 to %swift.tuple_type*
%8 = getelementptr inbounds %swift.tuple_type, %swift.tuple_type* %7, i64 0, i32 3, i64 1, i32 1
%.1.offset = load i32, i32* %8, align 8
%9 = bitcast <{}>* %0 to i8*
%10 = getelementptr inbounds i8, i8* %9, i32 %.1.offset
%.elt1 = bitcast i8* %10 to %swift.opaque*
%11 = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s1e8ortTupleQr_QR_tyFQOyQo0_MD") #8
%12 = bitcast %swift.type* %11 to i8***
%13 = getelementptr inbounds i8**, i8*** %12, i64 -1
%.valueWitnesses2 = load i8**, i8*** %13, align 8, !invariant.load !19, !dereferenceable !20
%14 = getelementptr inbounds i8*, i8** %.valueWitnesses2, i32 1
%15 = load i8*, i8** %14, align 8, !invariant.load !19
%destroy3 = bitcast i8* %15 to void (%swift.opaque*, %swift.type*)*
call void %destroy3(%swift.opaque* noalias %.elt1, %swift.type* %11) #9
ret <{}>* %0
}
VWTを使って0番要素を削除
[.code-highlight: 11]
define linkonce_odr hidden <{}>* @"$s1e8ortTupleQr_QR_tyFQOyQo__AaBQr_QR_tyFQOyQo0_tWOh"(<{}>* %0) #7 {
entry:
%.elt = bitcast <{}>* %0 to %swift.opaque*
%1 = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s1e8ortTupleQr_QR_tyFQOyQo_MD") #8
%2 = bitcast %swift.type* %1 to i8***
%3 = getelementptr inbounds i8**, i8*** %2, i64 -1
%.valueWitnesses = load i8**, i8*** %3, align 8, !invariant.load !19, !dereferenceable !20
%4 = getelementptr inbounds i8*, i8** %.valueWitnesses, i32 1
%5 = load i8*, i8** %4, align 8, !invariant.load !19
%destroy = bitcast i8* %5 to void (%swift.opaque*, %swift.type*)*
call void %destroy(%swift.opaque* noalias %.elt, %swift.type* %1) #9
%6 = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s1e8ortTupleQr_QR_tyFQOyQo__AaBQr_QR_tyFQOyQo0_tMD") #8
%7 = bitcast %swift.type* %6 to %swift.tuple_type*
%8 = getelementptr inbounds %swift.tuple_type, %swift.tuple_type* %7, i64 0, i32 3, i64 1, i32 1
%.1.offset = load i32, i32* %8, align 8
%9 = bitcast <{}>* %0 to i8*
%10 = getelementptr inbounds i8, i8* %9, i32 %.1.offset
%.elt1 = bitcast i8* %10 to %swift.opaque*
%11 = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s1e8ortTupleQr_QR_tyFQOyQo0_MD") #8
%12 = bitcast %swift.type* %11 to i8***
%13 = getelementptr inbounds i8**, i8*** %12, i64 -1
%.valueWitnesses2 = load i8**, i8*** %13, align 8, !invariant.load !19, !dereferenceable !20
%14 = getelementptr inbounds i8*, i8** %.valueWitnesses2, i32 1
%15 = load i8*, i8** %14, align 8, !invariant.load !19
%destroy3 = bitcast i8* %15 to void (%swift.opaque*, %swift.type*)*
call void %destroy3(%swift.opaque* noalias %.elt1, %swift.type* %11) #9
ret <{}>* %0
}
タプルの型を取得
[.code-highlight: 12]
define linkonce_odr hidden <{}>* @"$s1e8ortTupleQr_QR_tyFQOyQo__AaBQr_QR_tyFQOyQo0_tWOh"(<{}>* %0) #7 {
entry:
%.elt = bitcast <{}>* %0 to %swift.opaque*
%1 = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s1e8ortTupleQr_QR_tyFQOyQo_MD") #8
%2 = bitcast %swift.type* %1 to i8***
%3 = getelementptr inbounds i8**, i8*** %2, i64 -1
%.valueWitnesses = load i8**, i8*** %3, align 8, !invariant.load !19, !dereferenceable !20
%4 = getelementptr inbounds i8*, i8** %.valueWitnesses, i32 1
%5 = load i8*, i8** %4, align 8, !invariant.load !19
%destroy = bitcast i8* %5 to void (%swift.opaque*, %swift.type*)*
call void %destroy(%swift.opaque* noalias %.elt, %swift.type* %1) #9
%6 = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s1e8ortTupleQr_QR_tyFQOyQo__AaBQr_QR_tyFQOyQo0_tMD") #8
%7 = bitcast %swift.type* %6 to %swift.tuple_type*
%8 = getelementptr inbounds %swift.tuple_type, %swift.tuple_type* %7, i64 0, i32 3, i64 1, i32 1
%.1.offset = load i32, i32* %8, align 8
%9 = bitcast <{}>* %0 to i8*
%10 = getelementptr inbounds i8, i8* %9, i32 %.1.offset
%.elt1 = bitcast i8* %10 to %swift.opaque*
%11 = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s1e8ortTupleQr_QR_tyFQOyQo0_MD") #8
%12 = bitcast %swift.type* %11 to i8***
%13 = getelementptr inbounds i8**, i8*** %12, i64 -1
%.valueWitnesses2 = load i8**, i8*** %13, align 8, !invariant.load !19, !dereferenceable !20
%14 = getelementptr inbounds i8*, i8** %.valueWitnesses2, i32 1
%15 = load i8*, i8** %14, align 8, !invariant.load !19
%destroy3 = bitcast i8* %15 to void (%swift.opaque*, %swift.type*)*
call void %destroy3(%swift.opaque* noalias %.elt1, %swift.type* %11) #9
ret <{}>* %0
}
タプルの第1要素のポインタを取得
[.code-highlight: 17]
define linkonce_odr hidden <{}>* @"$s1e8ortTupleQr_QR_tyFQOyQo__AaBQr_QR_tyFQOyQo0_tWOh"(<{}>* %0) #7 {
entry:
%.elt = bitcast <{}>* %0 to %swift.opaque*
%1 = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s1e8ortTupleQr_QR_tyFQOyQo_MD") #8
%2 = bitcast %swift.type* %1 to i8***
%3 = getelementptr inbounds i8**, i8*** %2, i64 -1
%.valueWitnesses = load i8**, i8*** %3, align 8, !invariant.load !19, !dereferenceable !20
%4 = getelementptr inbounds i8*, i8** %.valueWitnesses, i32 1
%5 = load i8*, i8** %4, align 8, !invariant.load !19
%destroy = bitcast i8* %5 to void (%swift.opaque*, %swift.type*)*
call void %destroy(%swift.opaque* noalias %.elt, %swift.type* %1) #9
%6 = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s1e8ortTupleQr_QR_tyFQOyQo__AaBQr_QR_tyFQOyQo0_tMD") #8
%7 = bitcast %swift.type* %6 to %swift.tuple_type*
%8 = getelementptr inbounds %swift.tuple_type, %swift.tuple_type* %7, i64 0, i32 3, i64 1, i32 1
%.1.offset = load i32, i32* %8, align 8
%9 = bitcast <{}>* %0 to i8*
%10 = getelementptr inbounds i8, i8* %9, i32 %.1.offset
%.elt1 = bitcast i8* %10 to %swift.opaque*
%11 = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s1e8ortTupleQr_QR_tyFQOyQo0_MD") #8
%12 = bitcast %swift.type* %11 to i8***
%13 = getelementptr inbounds i8**, i8*** %12, i64 -1
%.valueWitnesses2 = load i8**, i8*** %13, align 8, !invariant.load !19, !dereferenceable !20
%14 = getelementptr inbounds i8*, i8** %.valueWitnesses2, i32 1
%15 = load i8*, i8** %14, align 8, !invariant.load !19
%destroy3 = bitcast i8* %15 to void (%swift.opaque*, %swift.type*)*
call void %destroy3(%swift.opaque* noalias %.elt1, %swift.type* %11) #9
ret <{}>* %0
}
タプルの第1要素の型を取得
[.code-highlight: 19]
define linkonce_odr hidden <{}>* @"$s1e8ortTupleQr_QR_tyFQOyQo__AaBQr_QR_tyFQOyQo0_tWOh"(<{}>* %0) #7 {
entry:
%.elt = bitcast <{}>* %0 to %swift.opaque*
%1 = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s1e8ortTupleQr_QR_tyFQOyQo_MD") #8
%2 = bitcast %swift.type* %1 to i8***
%3 = getelementptr inbounds i8**, i8*** %2, i64 -1
%.valueWitnesses = load i8**, i8*** %3, align 8, !invariant.load !19, !dereferenceable !20
%4 = getelementptr inbounds i8*, i8** %.valueWitnesses, i32 1
%5 = load i8*, i8** %4, align 8, !invariant.load !19
%destroy = bitcast i8* %5 to void (%swift.opaque*, %swift.type*)*
call void %destroy(%swift.opaque* noalias %.elt, %swift.type* %1) #9
%6 = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s1e8ortTupleQr_QR_tyFQOyQo__AaBQr_QR_tyFQOyQo0_tMD") #8
%7 = bitcast %swift.type* %6 to %swift.tuple_type*
%8 = getelementptr inbounds %swift.tuple_type, %swift.tuple_type* %7, i64 0, i32 3, i64 1, i32 1
%.1.offset = load i32, i32* %8, align 8
%9 = bitcast <{}>* %0 to i8*
%10 = getelementptr inbounds i8, i8* %9, i32 %.1.offset
%.elt1 = bitcast i8* %10 to %swift.opaque*
%11 = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s1e8ortTupleQr_QR_tyFQOyQo0_MD") #8
%12 = bitcast %swift.type* %11 to i8***
%13 = getelementptr inbounds i8**, i8*** %12, i64 -1
%.valueWitnesses2 = load i8**, i8*** %13, align 8, !invariant.load !19, !dereferenceable !20
%14 = getelementptr inbounds i8*, i8** %.valueWitnesses2, i32 1
%15 = load i8*, i8** %14, align 8, !invariant.load !19
%destroy3 = bitcast i8* %15 to void (%swift.opaque*, %swift.type*)*
call void %destroy3(%swift.opaque* noalias %.elt1, %swift.type* %11) #9
ret <{}>* %0
}
VWTを使ってタプルの第1要素を削除
[.code-highlight: 26]
define linkonce_odr hidden <{}>* @"$s1e8ortTupleQr_QR_tyFQOyQo__AaBQr_QR_tyFQOyQo0_tWOh"(<{}>* %0) #7 {
entry:
%.elt = bitcast <{}>* %0 to %swift.opaque*
%1 = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s1e8ortTupleQr_QR_tyFQOyQo_MD") #8
%2 = bitcast %swift.type* %1 to i8***
%3 = getelementptr inbounds i8**, i8*** %2, i64 -1
%.valueWitnesses = load i8**, i8*** %3, align 8, !invariant.load !19, !dereferenceable !20
%4 = getelementptr inbounds i8*, i8** %.valueWitnesses, i32 1
%5 = load i8*, i8** %4, align 8, !invariant.load !19
%destroy = bitcast i8* %5 to void (%swift.opaque*, %swift.type*)*
call void %destroy(%swift.opaque* noalias %.elt, %swift.type* %1) #9
%6 = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s1e8ortTupleQr_QR_tyFQOyQo__AaBQr_QR_tyFQOyQo0_tMD") #8
%7 = bitcast %swift.type* %6 to %swift.tuple_type*
%8 = getelementptr inbounds %swift.tuple_type, %swift.tuple_type* %7, i64 0, i32 3, i64 1, i32 1
%.1.offset = load i32, i32* %8, align 8
%9 = bitcast <{}>* %0 to i8*
%10 = getelementptr inbounds i8, i8* %9, i32 %.1.offset
%.elt1 = bitcast i8* %10 to %swift.opaque*
%11 = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s1e8ortTupleQr_QR_tyFQOyQo0_MD") #8
%12 = bitcast %swift.type* %11 to i8***
%13 = getelementptr inbounds i8**, i8*** %12, i64 -1
%.valueWitnesses2 = load i8**, i8*** %13, align 8, !invariant.load !19, !dereferenceable !20
%14 = getelementptr inbounds i8*, i8** %.valueWitnesses2, i32 1
%15 = load i8*, i8** %14, align 8, !invariant.load !19
%destroy3 = bitcast i8* %15 to void (%swift.opaque*, %swift.type*)*
call void %destroy3(%swift.opaque* noalias %.elt1, %swift.type* %11) #9
ret <{}>* %0
}
ジェネリック型でsomeの個数を変えた場合
public struct C<A, B, C> {
var a: A
var b: B
var c: C
public func getA() -> A { a }
public func getB() -> B { b }
public func getC() -> C { c }
}
public func ortGeneric1() -> C<Int, Int, some P> {
C<Int, Int, S>(a: 0, b: 1, c: S())
}
public func ortGeneric2() -> C<some P, (some P, some P), some P> {
C<S, (S, S), S>(a: S(), b: (S(), S()), c: S())
}
func main1() {
ortGeneric1().getC()
}
func main2() {
ortGeneric2().getC()
}
全体の型
[.code-highlight: 1-4, 7]
; $s1e1CVyS2iAA11ortGeneric1ACyS2iQrGyFQOyQo_GMD --->
; demangling cache variable for type metadata for
; e.C<Swift.Int, Swift.Int, <<opaque return type of e.ortGeneric1() -> e.C<Swift.Int, Swift.Int, some>>>.0>
define hidden swiftcc void @"$s1f5main1yyF"() #0 {
entry:
%0 = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s1e1CVyS2iAA11ortGeneric1ACyS2iQrGyFQOyQo_GMD") #7
%1 = bitcast %swift.type* %0 to i8***
%2 = getelementptr inbounds i8**, i8*** %1, i64 -1
%.valueWitnesses = load i8**, i8*** %2, align 8, !invariant.load !24, !dereferenceable !25
%3 = bitcast i8** %.valueWitnesses to %swift.vwtable*
%4 = getelementptr inbounds %swift.vwtable, %swift.vwtable* %3, i32 0, i32 8
%size = load i64, i64* %4, align 8, !invariant.load !24
%5 = alloca i8, i64 %size, align 16
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %5)
%6 = bitcast i8* %5 to %T1e1CVyS2iAA11ortGeneric1ACyS2iQrGyFQOyQo_G*
%7 = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s1e11ortGeneric1AA1CVyS2iQrGyFQOyQo_MD") #7
%8 = bitcast %swift.type* %7 to i8***
%9 = getelementptr inbounds i8**, i8*** %8, i64 -1
%.valueWitnesses1 = load i8**, i8*** %9, align 8, !invariant.load !24, !dereferenceable !25
%10 = bitcast i8** %.valueWitnesses1 to %swift.vwtable*
%11 = getelementptr inbounds %swift.vwtable, %swift.vwtable* %10, i32 0, i32 8
%size2 = load i64, i64* %11, align 8, !invariant.load !24
%12 = alloca i8, i64 %size2, align 16
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %12)
%13 = bitcast i8* %12 to %swift.opaque*
%14 = bitcast %T1e1CVyS2iAA11ortGeneric1ACyS2iQrGyFQOyQo_G* %6 to %swift.opaque*
call swiftcc void @"$s1e11ortGeneric1AA1CVyS2iQrGyF"(%swift.opaque* noalias nocapture sret(%swift.opaque) %14)
%15 = bitcast %T1e1CVyS2iAA11ortGeneric1ACyS2iQrGyFQOyQo_G* %6 to %T1e1CV*
call swiftcc void @"$s1e1CV4getCq0_yF"(%swift.opaque* noalias nocapture sret(%swift.opaque) %13, %swift.type* %0, %T1e1CV* noalias nocapture swiftself %15)
%16 = call %T1e1CVyS2iAA11ortGeneric1ACyS2iQrGyFQOyQo_G* @"$s1e1CVyS2iAA11ortGeneric1ACyS2iQrGyFQOyQo_GWOh"(%T1e1CVyS2iAA11ortGeneric1ACyS2iQrGyFQOyQo_G* %6)
%17 = getelementptr inbounds i8*, i8** %.valueWitnesses1, i32 1
%18 = load i8*, i8** %17, align 8, !invariant.load !24
%destroy = bitcast i8* %18 to void (%swift.opaque*, %swift.type*)*
call void %destroy(%swift.opaque* noalias %13, %swift.type* %7) #8
%19 = bitcast %swift.opaque* %13 to i8*
call void @llvm.lifetime.end.p0i8(i64 -1, i8* %19)
%20 = bitcast %T1e1CVyS2iAA11ortGeneric1ACyS2iQrGyFQOyQo_G* %6 to i8*
call void @llvm.lifetime.end.p0i8(i64 -1, i8* %20)
ret void
}
opaque result typeの0番
[.code-highlight: 1-4, 18]
; $s1e11ortGeneric1AA1CVyS2iQrGyFQOyQo_MD --->
; demangling cache variable for type metadata for <<
; opaque return type of e.ortGeneric1() -> e.C<Swift.Int, Swift.Int, some>
; >>.0
define hidden swiftcc void @"$s1f5main1yyF"() #0 {
entry:
%0 = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s1e1CVyS2iAA11ortGeneric1ACyS2iQrGyFQOyQo_GMD") #7
%1 = bitcast %swift.type* %0 to i8***
%2 = getelementptr inbounds i8**, i8*** %1, i64 -1
%.valueWitnesses = load i8**, i8*** %2, align 8, !invariant.load !24, !dereferenceable !25
%3 = bitcast i8** %.valueWitnesses to %swift.vwtable*
%4 = getelementptr inbounds %swift.vwtable, %swift.vwtable* %3, i32 0, i32 8
%size = load i64, i64* %4, align 8, !invariant.load !24
%5 = alloca i8, i64 %size, align 16
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %5)
%6 = bitcast i8* %5 to %T1e1CVyS2iAA11ortGeneric1ACyS2iQrGyFQOyQo_G*
%7 = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s1e11ortGeneric1AA1CVyS2iQrGyFQOyQo_MD") #7
%8 = bitcast %swift.type* %7 to i8***
%9 = getelementptr inbounds i8**, i8*** %8, i64 -1
%.valueWitnesses1 = load i8**, i8*** %9, align 8, !invariant.load !24, !dereferenceable !25
%10 = bitcast i8** %.valueWitnesses1 to %swift.vwtable*
%11 = getelementptr inbounds %swift.vwtable, %swift.vwtable* %10, i32 0, i32 8
%size2 = load i64, i64* %11, align 8, !invariant.load !24
%12 = alloca i8, i64 %size2, align 16
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %12)
%13 = bitcast i8* %12 to %swift.opaque*
%14 = bitcast %T1e1CVyS2iAA11ortGeneric1ACyS2iQrGyFQOyQo_G* %6 to %swift.opaque*
call swiftcc void @"$s1e11ortGeneric1AA1CVyS2iQrGyF"(%swift.opaque* noalias nocapture sret(%swift.opaque) %14)
%15 = bitcast %T1e1CVyS2iAA11ortGeneric1ACyS2iQrGyFQOyQo_G* %6 to %T1e1CV*
call swiftcc void @"$s1e1CV4getCq0_yF"(%swift.opaque* noalias nocapture sret(%swift.opaque) %13, %swift.type* %0, %T1e1CV* noalias nocapture swiftself %15)
%16 = call %T1e1CVyS2iAA11ortGeneric1ACyS2iQrGyFQOyQo_G* @"$s1e1CVyS2iAA11ortGeneric1ACyS2iQrGyFQOyQo_GWOh"(%T1e1CVyS2iAA11ortGeneric1ACyS2iQrGyFQOyQo_G* %6)
%17 = getelementptr inbounds i8*, i8** %.valueWitnesses1, i32 1
%18 = load i8*, i8** %17, align 8, !invariant.load !24
%destroy = bitcast i8* %18 to void (%swift.opaque*, %swift.type*)*
call void %destroy(%swift.opaque* noalias %13, %swift.type* %7) #8
%19 = bitcast %swift.opaque* %13 to i8*
call void @llvm.lifetime.end.p0i8(i64 -1, i8* %19)
%20 = bitcast %T1e1CVyS2iAA11ortGeneric1ACyS2iQrGyFQOyQo_G* %6 to i8*
call void @llvm.lifetime.end.p0i8(i64 -1, i8* %20)
ret void
}
opaque return typeの3番
[.code-highlight: 1-5, 18]
; $s1e11ortGeneric2AA1CVyQrQR__QR0_tQR1_GyFQOyQo2_MD --->
; demangling cache variable for type metadata for <<
; opaque return type of e.ortGeneric2() -> e.C<some, (some, some), some>
; >>.3
define hidden swiftcc void @"$s1f5main2yyF"() #0 {
entry:
%0 = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s1e1CVyAA11ortGeneric2ACyQrQR__QR0_tQR1_GyFQOyQo_AadEyFQOyQo0__AadEyFQOyQo1_tAadEyFQOyQo2_GMD") #7
%1 = bitcast %swift.type* %0 to i8***
%2 = getelementptr inbounds i8**, i8*** %1, i64 -1
%.valueWitnesses = load i8**, i8*** %2, align 8, !invariant.load !24, !dereferenceable !25
%3 = bitcast i8** %.valueWitnesses to %swift.vwtable*
%4 = getelementptr inbounds %swift.vwtable, %swift.vwtable* %3, i32 0, i32 8
%size = load i64, i64* %4, align 8, !invariant.load !24
%5 = alloca i8, i64 %size, align 16
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %5)
%6 = bitcast i8* %5 to %T1e1CVyAA11ortGeneric2ACyQrQR__QR0_tQR1_GyFQOyQo_AadEyFQOyQo0__AadEyFQOyQo1_tAadEyFQOyQo2_G*
%7 = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({ i32, i32 }* @"$s1e11ortGeneric2AA1CVyQrQR__QR0_tQR1_GyFQOyQo2_MD") #7
%8 = bitcast %swift.type* %7 to i8***
%9 = getelementptr inbounds i8**, i8*** %8, i64 -1
%.valueWitnesses1 = load i8**, i8*** %9, align 8, !invariant.load !24, !dereferenceable !25
%10 = bitcast i8** %.valueWitnesses1 to %swift.vwtable*
%11 = getelementptr inbounds %swift.vwtable, %swift.vwtable* %10, i32 0, i32 8
%size2 = load i64, i64* %11, align 8, !invariant.load !24
%12 = alloca i8, i64 %size2, align 16
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %12)
%13 = bitcast i8* %12 to %swift.opaque*
%14 = bitcast %T1e1CVyAA11ortGeneric2ACyQrQR__QR0_tQR1_GyFQOyQo_AadEyFQOyQo0__AadEyFQOyQo1_tAadEyFQOyQo2_G* %6 to %swift.opaque*
call swiftcc void @"$s1e11ortGeneric2AA1CVyQrQR__QR0_tQR1_GyF"(%swift.opaque* noalias nocapture sret(%swift.opaque) %14)
%15 = bitcast %T1e1CVyAA11ortGeneric2ACyQrQR__QR0_tQR1_GyFQOyQo_AadEyFQOyQo0__AadEyFQOyQo1_tAadEyFQOyQo2_G* %6 to %T1e1CV*
call swiftcc void @"$s1e1CV4getCq0_yF"(%swift.opaque* noalias nocapture sret(%swift.opaque) %13, %swift.type* %0, %T1e1CV* noalias nocapture swiftself %15)
%16 = call %T1e1CVyAA11ortGeneric2ACyQrQR__QR0_tQR1_GyFQOyQo_AadEyFQOyQo0__AadEyFQOyQo1_tAadEyFQOyQo2_G*
@"$s1e1CVyAA11ortGeneric2ACyQrQR__QR0_tQR1_GyFQOyQo_AadEyFQOyQo0__AadEyFQOyQo1_tAadEyFQOyQo2_GWOh"(
%T1e1CVyAA11ortGeneric2ACyQrQR__QR0_tQR1_GyFQOyQo_AadEyFQOyQo0__AadEyFQOyQo1_tAadEyFQOyQo2_G* %6
)
%17 = getelementptr inbounds i8*, i8** %.valueWitnesses1, i32 1
%18 = load i8*, i8** %17, align 8, !invariant.load !24
%destroy = bitcast i8* %18 to void (%swift.opaque*, %swift.type*)*
call void %destroy(%swift.opaque* noalias %13, %swift.type* %7) #8
%19 = bitcast %swift.opaque* %13 to i8*
call void @llvm.lifetime.end.p0i8(i64 -1, i8* %19)
%20 = bitcast %T1e1CVyAA11ortGeneric2ACyQrQR__QR0_tQR1_GyFQOyQo_AadEyFQOyQo0__AadEyFQOyQo1_tAadEyFQOyQo2_G* %6 to i8*
call void @llvm.lifetime.end.p0i8(i64 -1, i8* %20)
ret void
}
public func ortGeneric1() -> C<Int, Int, some P> { ... }
public func ortGeneric2() -> C<some P, (some P, some P), some P> { ... }
// 気持ち
public func ortGeneric1() -> <T0: P> C<Int, Int, T0> { ... }
// C.CはT0
public func ortGeneric2() -> <T0: P, T1: P, T2: P, T3: P> C<T0, (T1, T2), T3> { ... }
// C.CはT3
Reverse Genericsで見たときのパラメータ型のインデックスに対応している?
- 返り値でsomeを使える形が増えた
- ランタイム関数でsomeを含む返り値自体の型を取得できる
- 複数のsomeを含む場合、それぞれのsomeに番号が付いていて、個別の型の取得もできる
実はもう実装があって試せる。
$ swiftc \
-Xfrontend -enable-experimental-named-opaque-types \
-emit-module i.swift
public protocol P {}
struct S: P {}
public func makeTuple() -> <T: P, U: P> (T, T, U) {
(S(), S(), S())
}
func main() {
let tuple = makeTuple()
}
こうすれば、Reverse Parameterは2つ、opaque typeは3つなので、番号付けの規則が調べられる。
define hidden swiftcc void @"$s1j4mainyyF"() #0 {
entry:
%tuple.debug = alloca i8*, align 8
%0 = bitcast i8** %tuple.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %0, i8 0, i64 8, i1 false)
%1 = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName(
{ i32, i32 }* @"$s1i9makeTupleQr_QrQR_tyFQOyQo__AcaBQr_QrQR_tyFQOyQo0_tMD") #8
%2 = bitcast %swift.type* %1 to i8***
%3 = getelementptr inbounds i8**, i8*** %2, i64 -1
%.valueWitnesses = load i8**, i8*** %3, align 8, !invariant.load !19, !dereferenceable !20
%4 = bitcast i8** %.valueWitnesses to %swift.vwtable*
%5 = getelementptr inbounds %swift.vwtable, %swift.vwtable* %4, i32 0, i32 8
%size = load i64, i64* %5, align 8, !invariant.load !19
%tuple = alloca i8, i64 %size, align 16
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %tuple)
%6 = bitcast i8* %tuple to <{}>*
store i8* %tuple, i8** %tuple.debug, align 8
%.elt = bitcast <{}>* %6 to %swift.opaque*
%7 = bitcast %swift.type* %1 to %swift.tuple_type*
%8 = getelementptr inbounds %swift.tuple_type, %swift.tuple_type* %7, i64 0, i32 3, i64 1, i32 1
%.1.offset = load i32, i32* %8, align 8
%9 = bitcast <{}>* %6 to i8*
%10 = getelementptr inbounds i8, i8* %9, i32 %.1.offset
%.elt1 = bitcast i8* %10 to %swift.opaque*
%11 = bitcast %swift.type* %1 to %swift.tuple_type*
%12 = getelementptr inbounds %swift.tuple_type, %swift.tuple_type* %11, i64 0, i32 3, i64 2, i32 1
%.2.offset = load i32, i32* %12, align 8
%13 = bitcast <{}>* %6 to i8*
%14 = getelementptr inbounds i8, i8* %13, i32 %.2.offset
%.elt2 = bitcast i8* %14 to %swift.opaque*
call swiftcc void @"$s1i9makeTupleQr_QrQR_tyF"(
%swift.opaque* noalias nocapture %.elt, %swift.opaque* noalias nocapture %.elt1, %swift.opaque* noalias nocapture %.elt2)
%15 = call <{}>* @"$s1i9makeTupleQr_QrQR_tyFQOyQo__AcaBQr_QrQR_tyFQOyQo0_tWOh"(<{}>* %6)
%16 = bitcast <{}>* %6 to i8*
call void @llvm.lifetime.end.p0i8(i64 -1, i8* %16)
ret void
}
シグネチャは some が3つ。
[.code-highlight: 1, 33-34]
; $s1i9makeTupleQr_QrQR_tyF ---> i.makeTuple() -> (some, some, some)
define hidden swiftcc void @"$s1j4mainyyF"() #0 {
entry:
%tuple.debug = alloca i8*, align 8
%0 = bitcast i8** %tuple.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %0, i8 0, i64 8, i1 false)
%1 = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName(
{ i32, i32 }* @"$s1i9makeTupleQr_QrQR_tyFQOyQo__AcaBQr_QrQR_tyFQOyQo0_tMD") #8
%2 = bitcast %swift.type* %1 to i8***
%3 = getelementptr inbounds i8**, i8*** %2, i64 -1
%.valueWitnesses = load i8**, i8*** %3, align 8, !invariant.load !19, !dereferenceable !20
%4 = bitcast i8** %.valueWitnesses to %swift.vwtable*
%5 = getelementptr inbounds %swift.vwtable, %swift.vwtable* %4, i32 0, i32 8
%size = load i64, i64* %5, align 8, !invariant.load !19
%tuple = alloca i8, i64 %size, align 16
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %tuple)
%6 = bitcast i8* %tuple to <{}>*
store i8* %tuple, i8** %tuple.debug, align 8
%.elt = bitcast <{}>* %6 to %swift.opaque*
%7 = bitcast %swift.type* %1 to %swift.tuple_type*
%8 = getelementptr inbounds %swift.tuple_type, %swift.tuple_type* %7, i64 0, i32 3, i64 1, i32 1
%.1.offset = load i32, i32* %8, align 8
%9 = bitcast <{}>* %6 to i8*
%10 = getelementptr inbounds i8, i8* %9, i32 %.1.offset
%.elt1 = bitcast i8* %10 to %swift.opaque*
%11 = bitcast %swift.type* %1 to %swift.tuple_type*
%12 = getelementptr inbounds %swift.tuple_type, %swift.tuple_type* %11, i64 0, i32 3, i64 2, i32 1
%.2.offset = load i32, i32* %12, align 8
%13 = bitcast <{}>* %6 to i8*
%14 = getelementptr inbounds i8, i8* %13, i32 %.2.offset
%.elt2 = bitcast i8* %14 to %swift.opaque*
call swiftcc void @"$s1i9makeTupleQr_QrQR_tyF"(
%swift.opaque* noalias nocapture %.elt, %swift.opaque* noalias nocapture %.elt1, %swift.opaque* noalias nocapture %.elt2)
%15 = call <{}>* @"$s1i9makeTupleQr_QrQR_tyFQOyQo__AcaBQr_QrQR_tyFQOyQo0_tWOh"(<{}>* %6)
%16 = bitcast <{}>* %6 to i8*
call void @llvm.lifetime.end.p0i8(i64 -1, i8* %16)
ret void
}
返り値の型情報を取得する箇所
[.code-highlight: 6-7]
define hidden swiftcc void @"$s1j4mainyyF"() #0 {
entry:
%tuple.debug = alloca i8*, align 8
%0 = bitcast i8** %tuple.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %0, i8 0, i64 8, i1 false)
%1 = call %swift.type* @__swift_instantiateConcreteTypeFromMangledName(
{ i32, i32 }* @"$s1i9makeTupleQr_QrQR_tyFQOyQo__AcaBQr_QrQR_tyFQOyQo0_tMD") #8
%2 = bitcast %swift.type* %1 to i8***
%3 = getelementptr inbounds i8**, i8*** %2, i64 -1
%.valueWitnesses = load i8**, i8*** %3, align 8, !invariant.load !19, !dereferenceable !20
%4 = bitcast i8** %.valueWitnesses to %swift.vwtable*
%5 = getelementptr inbounds %swift.vwtable, %swift.vwtable* %4, i32 0, i32 8
%size = load i64, i64* %5, align 8, !invariant.load !19
%tuple = alloca i8, i64 %size, align 16
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %tuple)
%6 = bitcast i8* %tuple to <{}>*
store i8* %tuple, i8** %tuple.debug, align 8
%.elt = bitcast <{}>* %6 to %swift.opaque*
%7 = bitcast %swift.type* %1 to %swift.tuple_type*
%8 = getelementptr inbounds %swift.tuple_type, %swift.tuple_type* %7, i64 0, i32 3, i64 1, i32 1
%.1.offset = load i32, i32* %8, align 8
%9 = bitcast <{}>* %6 to i8*
%10 = getelementptr inbounds i8, i8* %9, i32 %.1.offset
%.elt1 = bitcast i8* %10 to %swift.opaque*
%11 = bitcast %swift.type* %1 to %swift.tuple_type*
%12 = getelementptr inbounds %swift.tuple_type, %swift.tuple_type* %11, i64 0, i32 3, i64 2, i32 1
%.2.offset = load i32, i32* %12, align 8
%13 = bitcast <{}>* %6 to i8*
%14 = getelementptr inbounds i8, i8* %13, i32 %.2.offset
%.elt2 = bitcast i8* %14 to %swift.opaque*
call swiftcc void @"$s1i9makeTupleQr_QrQR_tyF"(
%swift.opaque* noalias nocapture %.elt, %swift.opaque* noalias nocapture %.elt1, %swift.opaque* noalias nocapture %.elt2)
%15 = call <{}>* @"$s1i9makeTupleQr_QrQR_tyFQOyQo__AcaBQr_QrQR_tyFQOyQo0_tWOh"(<{}>* %6)
%16 = bitcast <{}>* %6 to i8*
call void @llvm.lifetime.end.p0i8(i64 -1, i8* %16)
ret void
}
$s1i9makeTupleQr_QrQR_tyFQOyQo__AcaBQr_QrQR_tyFQOyQo0_tMD --->
demangling cache variable for type metadata for (
<<opaque return type of i.makeTuple() -> (some, some, some)>>.0,
<<opaque return type of i.makeTuple() -> (some, some, some)>>.0,
<<opaque return type of i.makeTuple() -> (some, some, some)>>.1
)
タプルの型は (0, 0, 1)
なので、opaque return typeの番号は、Reverse Generic Parameterの並びに対応しているとわかる。
func f(p: some P) { ... }
// 等価
func f<T: P>(p: T) { ... }
someを引数で使える。それぞれのsomeが個別の型パラメータとなる。
func foo(_ a: (some P, some P)) {}
もちろんタプルなどのジェネリックパラメータの中に使うこともできる。
func foo(_ f: (some P) -> Void) {}
fooの中でfに渡す some P を作る方法がない
func foo(_ a: (some P, some P)) {}
define hidden swiftcc void @"$s1g3fooyyx_q_t_tAA1PRzAaCR_r0_lF"(
%swift.opaque* noalias nocapture %0,
%swift.opaque* noalias nocapture %1,
%swift.type* %"<anonymous>",
%swift.type* %"<anonymous>1",
i8** %"<anonymous>.P",
i8** %"<anonymous>.P2"
) { ... }
; $s1g3fooyyx_q_t_tAA1PRzAaCR_r0_lF --->
; g.foo<A, B where A: g.P, B: g.P>((A, B)) -> ()
デマングルすれば通常のジェネリクスになっている事が確認できる
func readSyntaxHighlightedLines(_ file: String) -> some Sequence<[Token]> {
...
}
プロトコル名の後ろに三角括弧でパラメータ指定して、associated typeの制約を書ける
protocol Sequence<Element> {
associatedtype Element
associatedtype Iterator : IteratorProtocol
where Element == Iterator.Element
...
}
プロトコル名の後ろに三角括弧でパラメータ宣言しておく。 associated typeの名前を書く。
associated typeはprotocol conformanceの際に固定する内部パラメータだが、 外部パラメータごとに異なるconformanceとみなすGeneric Protocolというアイデアがある。
三角括弧は将来そのような機能に使いそうだったが、今回別の用途に消費してしまった。 提案では、Generic Protocolには丸括弧の案が示されている。
protocol Convertible(from: Self, to: Other) {
static func convert(_: Self) -> Other
}
extension Convertible(from: String, to: Int) {
static func convert(_: String) -> Int
}
extension Convertible(from: String, to: Double) {
static func convert(_: String) -> Int
}
protocol P<A> {
associatedtype A
}
struct S<A>: P {}
func foo(a: some P<Int>) -> some P<Bool> { ... }
define hidden swiftcc void @"$s1g3foo1aQrx_tAA1PRzSi1ARtzlF"(
%swift.opaque* noalias nocapture sret(%swift.opaque) %0,
%swift.opaque* noalias nocapture %1,
%swift.type* %"<anonymous>",
i8** %"<anonymous>.P"
) #0 { ... }
; $s1g3foo1aQrx_tAA1PRzSi1ARtzlF --->
; g.foo<A where A: g.P, A.A == Swift.Int>(a: A) -> some
// $s1g3fooQryF ---> g.foo() -> some
func foo() -> some P<Int> { ... }
// $s1g3fooQryF ---> g.foo() -> some
func foo() -> some Q { ... }
// $s1g3fooQr_QR_tyF ---> g.foo() -> (some, some)
func foo() -> (some Q, some Q) { ... }
ORTのジェネリック制約部分はそれ自体の制約(P)やassociated type(Int)を含め全くシグネチャに乗らないので、 制約ではオーバーロードできないが、形ではオーバーロードできる。
protocol P {
associatedtype A
}
func useSomeP(_ p: some P) {}
func useAnyP(_ p: any P) {
useSomeP(p)
}
existentialを関数呼び出しのときにopenできる。つまり、anyをsomeに変換できる。
extension P {
func callUseSomeP() {
useSomeP(self)
}
}
func useAnyP(_ p: any P) {
p.callUseSomeP(p)
}
技術的にはexistentialによるopenでできていた事を、 どこでも手間なしで使えるようになったとみなせる。
func useSomeP(_ p: inout some P) {}
func useAnyP(_ p: any P) {
var p = p
useSomeP(&p)
}
func cannotOpen1<T: P>(_ array: [T]) { }
func cannotOpen2<T: P>(_ a: T, _ b: T) { }
func cannotOpen3<T: P>(_ values: T...) { }
struct X<T> { }
func cannotOpen4<T: P>(_ x: X<T>) { }
func cannotOpen5<T: P>(_ x: T, _ a: T.A) { }
func cannotOpen6<T: P>(_ x: T?) { }
func cannotOpenDemo(
array: [any P],
p1: any P, p2: any P,
xp: X<any P>,
pOpt: (any P)?
) {
cannotOpen1(array) // 要素の型が異なるかもしれないし、空かもしれない
cannotOpen2(p1, p2) // p1とp2の型が異なるかもしれない
cannotOpen3(p1, p2) // p1とp2の型が異なるかもしれない
cannotOpen4(xp) // 中身を取り出す方法がない
cannotOpen5(p1, p2.getA()) // p1とp2の型が異なるかもしれない
cannotOpen5(p1, p1.getA()) // p1とp1.getA()の型の関連は追跡されない
cannotOpen6(pOpt) // 中身がないかもしれない
}
openするには any P
の中身の真の値が必要。
func useSomePType<T: P>(_ t: T.Type) {}
func useAnyPType(_ t: any P.Type) {
useSomePType(t)
}
メタタイプのexistentialもopenできる
protocol P {
associatedtype A: AP
func getA() -> A
}
protocol AP {}
func decompose<T: P>(_ p: T) -> (T, T.A) {
(p, p.getA())
}
func useAnyP(_ p: any P) {
let (p, a) = decompose(p)
}
openした関数の返り値はupper boundのexistentialにeraseされる。
func useAnyP(_ p: any P) {
let (p, a): (any P, any AP) = decompose(p)
}
SE-0309のexistentialの制限排除で導入された、covariantなassociated valueがeraseされるのと同じ仕組み。
func useAnyP(_ p: any P) {
let a: any AP = p.getA()
}
func makeFunc<T: P>(_ p: T) -> (T) -> () {
return { (_) in }
}
func useAnyP(_ p: any P) {
// error: type 'any P' cannot conform to 'P'
makeFunc(p)
}
struct X<T> { var t: T }
func wrapX<T: P>(_ p: T) -> X<T> { ... }
func useAnyP(_ p: any P) {
// error: type 'any P' cannot conform to 'P'
wrapX(p)
}
ユーザ定義genericsはinvariantなのでcontravariant
func acceptValueAndFunction<T: P>(_ value: T, body: (T) -> Void) { ... }
func testContravariantErasure(p: any P) {
acceptValueAndFunction(p) { (innerValue: any P) in
...
}
}
func takeP<U: P>(_: U) -> Void { ... }
func implicitOpeningArguments(p: any P) {
acceptValueAndFunction(p, body: takeP)
}
takePのUが直接pの真の型になる。 eraseしてから再度openしているとも見做せる。
protocol P {
associatedtype A
}
protocol Q {
associatedtype B: P where B.A == Int
}
func getBFromQ<T: Q>(_ q: T) -> T.B { ... }
func eraseQAssoc(q: any Q) {
let b = getBFromQ(q)
}
getBFromQ
の返り値の型は <U: P> where P.A == Int
だが、
b
にeraseするときに any P
になり、A == Int
の制約が喪失する。
この問題はexistentialが制約を持てない事に起因する。
将来的に解決した場合、b
の型はより正確になるが、ソース互換性が壊れる。
// b: any P ならこっち
func f<T: P>(_: T) -> Int { 17 }
// b: any P<Int> ならこっち
func f<T: P>(_: T) -> Double where T.A == Int { 3.14159 }
func eraseQAssoc(q: any Q) {
let b = getBFromQ(q)
// どっち?
f(b)
}
そこで、制約が喪失するeraseには明示的なasを強制する。
func eraseQAssoc(q: any Q) {
let b = getBFromQ(q) as any P
}
SE-0309も同じ問題があったので明示的なasを強制する。
extension Q {
func getBFromQ() -> B { ... }
}
func eraseQAssocWithSE0309(q: any Q) {
let b = q.getBFromQ() as any P
}
extension Int: P { }
func getP() -> any P {
print("getP()")
return 17
}
func acceptFunctionStringAndValue<T: P>(body: (T) -> Void, string: String, value: T) { ... }
func hello() -> String {
print("hello()")
return "hello"
}
func implicitOpeningArgumentsBackwards() {
acceptFunctionStringAndValue(body: takeP, string: hello(), value: getP())
}
acceptFunctionStringAndValue(body: takeP, string: hello(), value: getP())
takePを評価するためには、<T>
に真の型が束縛されなければならない。
しかし、 <T>
は getP
の返り値をopenしなければ決定できない。
その結果、getP()
→ takeP
→ hello()
の順に評価され、副作用として以下が出力される。
getP()
hello()
これはSwiftの左から右に引数を評価する規則と矛盾する。
そこで、すでに左側で使われたジェネリックパラメータを、 それより右側でopenする事はできない、というルールを追加する。
// error: type 'any P' cannot conform to 'P'
acceptFunctionStringAndValue(body: takeP, string: hello(), value: getP())
func acceptsBox<T>(_ value: T) -> Any { [value] }
func passBox(p: any P) {
let result = acceptsBox(p)
// これまでは result: [any P]
// これからは result: [open(any P)]
}
自己準拠するexistential(Error
と@objc
)も問題になる。
func takeError<E: Error>(_ error: E) { ... }
func passError(error: any Error) {
takeError(error)
// これまでは E = any Error
// これからは E = open(any Error)
}
将来、existentialを自己準拠させる文法が追加される場合、これについては互換性の問題は生じないのでopenする。
extension any P: P {}
既存の問題については互換性維持のため、Swift5ではopenしない事にする。 Swift6では互換性破壊できるので、openできるときはopenするように変更する。
明示的なasによって、openを抑制できる。
// (1)
func f<T>(_: T) { }
// (2)
func f<T: P>(_: T) { }
func test(p: any P) {
// pをopenして(2)を呼ぶ
f(p)
// pのopenを抑制するため(1)を呼ぶ
f(p as any P)
}
丸括弧を付けるとopenの抑制を無効化できる
func test(p: any P) {
// openの抑制を無効化するため、openして(1)を呼ぶ
f((p as any P))
}
protocol P {
associatedtype A
}
protocol Q {
associatedtype B: P where B.A == Int
}
func getP<T: P>(_ p: T)
func getBFromQ<T: Q>(_ q: T) -> T.B { ... }
func eraseQAssoc(q: any Q) {
// A == Int が喪失するので as any P が必要
getP(getBFromQ(q))
// 制約喪失が許容されたが、openも抑制するためgetPが呼び出せない
getP(getBFromQ(q) as any P)
// 制約喪失を許容し、openの抑制を無効化したので、getPが呼び出せる
getP((getBFromQ(q) as any P))
}
- 関数呼び出しでopenできる
- openした型が戻ってくる場合eraseされる
- 抑制記法もある
primary associated typeを指定したexistentialが使える
any Collection<Int>
protocol P<A> {
associatedtype A
}
protocol Q {
associatedtype B: P where B.A == Int
}
Existentialのメンバにアクセスする時
extension Q {
func getB() -> B
}
func useQ(_ q: any Q) {
let b: any P<Int> = q.getB()
}
Openする時
func getB<T: Q>(_ q: T) -> T.B { ... }
func useQ(_ q: any Q) {
let b: any P<Int> = getB(q)
}
protocol P<A> {
associatedtype A
func getA() -> A
}
func useIntP(_ p: any P<Int>) {
let a: Int = p.getA()
}
define hidden swiftcc void @"$s1h7useIntPyyAA1P_pySiXPF"(%T1h1P_pySiXP* noalias nocapture dereferenceable(40) %0) #0 {
entry:
%p.debug = alloca %T1h1P_pySiXP*, align 8
%1 = bitcast %T1h1P_pySiXP** %p.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %1, i8 0, i64 8, i1 false)
%2 = alloca %TSi, align 8
%a.debug = alloca i64, align 8
%3 = bitcast i64* %a.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %3, i8 0, i64 8, i1 false)
store %T1h1P_pySiXP* %0, %T1h1P_pySiXP** %p.debug, align 8
%4 = getelementptr inbounds %T1h1P_pySiXP, %T1h1P_pySiXP* %0, i32 0, i32 1
%5 = load %swift.type*, %swift.type** %4, align 8
%6 = getelementptr inbounds %T1h1P_pySiXP, %T1h1P_pySiXP* %0, i32 0, i32 2
%7 = load i8**, i8*** %6, align 8
%8 = bitcast %T1h1P_pySiXP* %0 to %__opaque_existential_type_1*
%9 = call %swift.opaque* @__swift_project_boxed_opaque_existential_1(%__opaque_existential_type_1* %8, %swift.type* %5) #5
%10 = bitcast %TSi* %2 to i8*
call void @llvm.lifetime.start.p0i8(i64 8, i8* %10)
%11 = getelementptr inbounds i8*, i8** %7, i32 2
%12 = load i8*, i8** %11, align 8, !invariant.load !21
%13 = bitcast i8* %12 to void (%swift.opaque*, %swift.opaque*, %swift.type*, i8**)*
%14 = bitcast %TSi* %2 to %swift.opaque*
call swiftcc void %13(%swift.opaque* noalias nocapture sret(%swift.opaque) %14, %swift.opaque* noalias nocapture swiftself %9, %swift.type* %5, i8** %7)
%._value = getelementptr inbounds %TSi, %TSi* %2, i32 0, i32 0
%15 = load i64, i64* %._value, align 8
store i64 %15, i64* %a.debug, align 8
%16 = bitcast %TSi* %2 to i8*
call void @llvm.lifetime.end.p0i8(i64 8, i8* %16)
ret void
}
; $s1h7useIntPyyAA1P_pySiXPF ---> h.useIntP(h.P<Swift.Int>) -> ()
%T1h1P_pySiXP = type { [24 x i8], %swift.type*, i8** }
define hidden swiftcc void @"$s1h7useIntPyyAA1P_pySiXPF"(%T1h1P_pySiXP* noalias nocapture dereferenceable(40) %0) #0 {
...
}
Intのメモリ確保とopaque型への変換
[.code-highlight: 6, 22]
define hidden swiftcc void @"$s1h7useIntPyyAA1P_pySiXPF"(%T1h1P_pySiXP* noalias nocapture dereferenceable(40) %0) #0 {
entry:
%p.debug = alloca %T1h1P_pySiXP*, align 8
%1 = bitcast %T1h1P_pySiXP** %p.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %1, i8 0, i64 8, i1 false)
%2 = alloca %TSi, align 8
%a.debug = alloca i64, align 8
%3 = bitcast i64* %a.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %3, i8 0, i64 8, i1 false)
store %T1h1P_pySiXP* %0, %T1h1P_pySiXP** %p.debug, align 8
%4 = getelementptr inbounds %T1h1P_pySiXP, %T1h1P_pySiXP* %0, i32 0, i32 1
%5 = load %swift.type*, %swift.type** %4, align 8
%6 = getelementptr inbounds %T1h1P_pySiXP, %T1h1P_pySiXP* %0, i32 0, i32 2
%7 = load i8**, i8*** %6, align 8
%8 = bitcast %T1h1P_pySiXP* %0 to %__opaque_existential_type_1*
%9 = call %swift.opaque* @__swift_project_boxed_opaque_existential_1(%__opaque_existential_type_1* %8, %swift.type* %5) #5
%10 = bitcast %TSi* %2 to i8*
call void @llvm.lifetime.start.p0i8(i64 8, i8* %10)
%11 = getelementptr inbounds i8*, i8** %7, i32 2
%12 = load i8*, i8** %11, align 8, !invariant.load !21
%13 = bitcast i8* %12 to void (%swift.opaque*, %swift.opaque*, %swift.type*, i8**)*
%14 = bitcast %TSi* %2 to %swift.opaque*
call swiftcc void %13(%swift.opaque* noalias nocapture sret(%swift.opaque) %14, %swift.opaque* noalias nocapture swiftself %9, %swift.type* %5, i8** %7)
%._value = getelementptr inbounds %TSi, %TSi* %2, i32 0, i32 0
%15 = load i64, i64* %._value, align 8
store i64 %15, i64* %a.debug, align 8
%16 = bitcast %TSi* %2 to i8*
call void @llvm.lifetime.end.p0i8(i64 8, i8* %16)
ret void
}
openして型、PWT、値の取り出し
[.code-highlight: 11-16]
define hidden swiftcc void @"$s1h7useIntPyyAA1P_pySiXPF"(%T1h1P_pySiXP* noalias nocapture dereferenceable(40) %0) #0 {
entry:
%p.debug = alloca %T1h1P_pySiXP*, align 8
%1 = bitcast %T1h1P_pySiXP** %p.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %1, i8 0, i64 8, i1 false)
%2 = alloca %TSi, align 8
%a.debug = alloca i64, align 8
%3 = bitcast i64* %a.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %3, i8 0, i64 8, i1 false)
store %T1h1P_pySiXP* %0, %T1h1P_pySiXP** %p.debug, align 8
%4 = getelementptr inbounds %T1h1P_pySiXP, %T1h1P_pySiXP* %0, i32 0, i32 1
%5 = load %swift.type*, %swift.type** %4, align 8
%6 = getelementptr inbounds %T1h1P_pySiXP, %T1h1P_pySiXP* %0, i32 0, i32 2
%7 = load i8**, i8*** %6, align 8
%8 = bitcast %T1h1P_pySiXP* %0 to %__opaque_existential_type_1*
%9 = call %swift.opaque* @__swift_project_boxed_opaque_existential_1(%__opaque_existential_type_1* %8, %swift.type* %5) #5
%10 = bitcast %TSi* %2 to i8*
call void @llvm.lifetime.start.p0i8(i64 8, i8* %10)
%11 = getelementptr inbounds i8*, i8** %7, i32 2
%12 = load i8*, i8** %11, align 8, !invariant.load !21
%13 = bitcast i8* %12 to void (%swift.opaque*, %swift.opaque*, %swift.type*, i8**)*
%14 = bitcast %TSi* %2 to %swift.opaque*
call swiftcc void %13(%swift.opaque* noalias nocapture sret(%swift.opaque) %14, %swift.opaque* noalias nocapture swiftself %9, %swift.type* %5, i8** %7)
%._value = getelementptr inbounds %TSi, %TSi* %2, i32 0, i32 0
%15 = load i64, i64* %._value, align 8
store i64 %15, i64* %a.debug, align 8
%16 = bitcast %TSi* %2 to i8*
call void @llvm.lifetime.end.p0i8(i64 8, i8* %16)
ret void
}
PWTから関数の取り出し
[.code-highlight: 19-21]
define hidden swiftcc void @"$s1h7useIntPyyAA1P_pySiXPF"(%T1h1P_pySiXP* noalias nocapture dereferenceable(40) %0) #0 {
entry:
%p.debug = alloca %T1h1P_pySiXP*, align 8
%1 = bitcast %T1h1P_pySiXP** %p.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %1, i8 0, i64 8, i1 false)
%2 = alloca %TSi, align 8
%a.debug = alloca i64, align 8
%3 = bitcast i64* %a.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %3, i8 0, i64 8, i1 false)
store %T1h1P_pySiXP* %0, %T1h1P_pySiXP** %p.debug, align 8
%4 = getelementptr inbounds %T1h1P_pySiXP, %T1h1P_pySiXP* %0, i32 0, i32 1
%5 = load %swift.type*, %swift.type** %4, align 8
%6 = getelementptr inbounds %T1h1P_pySiXP, %T1h1P_pySiXP* %0, i32 0, i32 2
%7 = load i8**, i8*** %6, align 8
%8 = bitcast %T1h1P_pySiXP* %0 to %__opaque_existential_type_1*
%9 = call %swift.opaque* @__swift_project_boxed_opaque_existential_1(%__opaque_existential_type_1* %8, %swift.type* %5) #5
%10 = bitcast %TSi* %2 to i8*
call void @llvm.lifetime.start.p0i8(i64 8, i8* %10)
%11 = getelementptr inbounds i8*, i8** %7, i32 2
%12 = load i8*, i8** %11, align 8, !invariant.load !21
%13 = bitcast i8* %12 to void (%swift.opaque*, %swift.opaque*, %swift.type*, i8**)*
%14 = bitcast %TSi* %2 to %swift.opaque*
call swiftcc void %13(%swift.opaque* noalias nocapture sret(%swift.opaque) %14, %swift.opaque* noalias nocapture swiftself %9, %swift.type* %5, i8** %7)
%._value = getelementptr inbounds %TSi, %TSi* %2, i32 0, i32 0
%15 = load i64, i64* %._value, align 8
store i64 %15, i64* %a.debug, align 8
%16 = bitcast %TSi* %2 to i8*
call void @llvm.lifetime.end.p0i8(i64 8, i8* %16)
ret void
}
関数呼び出し
[.code-highlight: 22, 23, 16, 12, 21]
define hidden swiftcc void @"$s1h7useIntPyyAA1P_pySiXPF"(%T1h1P_pySiXP* noalias nocapture dereferenceable(40) %0) #0 {
entry:
%p.debug = alloca %T1h1P_pySiXP*, align 8
%1 = bitcast %T1h1P_pySiXP** %p.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %1, i8 0, i64 8, i1 false)
%2 = alloca %TSi, align 8
%a.debug = alloca i64, align 8
%3 = bitcast i64* %a.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %3, i8 0, i64 8, i1 false)
store %T1h1P_pySiXP* %0, %T1h1P_pySiXP** %p.debug, align 8
%4 = getelementptr inbounds %T1h1P_pySiXP, %T1h1P_pySiXP* %0, i32 0, i32 1
%5 = load %swift.type*, %swift.type** %4, align 8
%6 = getelementptr inbounds %T1h1P_pySiXP, %T1h1P_pySiXP* %0, i32 0, i32 2
%7 = load i8**, i8*** %6, align 8
%8 = bitcast %T1h1P_pySiXP* %0 to %__opaque_existential_type_1*
%9 = call %swift.opaque* @__swift_project_boxed_opaque_existential_1(%__opaque_existential_type_1* %8, %swift.type* %5) #5
%10 = bitcast %TSi* %2 to i8*
call void @llvm.lifetime.start.p0i8(i64 8, i8* %10)
%11 = getelementptr inbounds i8*, i8** %7, i32 2
%12 = load i8*, i8** %11, align 8, !invariant.load !21
%13 = bitcast i8* %12 to void (%swift.opaque*, %swift.opaque*, %swift.type*, i8**)*
%14 = bitcast %TSi* %2 to %swift.opaque*
call swiftcc void %13(%swift.opaque* noalias nocapture sret(%swift.opaque) %14, %swift.opaque* noalias nocapture swiftself %9, %swift.type* %5, i8** %7)
%._value = getelementptr inbounds %TSi, %TSi* %2, i32 0, i32 0
%15 = load i64, i64* %._value, align 8
store i64 %15, i64* %a.debug, align 8
%16 = bitcast %TSi* %2 to i8*
call void @llvm.lifetime.end.p0i8(i64 8, i8* %16)
ret void
}
- 三角括弧での型パラメータ指定をexistentialにも適用した
- upper boundがより正確になる
- 利用箇所のシグネチャに影響する
- Existentialのレイアウトには変化なし
- someの用法が拡大した
- anyが導入され、用法が拡大した
- upper boundによるeraseの概念が追加された
- 自然なopenができるようになった
- primary associated typeが導入された
- 非primaryなassociated typeのexistentialへの指定
- existentialの自己準拠文法
- Reverse Genericsによる自由なORT
Footnotes
-
https://github.com/apple/swift-evolution/blob/main/proposals/0309-unlock-existential-types-for-all-protocols.md
↩ -
https://github.com/apple/swift-evolution/blob/main/proposals/0328-structural-opaque-result-types.md
↩ -
https://github.com/apple/swift-evolution/blob/main/proposals/0335-existential-any.md
↩ -
https://github.com/apple/swift-evolution/blob/main/proposals/0341-opaque-parameters.md
↩ -
https://github.com/apple/swift-evolution/blob/main/proposals/0346-light-weight-same-type-syntax.md
↩ -
https://github.com/apple/swift-evolution/blob/main/proposals/0352-implicit-open-existentials.md
↩ -
https://github.com/apple/swift-evolution/blob/main/proposals/0353-constrained-existential-types.md
↩ -
https://github.com/apple/swift/blob/main/docs/Generics.rst
↩ -
https://github.com/apple/swift/blob/main/docs/GenericsManifesto.md
↩ -
https://forums.swift.org/t/improving-the-ui-of-generics/22814
↩ -
https://github.com/apple/swift/blob/main/include/swift/ABI/ValueWitness.def
↩ -
https://github.com/apple/swift/blob/main/docs/ABI/TypeLayout.rst#existential-container-layout
↩ ↩2 ↩3 -
https://github.com/apple/swift/blob/main/test/type/opaque_return_structural.swift
↩ -
https://github.com/apple/swift-evolution/blob/main/proposals/0341-opaque-parameters.md#opaque-parameters-in-consuming-positions-of-function-types
↩