メインコンテンツにスキップ

Union型とIntersection型の新しい実装

概要

Flow 0.28より前では、union型/intersection型の実装に深刻なバグがあり、過去にFlowで遭遇した多くの奇妙な動作の根本原因となっていました (これこれこれこれこれこれこれこれこれなど)。これらのバグは、0.28の差分で修正されました。

型システム実装の複雑な部分の大幅な書き換え後には予想されるように、短い調整期間があります。すぐに解決しようとする問題が発生したり、なじみのないエラーメッセージが表示される場合があります。

新しいエラーメッセージ

<error location> Could not decide which case to select
<location of union/intersection type>

Case 1 may work:
<location of 1st case of union/intersection type>

But if it doesn't, case 2 looks promising too:
<location of 2nd case of union/intersection type>

Please provide additional annotation(s) to determine whether case 1 works
(or consider merging it with case 2):
<location to annotate>
<location to annotate>
...

これは、<エラーの場所> で、Flowが選択を行う必要があることを意味します。<union型/intersection型の場所> にあるunion型/intersection型のメンバーの1つを適用する必要がありますが、Flowは利用可能な情報に基づいて安全に選択できません。特に、ケース1とケース2を区別できないため、Flowは2つのケースを明確にするのに役立つアノテーションを一覧表示します。

必要なアクション

エラーを修正するには、2つの方法があります。

  • 実際に、リストされている場所にアノテーションを付けます。これは、最も一般的な修正方法です。
  • ケース1とケース2の間に意図しないあいまいさがあることを発見し、あいまいさをなくすようにunion型の2つのケースを書き直します。これが発生すると、通常は多数のエラーが修正されます。

しかし、さらに2つの可能性があります。

  • 実際にはあいまいさがないのに、Flowが保守的すぎる/愚かである。この場合は、とにかくアノテーションを行い、GitHubに問題を報告してください。短期的なフォローアップ作業を多く行い、より多くのケースを自動的に明確にする予定なので、時間の経過とともに(3)は少なくなっていくはずです。
  • 何が起こっているのかわからない。指摘されているケースが意味をなさない。 <エラーの場所> にあるものに対応していない。うまくいけば(4)に遭遇することはあまりないでしょうが、もし遭遇した場合は、実装に潜在的なバグがまだあることを意味するため、**問題を報告してください**。

GitHubに問題を報告する場合は、問題を再現するためのコードを含めてください。 Try Flow を使用すると、再現ケースを簡単に共有できます。

これらの新しいエラーメッセージの理由と方法について詳しく知りたい場合は、「unionの運命」差分のコミットメッセージからの抜粋を以下に示します。

問題

Flowの推論エンジンは、制約が追加されるにつれて時間の経過とともに المزيدのエラーを見つけるように設計されています...しかし、バックトラックするように設計されていません。残念ながら、union型に対する式の型のチェックにはバックトラックが必要です。union型のブランチがうまくいかない場合は、次のブランチを試す必要があり、以降も同様です。(intersection型を含むチェックにも同じことが当てはまります。)

チェック時点で式の型が完全にはわからない場合があるため、状況はさらに複雑になります。そのため、今は有望に見えるブランチが後で正しくないことが判明する可能性があります。

解決策

基本的な考え方は、さらなる情報なしに、ブランチが確実に失敗するか成功するかを判断できるようになるまで、ブランチを試すのを遅らせることです。ブランチを試した結果、失敗した場合は、バックトラックすることなく次のブランチに進むことができます。ブランチが成功した場合は、完了です。最後のケースは、ブランチは有望に見えますが、制約を追加しないと確信が持てない場合です。この場合は、他のブランチを試してみて、あいまいさに遭遇したときに *ベイルアウト* し、どのブランチを選択するかを決定するための追加のアノテーションを要求します。全体として、これは(1)正しくないことが判明する可能性のあるブランチにコミットすることは決してなく、(2)十分なアノテーションがあれば常に正しいブランチ(そのようなブランチが存在する場合)を選択できることを意味します。