Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

エフェクト、const trait、および const 条件チェック

HostEffect 述語

HostEffectPredicate は、[const] Tr または const Tr 境界に由来する述語の一種です。 これは trait 参照と、境界に応じて Maybe または Const になり得る constness を持ちます。 [const] Tr、より正確には Maybe 境界は、 それが置かれているコンテキストに応じて異なる適用のされ方をするため、通常の境界とは異なる 振る舞いをします。 T: Tr のような関数上の通常の trait 境界は、関数が呼び出されるときに証明され、 関数内で仮定されるものとして predicates_of クエリ内に収集されますが、 T: [const] Tr のような境界は通常の trait 境界として振る舞い、predicates_of の結果に T: Tr を追加する一方で、const_conditions クエリにも HostEffectPredicate を追加します。

一方、T: const Tr 境界はコンテキストをまたいでも意味が変わらないため、 predicates_of には HostEffect(T: Tr, const) が追加され、 const_conditions には追加されません。

const_conditions クエリ

predicates_of は、ある item を使用するために証明する必要がある述語の集合を表します。 たとえば、以下の例で foo を使用するには次のようにします。

#![allow(unused)]
fn main() {
fn foo<T>() where T: Default {}
}

TDefault を実装していることを証明できなければなりません。 同様に、 const_conditions は、ある item を const コンテキスト内で 使用するために 証明する必要がある述語の集合を表します。上の例を const trait 境界を使うように調整すると、次のようになります。

#![allow(unused)]
fn main() {
const fn foo<T>() where T: [const] Default {}
}

この場合、fooconst_conditions クエリ内に HostEffect(T: Default, maybe) を持つことになり、 const コンテキストから foo を呼び出すためには、TDefault の const 実装を持つことを 証明しなければならないことを示します。

const_conditions の強制

const_conditions は現在、さまざまな場所でチェックされています。

const コンテキスト(const fnconst item を含む)からの HIR 内のすべての呼び出しでは、 呼び出している関数の const_conditions が成り立つことをチェックします。 これは FnCtxt::enforce_context_effects で行われます。 以下のコードはコンパイルされる必要があるため、 関数が参照されているだけで呼び出されていない場合はチェックしないことに注意してください。

#![allow(unused)]
fn main() {
const fn hi<T: [const] Default>() -> T {
    T::default()
}
const X: fn() -> u32 = hi::<u32>;
}

trait impl が well-formed であるためには、impl の環境から trait の const_conditions を証明できなければなりません。 これは wfcheck::check_impl でチェックされます。

例を示します。

#![allow(unused)]
fn main() {
const trait Bar {}
const trait Foo: [const] Bar {}
// `const_conditions` には `HostEffect(Self: Bar, maybe)` が含まれる

impl const Bar for () {}
impl const Foo for () {}
// ^ ここで impl が well-formed であるための `const_conditions` をチェックする
}

trait impl のメソッドは、それが実装している trait のメソッドよりも厳しい境界を持ってはなりません。 メソッドに互換性があることをチェックするために、 impl の述語に trait メソッドの述語を加えたハイブリッド環境が構築され、 impl メソッドの述語を証明しようとします。 const_conditions についても同じことを行います。

#![allow(unused)]
fn main() {
const trait Foo {
    fn hi<T: [const] Default>();
}

impl<T: [const] Clone> Foo for Vec<T> {
    fn hi<T: [const] PartialEq>();
    // ^ `T: [const] Clone` と `T: [const] Default` が与えられても
    // `T: [const] PartialEq` を証明できないため、impl 上のメソッドが
    // trait 上のメソッドよりも厳しいことがわかる。
}
}

これらのチェックは compare_method_predicate_entailment で行われます。 関連型に対して同じチェックを行う類似の関数は compare_type_predicate_entailment と呼ばれます。 これらはどちらも、const コンテキスト内では const_conditions を考慮する必要があります。

MIR では、const チェックの一部として、呼び出される item の const_conditionsChecker::revalidate_conditional_constness で再度検証されます。

関連型と trait における explicit_implied_const_bounds

以下のような関連型、不透明型、および supertrait 上の境界は、 その境界が異なる形で表現されます。

#![allow(unused)]
fn main() {
trait Foo: [const] PartialEq {
    type X: [const] PartialEq;
}

fn foo() -> impl [const] PartialEq {
    // ^ 未実装の構文
}
}

const_conditions は呼び出し元に対して証明される必要があり、 定義内(たとえば関数上の trait 境界)では仮定できますが、これらの境界は定義時(impl 内、 または opaque を返すとき)に証明される必要があり、呼び出し元では仮定できます。 これらの境界の非 const 版は explicit_item_bounds と呼ばれます。

これらの境界は、HIR typeck では compare_impl_item::check_type_bounds、古い solver では evaluate_host_effect_from_item_bounds、 新しい solver では consider_additional_alias_assumptions でチェックされます。

HostEffectPredicate の証明

HostEffectPredicate は [old solver] と [new trait solver] の両方で実装されています。 一般に、次のいずれかの条件を満たす場合に HostEffect 述語を証明できます。

* 述語は呼び出し元の境界から仮定できます。
* 型がそのトレイトに対する `const` `impl` を持ち、*かつ* その impl 上の const 条件が
  成立し、*かつ* そのトレイトの `explicit_implied_const_bounds` が成立する場合。または
* 型が const コンテキストにおいてそのトレイトの組み込み実装を持つ場合。
  たとえば、`Fn` は、その const 条件が満たされていれば関数アイテムによって実装されることがあり、
  また `Destruct` は、その型をコンパイル時にドロップできる場合に const コンテキストで実装されます。

[old solver]: https://doc.rust-lang.org/nightly/nightly-rustc/src/rustc_trait_selection/traits/effects.rs.html
[new trait solver]: https://doc.rust-lang.org/nightly/nightly-rustc/src/rustc_next_trait_solver/solve/effect_goals.rs.html

## const トレイトの詳細

後で拡充予定です。

### `#[rustc_non_const_trait_method]` 属性

これは内部(標準ライブラリ)での使用のみを意図しています。
この属性をトレイトメソッドに適用すると、コンパイラはこのメソッドのデフォルト本体が
コンパイル時に実行可能かどうかをチェックしません。
そのトレイトのユーザーも、このトレイトメソッドを const コンテキストで使用することは許可されません。
この属性は主に、
`Iterator` のような大規模なトレイトを、そのすべてのメソッドを同時に `const` にすることなく
const 化するために使用されます。

この属性は、トレイトを `const` として安定化する際には存在していてはなりません。