spec: ignore channel direction during loose unification
要約
概要
型パラメータの制約に「方向付きチャネル型」(chan<- E や <-chan E)が混ざっていると、要素型 E が推論できなくなる問題を解消する言語仕様の変更提案です。型推論の「loose unification(緩い単一化)」の段階でチャネルの方向を無視するようにします。
ステータス変更
likely_accept → active
2026年11月4日のレビューで、仕様の差分付きで一度 likely accept とされました。翌日、@Merovius が「提案本文の例 Close は成立しない」と指摘しました。close は送信可能なチャネルにしか使えないため、<-chan E を含む制約では関数本体の型チェックで弾かれます。参考になった #69153 の例も close ではなく cap を使っています。@Merovius 自身は「推論の話なので提案の本質には影響しない」と添えています。これを受けて @aclements が「likely accept から外し、@griesemer が考え直す」と述べ、active に戻りました。issue 上には、指摘以外の差し戻し理由は書かれていません。仕様の文言や設計を詰め直すための差し戻しと考えられます。
技術的背景
現状の問題点
Goの型推論では、引数の型と制約を突き合わせて型引数を決めます。現在の仕様では、制約の型集合がすべて同じ要素型のチャネルであり、かつ方向が衝突しないこと(core type、つまり型集合に共通する基底型が存在すること)が推論の条件です。chan T | <-chan T なら推論できますが、chan T | <-chan T | chan<- T のように送信専用と受信専用が両方入ると推論できません。これは廃止が進む core type 概念の名残です。
type channelConstraint[T any] interface {
chan T | <-chan T | chan<- T
}
func printCap[T any, C channelConstraint[T]](ch C) { fmt.Println(cap(ch)) }
var r <-chan int = make(chan int, 1)
printCap(r) // error: cannot infer T
提案された解決策
仕様の型単一化ルールを次のように変更します。
- 制約
Cの型集合がすべて同じ要素型のチャネル型である場合、条件から「方向が衝突しないこと」を削除します。そのうえで「最も制限的なチャネル型」ではなく「任意のチャネル型」と型引数Aを緩く単一化します。 - loose unification のルールに次の項目を追加します。「両方がチャネル型で、要素型が単一化できればよい。チャネルの方向は無視する。」
既存のプログラムの動作は変わらず、受理されるプログラムが増えるだけなので、後方互換性があります。コストは、コンパイラの単一化処理への関数1つの追加と、制約ごとに1回の型アサーションです。
これによって何ができるようになるか
方向を問わずチャネルを受け取る汎用ヘルパーを、型引数を明示せずに呼べるようになります。
len/capを使ってバッファの使用状況を監視するユーティリティ- 送受信の方向が混在するコードベースでの共通ヘルパー(ログ出力、メトリクス収集など)
- チャネルを抽象化するジェネリックなライブラリAPI
コード例
// Before: 要素型を明示する必要がある
printCap[string](sendOnlyCh)
printCap[int](receiveOnlyCh)
printCap[any](bidiCh)
// After: 方向に関係なく要素型が推論される
printCap(sendOnlyCh)
printCap(receiveOnlyCh)
printCap(bidiCh)
議論のハイライト
- 提案者の @mcy は、プロトタイプ実装 CL 829606 を用意したうえで提案しています。この CL は既知のバグ #69153 の修正にもなります。
- #69153 で @griesemer は、原因を「制約に core type がないこと」と説明しています。
chan T | <-chan Tなら推論できますが、その場合は制約に含まれない方向のチャネルで関数を実体化(インスタンス化)できない、というジレンマも指摘しています。 - @Merovius は、提案本文の
closeの例はそもそも型チェックを通らないと指摘しました。推論の話なので本質的な影響はないとしています。この指摘が likely accept からの差し戻しのきっかけになりました。 - 関連する議論として、チャネル型の推論の柔軟化(#45920、#65202)、十分に制約された制約からの推論(#73527)、
len/capなどの組み込み関数に対する core type 制限の撤廃(#63940)があります。