クロージャ制約の伝播
型テストとユニバーサルリージョンを検査しているとき、クロージャ本体内にいる場合には、まだ証明できない制約に遭遇することがあります!しかし、必要な制約が実際には成り立っている可能性があります(まだそれが分からないだけです)。したがって、クロージャ内にいる場合は、まだ証明できないすべての制約を収集して返すだけにします。後で、そのクロージャを作成した MIR ノードを借用検査するときに、これらの制約が成り立つことも検査できます。その時点で、それらが成り立つことを証明できなければ、エラーを報告します。
これがどのように実装されているか
RegionInferenceContext::solve 内でクロージャを借用検査している間、型 outlives 制約とリージョン outlives 制約をローカルで証明できない場合には、それらを親へ伝播しようと別々に試みます。
リージョン outlives 制約
RegionInferenceContext::check_universal_regions が何らかの outlives 制約 'longer_fr: 'shorter_fr の証明に失敗した場合、fn try_propagate_universal_region_error でそれを伝播しようとします。これらのユニバーサルリージョンはいずれも、クロージャにローカルなリージョンか、外部リージョンのどちらかです。
'longer_fr がローカルなユニバーサルリージョンである場合、'longer_fr によって outlive される最大の外部リージョン 'fr_minus、つまり 'longer_fr: 'fr_minus を探します。そのようなリージョンが複数ある場合は、mutual_immediate_postdominator を選びます。これはすべての GLB の GLB を繰り返し計算することによる不動点です。詳細については TransitiveRelation::postdom_upper_bound を参照してください。
'fr_minus が存在する場合、それが 'shorter_fr のすべての非ローカル上限よりも長く生存することを要求します。少なくとも 1 つの非ローカル上限 'static は常に存在します。
型 outlives 制約
型 outlives 制約は check_type_tests で証明されます。これは outlives グラフの計算後に行われ、そのグラフはこの時点では不変です。
クロージャ内の fn eval_verify_bound によって証明できなかったすべての型テストについて、try_promote_type_test を呼び出します。TypeTest は、verify_bound とともに型 outlives 境界 generic_kind: lower_bound を表します。VerifyBound が lower_bound に対して成り立つ場合、その制約は満たされます。try_promote_type_test は verify_bound を気にしません。
これは fn try_promote_type_test_subject を呼び出すことから始まります。この関数は GenericKind を受け取り、クロージャにローカルなものをもはや何も参照しない ClosureOutlivesSubject へ変換しようとします。これは、その型内のすべての自由リージョンを、'static またはその自由リージョンと等しいリージョンパラメータのいずれかに置き換えることで行われます。generic_kind に置き換えられないリージョンが含まれている場合、この操作は失敗します。
次に、lower_bound を呼び出し元のコンテキストに昇格します。下限がプレースホルダーと等しい場合、それを 'static に置き換えます
次に、lower_bound によって outlive される必要があるすべてのユニバーサルリージョン uv、つまり借用検査がリージョン制約を追加したものを確認します。これらのそれぞれについて、uv よりも長く生存することが分かっているすべての非ローカルなユニバーサルリージョンに対して ClosureOutlivesRequirement を出力します。
この時点ではすでにクロージャのリージョングラフを構築しており、それが一貫していることも別途検査しているため、ここでは outlives 制約 uv: lower_bound を仮定することもできます。
したがって、証明できない型 outlives 境界、たとえば T: 'local_infer がある場合、リージョングラフを使用して 'a: local_infer を満たすユニバーサル変数 'a に移動します。'a がローカルな場合は、仮定された outlived 制約を使用して非ローカルなものに移動します。
次に、昇格された型テストのリストを BorrowCheckResults に格納します。
その後、その親を借用検査している間に TypeChecker::prove_closure_bounds でそれらを適用します。
TODO: それが正確にどのように機能するかを説明する :3