メインコンテンツへスキップ
#81822active

spec: ignore channel direction during loose unification

新規提案

要約

AIによる要約であり、誤りを含む場合があります。

概要

chan E | chan<- E | <-chan E のように、向き(送信専用・受信専用・双方向)の違うチャネル型をまとめた制約では、現在は要素型 E を型推論できません。この proposal は、型推論の「loose unification(緩い単一化)」でチャネルの向きを無視するよう言語仕様を変え、こうした場合にも E を推論できるようにするものです。

ステータス変更

(新規) → active
2026年10月29日、@aclements が proposal review group を代表して、この proposal を active 列に追加しました。今後は週次の proposal review meeting で議論されます。提案者 @mcy は実装 CL(CL 829606)を既に用意しており、仕様変更が承認され次第取り込める状態です。もとになったバグ報告 #69153 は 2024 年から未解決で、Go 1.24、1.25 とマイルストーンが先送りされてきました。仕様を変える必要があるため、proposal として正式に審議することになったと考えられます。

技術的背景

現状の問題点

現在の仕様では、制約 C の型集合が「要素型が同じで、向きが矛盾しない」チャネル型だけで構成されている場合に限り、そのうち最も制限の強いチャネル型と実引数の型を loose unification します。

  • chan T | <-chan T は推論できる(最も制限が強い <-chan T を使う)
  • chan T | <-chan T | chan<- T は推論できない(<-chan と chan<- が矛盾し、共通の型を選べない)
    この制限は、ジェネリクスの初期設計にあった「core type(型集合に共通する唯一の基底型)」という概念の名残です。core type は Go 1.25 で仕様から取り除かれました(#70128)。#69153 で @griesemer も、原因は「制約に core type がないこと」だと説明しています。

提案された解決策

CL 829606 では、仕様の Type unification の節を次のように変更します。

  1. 制約に由来する型方程式の条件を緩める。「要素型が同じで向きが矛盾しない」を「要素型が同じ」に変え、「最も制限の強いチャネル型」を「型集合内の任意のチャネル型」に変える。
  2. loose unification の規則に「両方がチャネル型なら、要素型を unify し、チャネルの向きは無視する」を追加する。
    コンパイラ側の変更は小さく、types2 と go/types の infer.go・under.go に関数を 1 つ追加する程度です。CL の説明によれば、チャネル型だけで制約された型パラメータについて、推論のためだけに型集合内のチャネル型のどれか 1 つを代わりに使います。リリースノートの草案(doc/next/2-language.md)も CL に含まれています。

これによって何ができるようになるか

チャネルの向きを問わずに受け取る汎用ヘルパーを、呼び出し側で型引数を書かずに使えるようになります。

  • close を呼ぶ汎用の Close 関数
  • len/cap でバッファの埋まり具合を監視するユーティリティ(#69153 の元の用途)
  • 送信専用・受信専用・双方向のチャネルが混在するコードベースでの、メトリクス収集やデバッグ用ヘルパー

コード例

type anyChan[T any] interface {
	chan T | <-chan T | chan<- T
}
func printCap[T any, C anyChan[T]](ch C) {
	fmt.Println(cap(ch))
}
// Before: 要素型を毎回明示する必要がある
var send chan<- string = make(chan string)
printCap(send)          // error: cannot infer T
printCap[string](send)  // OK(ワークアラウンド)
// After: 向きに関係なく T が推論される
printCap(send)               // T = string
printCap(make(<-chan int))   // T = int
printCap(make(chan any))     // T = any

議論のハイライト

  • issue のコメントは、提案者の cc、gabyhelp による関連 issue の一覧、active 化の告知だけで、技術的な議論はまだ始まっていません。
  • #69153 では @ianlancetaylor が「チャネル型には特別な型推論ルールが必要になるだろう」と述べ、@griesemer は原因が core type の欠如にあると説明しています。今回の提案はこの見立てに沿った最小限の変更です。
  • 提案者によれば後方互換性は完全に保たれます。既存のプログラムの動作は変わらず、これまでコンパイルエラーだったプログラムが新たに通るようになるだけです。
  • 性能面のコストは、推論アルゴリズムで制約ごとに型アサーションが 1 回増える程度とされています。
  • 関連する未解決の issue に #65202 があります。~<-chan E 制約に双方向の chan int を渡すと、制約を満たさないというエラーになる問題です。ただし、これは推論ではなく「制約を満たすか」の判定の問題で、今回の提案の対象外と考えられます。

関連リンク