Goにジェネリクスが来るぞ!ということで早速試してみることにする。
適当にmasterをクローンして cd src && ./make.bash
でビルド(これだけでビルドできるの楽ちん)。
$ go version go version devel go1.18-6602c86a38 Fri Sep 17 08:20:48 2021 +0000 linux/amd64
いろいろ遊んでみたところで、以下のようなコードを書いた時にインターナルコンパイルエラー(ICE)に遭遇した。
package main import "fmt" func Foo[T interface{ int }, S interface{ *T }](x T) S { return &x } func main() { x := 42 y := Foo(x) fmt.Println(*y) }
コンパイルエラーの出力はこのような感じ。
$ ../go/bin/go build -gcflags=-G=3 foo.go # command-line-arguments ./foo.go:7:9: internal compiler error: found illegal assignment PTR-*.shape.int_0 -> .shape.*uint8_1; goroutine 1 [running]: runtime/debug.Stack() /home/kubo39/dev/go/go/src/runtime/debug/stack.go:24 +0x65 cmd/compile/internal/base.FatalfAt({0x0, 0x0}, {0xd0ffd4, 0x27}, {0xc00045cd60, 0x3, 0x3}) /home/kubo39/dev/go/go/src/cmd/compile/internal/base/print.go:227 +0x154 cmd/compile/internal/base.Fatalf(...) /home/kubo39/dev/go/go/src/cmd/compile/internal/base/print.go:196 cmd/compile/internal/noder.assignconvfn({0xe6c010, 0xc000463220}, 0xc00041dab0) /home/kubo39/dev/go/go/src/cmd/compile/internal/noder/transform.go:417 +0x1b2 cmd/compile/internal/noder.typecheckaste(0x98, {0xc0004631d0, 0xc000463220}, 0x0, 0xc00045ce80, {0xc000408a00, 0x1, 0xc00045ce80}) /home/kubo39/dev/go/go/src/cmd/compile/internal/noder/transform.go:484 +0x179 cmd/compile/internal/noder.transformReturn(0xc0004631d0) /home/kubo39/dev/go/go/src/cmd/compile/internal/noder/transform.go:505 +0xa8 cmd/compile/internal/noder.(*subster).node.func1({0xe6e270, 0xc000443a90}) /home/kubo39/dev/go/go/src/cmd/compile/internal/noder/stencil.go:993 +0x7cb cmd/compile/internal/noder.(*subster).node(0xc00041db20, {0xe6e270, 0xc000443a90}) /home/kubo39/dev/go/go/src/cmd/compile/internal/noder/stencil.go:1166 +0xa5 cmd/compile/internal/noder.(*subster).list(0xc000404300, {0xc000408800, 0x1, 0xc0000be550}) /home/kubo39/dev/go/go/src/cmd/compile/internal/noder/stencil.go:1418 +0x8e cmd/compile/internal/noder.(*irgen).genericSubst(0xc00045e000, 0xc000462ff0, 0xc000460000, {0xc000408980, 0x2, 0x2}, 0x0, 0xc00040cb28) /home/kubo39/dev/go/go/src/cmd/compile/internal/noder/stencil.go:765 +0xce6 cmd/compile/internal/noder.(*irgen).getInstantiation(0xc00045e000, 0xc000460000, {0xc000408970, 0x2, 0x2}, 0x0) /home/kubo39/dev/go/go/src/cmd/compile/internal/noder/stencil.go:643 +0x2b0 cmd/compile/internal/noder.(*irgen).stencil.func1({0xe6c718, 0xc000430480}) /home/kubo39/dev/go/go/src/cmd/compile/internal/noder/stencil.go:108 +0x2df cmd/compile/internal/ir.Visit.func1({0xe6c718, 0xc000430480}) /home/kubo39/dev/go/go/src/cmd/compile/internal/ir/visit.go:105 +0x30 cmd/compile/internal/ir.(*AssignStmt).doChildren(0xc000443d60, 0xc00040cb10) /home/kubo39/dev/go/go/src/cmd/compile/internal/ir/node_gen.go:152 +0x82 cmd/compile/internal/ir.DoChildren(...) /home/kubo39/dev/go/go/src/cmd/compile/internal/ir/visit.go:94 cmd/compile/internal/ir.Visit.func1({0xe6c330, 0xc000443d60}) /home/kubo39/dev/go/go/src/cmd/compile/internal/ir/visit.go:106 +0x57 cmd/compile/internal/ir.doNodes({0xc000417380, 0x4, 0x0}, 0xc00040cb10) /home/kubo39/dev/go/go/src/cmd/compile/internal/ir/node_gen.go:1512 +0x67 cmd/compile/internal/ir.(*Func).doChildren(0xe6d078, 0xc00040a420) /home/kubo39/dev/go/go/src/cmd/compile/internal/ir/func.go:152 +0x2e cmd/compile/internal/ir.DoChildren(...) /home/kubo39/dev/go/go/src/cmd/compile/internal/ir/visit.go:94 cmd/compile/internal/ir.Visit.func1({0xe6d078, 0xc00040a420}) /home/kubo39/dev/go/go/src/cmd/compile/internal/ir/visit.go:106 +0x57 cmd/compile/internal/ir.Visit({0xe6d078, 0xc00040a420}, 0xc0004174c0) /home/kubo39/dev/go/go/src/cmd/compile/internal/ir/visit.go:108 +0xb8 cmd/compile/internal/noder.(*irgen).stencil(0xc00045e000) /home/kubo39/dev/go/go/src/cmd/compile/internal/noder/stencil.go:90 +0x238 cmd/compile/internal/noder.(*irgen).generate(0xc00045e000, {0xc00009eb40, 0x2, 0x2}) /home/kubo39/dev/go/go/src/cmd/compile/internal/noder/irgen.go:301 +0x359 cmd/compile/internal/noder.check2({0xc00009eb40, 0x2, 0x2}) /home/kubo39/dev/go/go/src/cmd/compile/internal/noder/irgen.go:93 +0x175 cmd/compile/internal/noder.LoadPackage({0xc0000b8100, 0x2, 0x0}) /home/kubo39/dev/go/go/src/cmd/compile/internal/noder/noder.go:90 +0x335 cmd/compile/internal/gc.Main(0xd23420) /home/kubo39/dev/go/go/src/cmd/compile/internal/gc/main.go:190 +0xaf3 main.main() /home/kubo39/dev/go/go/src/cmd/compile/main.go:55 +0xdd
エラーになっているのは return文 return &x
の型と関数の返り値の型 S
(実態は interface { *T }
) の型チェックを行った際に、
transform.assignconvfn -> transform.Assignop -> typecheck.Assignop1 で解決できないまま素通しになった結果illegal assignment扱いになっているためだが、
そもそも S interface { *T }
が *uint8
になっているのがおかしいようにみえる。
(どうでもいいがtransform.Assignopはなぜかtypecheck.Assignopと同じ定義になっており、transform側の定義は冗長なためここを消すcontribution chanceがある)。
サクッと直せないだろうかとてきとうにあたりをつけながらみてみたが、パッと修正箇所がみつからなかったのでとりあえずこんなことがあったくらいの話になってしまった。。
というわけでGoのジェネリクスはまだバグがありそうなので、皆さんでコーナーケース探して修正していくとよさそうです。
追記 (2021/09/21)
このパッチ で修正されました。 なんかshapeな型として*uint8くるのは別に間違ってないっぽい。。?このへんgcshapeの意味とってないのでよくわかんないですが。 なおこの変更によってtransformとtypecheckのAssignopの実装に乖離が生まれたので定義の冗長さも消えました、よかったですね(?)