Electrolysisを使ってみた
概要: ElectrolysisはRustの検証条件をLEANに出力するプロジェクトである。これを使ってみた。
Electrolysisとは
Electrolysis (electrolysis: 電解) はSebastian Ullrich氏の修士研究で開発されたプロジェクトで、Rustプログラムの正当性や計算量に関する検証条件をLean Theorem Proverの命題として出力する機能を提供する。
なお、GitHubの様子だと、このプロジェクトは修論の日付からほぼ開発がストップしているようだ。Ullrich氏はその後、Electrolysisの成果の一部をLEANに還元するなどの活動をしているようだ。
Electrolysisの実行
以下、Ubuntu 16.04を仮定する。
ElectrolysisはRustのコンパイラプラグインとして実装されているため、Rustの特定のnightlyバージョンに強く依存している。また、libcore
自体を検証ターゲットにしているため、Rustコンパイラのソースコード自体も取得する必要がある。
$ git clone https://github.com/Kha/electrolysis.git $ cd electrolysis $ rustup override add $(cat rust-nightly-version) $ rustup component add rust-src $ cargo run core $ cargo run alloc $ cargo run collections $ cargo run fixedbitset
petgraphに対する検証条件の出力
petgraph
に対する検証条件の出力はやや面倒である。まずpetgraphを取得してビルドする。
$ git submodule update --init $ cd thys/petgraph/src $ cargo build $ cd ../../..
次に thys/petgraph/config.toml
を編集して、libfixedbitset
のrlibのハッシュを適切に置き換える。例えば、
rustc_args = "thys/petgraph/src/src/lib.rs --crate-name petgraph --crate-type lib -L dependency=thys/petgraph/src/target/debug/deps --extern fixedbitset=thys/petgraph/src/target/debug/deps/libfixedbitset-0ba3fe99bd419295.rlib" targets = [ "algo.scc", ]
とすると以下が通る。
$ cargo run petgraph
Lean2のビルド
Leanは現在、過去の証明との互換性のために残されている0.2.0系列と、最新の3.0.0系列がある。Electrolysisに適しているのは0.2.0系列なので、そちらを使う。
また、lean2のビルドスクリプトにはninjaを取得する部分があるが、ninjaの取得先が削除されてしまっているので、以下のパッチを当てる必要がある。(以下これをlinja.patch
と呼ぶ)
diff --git a/bin/linja.in b/bin/linja.in index 926f33e..10ee37d 100755 --- a/bin/linja.in +++ b/bin/linja.in @@ -239,7 +239,7 @@ def show_download_progress(*data): log_nonewline("Download: size\t= %i kb, packet: %i/%i" % (file_size, downloaded_packets, total_packets+1)) def get_ninja_url(): - prefix = "https://leanprover.github.io/bin/" + prefix = "https://github.com/leanprover/leanprover.github.io/raw/8fb36e926a3c4df8b84bfafedb7f39687f24b93b/bin/" if platform.architecture()[0] == "64bit": if platform.system() == "Linux": return prefix + "ninja-1.5.1-linux-x86_64"
$ sudo apt install python3 git libgmp-dev libmpfr-dev $ git clone https://github.com/leanprover/lean2.git $ cd lean2 $ patch -p1 < path/to/linja.patch $ mkdir -p build/release $ cd build/release $ cmake -DCMAKE_BUILD_TYPE=Release ../../src $ make -j4 install DESTDIR=.
上の例ではDESTDIR=.
を指定することで./usr/local
にインストールしているが、これを外せば/usr/local
にインストールされる。
検証条件に対するLEAN2の実行
lean2にはlean3のような--make
オプションがついていない。以下のようなMakefileをthys
の直下に置くとよい。(LEANDIR
を適切に変更する)
#!/usr/bin/make -f LEANDIR = /somewhere/lean2/build/release/usr/local LEAN = $(LEANDIR)/bin/lean LEAN_SOURCES = $(shell find . -name '*.lean') LEAN_BINARIES = $(LEAN_SOURCES:.lean=.olean) LEAN_DEPFILES = $(LEAN_SOURCES:.lean=.d) all: $(MAKE) deps $(MAKE) all2 deps: $(LEAN_DEPFILES) all2: $(LEAN_BINARIES) clean: $(RM) $(LEAN_DEPFILES) $(LEAN_BINARIES) .PHONY: all deps all2 clean %.d: %.lean (echo $<:; $(LEAN) --deps $<) | tr '\n' ' ' > $@ %.olean: %.lean $(LEAN) $< -o $@ -include $(LEAN_DEPFILES)
これを配置した上で thys
直下で make
を実行すると、証明がコンパイルされる。
まとめと感想
Electrolysisの機能を一通り動かすことができた。
実は別のRustバージョンや別のLeanバージョンで動かせないか検討したがかなり困難であることがわかった。
Rustの検証プロジェクトではむしろRustBeltが有名で、メンバーから考えてもかなり期待が持てる。RustBeltとElectrolysisは以下のように異なる。
- 検証の目的: RustBeltはunsafeな動作を含むより低レベルな操作に対し、UBを踏まないなどの証明をターゲットにしている。Electrolysisはより高級な変換で、アルゴリズムの正当性や計算量の検証を目指している。
- ロジック: RustBeltは高階並行分離論理フレームワークIrisに立脚している。
- 証明支援系: RustBeltはCoqで検証する。ElectrolysisはLeanで検証する。
- 検証条件の抽出: Electrolysisは実際のRustコード(MIR)からの抽出に対応している。RustBeltは今のところMIRからの抽出には対応していない(Coq側の対応するコードは手動で書かれている)が、Ralf Jung氏が最近MIRの改造に取り組んでいるところから見るに、そのうち対応すると思われる。
Rust組込みトレイトのコヒーレンス
以下のトレイトは通常のコヒーレンス規則に加えて、特別なコヒーレンス規則が適用される。
Sized
, Unsize
Sized
, Unsize
の手動実装を与えることはできない。
Fn
, FnMut
, FnOnce
Fn
, FnMut
, FnOnce
の手動実装は安定版では禁止されており、 #![feature(unboxed_closures)]
が必要である。
Drop
Drop
はユーザー定義の構造体・列挙型・共用体にのみ定義できる。
また、(なぜかコヒーレンスチェッカーではなくDropチェッカーの一部になっているが)Drop
は元の構造体・列挙型・共用体のジェネリクスを特殊化してはならない。これにより Drop
は、各ADT型に対して定義されるか、定義されないかのどちらかになる。
Copy
Self
はユーザー定義の構造体・列挙型・共用体である。- その
impl
に課された境界から、各フィールドがCopy
であることを結論づけられる。 - この構造体・列挙型・共用体は
Drop
を実装していない。
CoerceUnsized
CoerceUnsized
の実装は以下の条件を満たしている必要がある。
- 両辺ともポインタ/参照型であるか、両辺とも構造体である。
- ポインタ/参照型の場合、 (これは
libcore
で網羅されている)- ポインタからポインタ、ポインタから参照、参照から参照のいずれかである必要がある。
mut
からmut
,mut
からconst
,const
からconst
のいずれかである必要がある。- 参照から参照への場合は、大きいリージョン(部分型づけの意味では小さい)から小さいリージョン(部分型づけの意味では大きい)への変換である必要がある。
- 構造体の場合、
- 両辺が同じ定義を指している必要がある。
- 両辺のフィールドをそれぞれ単一化したとき、ちょうど1個だけが失敗する必要がある。
- 単一化が失敗したフィールドに対して同様に
CoerceUnsized
が成り立っている必要がある。
Rustにおける再帰的/余再帰的なトレイト選択/トレイト履行
Rustでは以下のようなプログラムはコンパイルエラーになる。
struct List<X>(Option<Box<(X, List<X>)>>); // 通常は X: Clone を仮定するが、あえて Option<Box<(X, List<X>)>>: Clone としてみる impl<X> Clone for List<X> where Option<Box<(X, List<X>)>>: Clone { fn clone(&self) -> Self { List(self.0.clone()) } } fn main() { let x = List::<i32>(None).clone(); }
このとき、 List<i32>: Clone
をするために以下のような推論が行われる。
List<i32>: Clone
は上で定義されているimpl
を使うことができる。- そのためには
where
節にあるOption<Box<(i32, List<i32>)>>: Clone
を充足する必要がある。 - これには
impl<T: Clone> Clone for Option<T>
を使うことができる。 - そのためには
where
節にあるBox<(i32, List<i32>)>: Clone
を充足する必要がある。 - これには
impl<T: Clone> Clone for Box<T>
を使うことができる。 - そのためには
where
節にある(i32, List<i32>): Clone
を充足する必要がある。 - これには
impl<T0: Clone, T1: Clone> Clone for (T0, T1)
を使うことができる。 - そのためには
where
節にあるi32: Clone
とList<i32>: Clone
を充足する必要がある。 i32: Clone
はimpl Clone for i32
を使うことができる。List<i32>: Clone
を解決する必要があるが、これは元の問題と全く同じであるため失敗とみなす。
むろんこれは、 Clone
の実装の where
節に普通使わない書き方を採用したからであり、 X: Clone
とすればこのような再帰的な解決は不要になる。
例外として、余帰納的なマッチング (coinductive matching)が許されるケースがある。それは以下のケースである。
- 検出されたサイクル上に登場する全てのトレイトが既定実装を持つとき。
例えば、先ほどの例で出てきた List<i32>
が Send
かどうかを調べようとすると、以下のような推論が行われる。
List<i32>: Send
には他の候補はないため、既定実装候補が採用される。List
にはフィールドが一つあるため、Option<Box<(i32, Lists<i32>)>>: Send
を充足する必要がある。Option<Box<(i32, Lists<i32>)>>: Send
には他の候補はないため、既定実装候補が採用される。Option
にはフィールドが一つあるため、Box<(i32, Lists<i32>)>: Send
を充足する必要がある。Box<(i32, Lists<i32>)>: Send
には他の候補はないため、既定実装候補が採用される。Box
にはフィールドが一つあるため、Unique<(i32, Lists<i32>)>: Send
を充足する必要がある。Unique<(i32, Lists<i32>)>: Send
はimpl<T: Send + ?Sized> Send for Unique<T>
を使うことができる。- そのためには
where
節にある(i32, Lists<i32>): Send
を充足する必要がある。 (i32, Lists<i32>): Send
には他の候補はないため、既定実装候補が採用される。(_, _)
にはフィールドが二つあるため、i32: Send
とLists<i32>: Send
を充足する必要がある。i32: Send
には他の候補はないため、既定実装候補が採用され、条件なしで充足される。Lists<i32>: Send
を解決する必要があるが、これは元の問題と全く同じである。通常ならばこれは失敗となるが、余帰納的なマッチングの条件を満たしているため、その場で成功とみなす。
なお、Rust 1.19.0時点では、この制約はトレイト履行(fulfillment)の場合にのみ適用され、トレイト選択(selection)時には余帰納的かどうかに関わらず再帰的なマッチングは認められていた。現時点での最新版では、#42840 の一部として、同じ制約がトレイト選択でも使われるようになっている。そのため、stableとnightlyでは以下のように表示されるエラーが異なっている。
stable
error[E0275]: overflow evaluating the requirement `List<i32>: std::clone::Clone` --> src/main.rs:11:31 | 11 | let x = List::<i32>(None).clone(); | ^^^^^
nightly
error[E0599]: no method named `clone` found for type `List<i32>` in the current scope --> src/main.rs:11:31 | 11 | let x = List::<i32>(None).clone(); | ^^^^^ | = note: the method `clone` exists but the following trait bounds were not satisfied: `std::option::Option<std::boxed::Box<(i32, List<i32>)>> : std::clone::Clone` = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `clone`, perhaps you need to implement it: candidate #1: `std::clone::Clone`
RustのRFC一覧 (~1552)
概要: RustのRFCの一覧を作ろうとしたが、あまりに多いのでとりあえず1552までで公開することにした。なお、単に全てのRFCを列挙したいならばここを見ればよい。
このRFCはRustのコミュニティーが管理しているものであり、 “RFC” の元祖であるIETF RFCとは関係ない。いずれもrequest-for-commentの略である。
メタ
- RFC 0002 Rust RFCの提出プロセスの説明
- RFC 0531 Rust RFCが関与する範囲を Rust/Cargo/Crates.io/このRFCプロセス自身 の4つに限定
- RFC 1068 Rust開発者チームの組織構造を文書化したもの
- RFC 1105 標準ライブラリや
crates.io
上のライブラリについて、どのような変更がsemverの major change/minor changeにあたるかの基準を与える - RFC 1122 コンパイラのバージョニングについて、マイナーバージョンでの破壊的変更は「コンパイラのバグ」「型システム上の問題」の修正などに留めることを明記。破壊的変更の影響を最小限に抑えるための手続き (crater/cargobombツールの利用、
[breaking-change]
タグ、tracking issueの作成、warning cycleの実施など)を策定。
スタイル/慣習
- RFC 0199 似たような動作で、所有権/借用の種別だけが異なるようなメソッドの命名規則を定める
- RFC 0236
panic!
/Result
の使い分けの慣習を定義する、関連するメソッドの命名規則を定める - RFC 0240
unsafe
の慣習の整理:unsafe
関数をメソッドにする条件の定義、論理的な不変条件を壊すが未定義動作を引き起こさない関数はunsafe
ではなく*_unchecked
と命名することを定義、その他unsafe
関数の命名規則の定義 - RFC 0344 関数/メソッド名が型名に言及する際の命名規則 (
Prelude*
はRFC 0445により廃止され、Rust PR #23104により完全に不要になった) - RFC 0430 命名規則のケーシング(snake_case, CamelCase, etc.) と、
unwrap
/into_*
の命名規則を定義 - RFC 0445 拡張トレイトパターンに使うトレイトの名前を
*Ext
とする命名規則 - RFC 0505 doc-commentの慣習の確立:
///
を優先的に使う。Markdownを使う
ソースファイル処理と字句
- RFC 0063 二重インクルードによる混乱を防ぐため、
mod foo;
による外部ファイルの読み込みに制限をつける - RFC 0069 バイトリテラル
b'x'
とバイト列リテラルb"Foo"
の導入 - RFC 0090/0021 字句解析器をより単純にする
- RFC 0326 文字/文字列リテラルにおいて
\x00
-\x7F
に限定し\x80
-\xFF
を禁止 - RFC 0342
abstract
,final
,override
をキーワードとして予約する - RFC 0446 文字/文字列リテラルの
\uXXXX
/\UXXXXXXXX
を廃止し、\u{XXXXXX}
を導入 - RFC 0463 将来の互換性のために、リテラル直後の識別子の字句規則を変更
- RFC 0593
Self
をキーワードにする - RFC 0601 将来の末尾再帰のための予約キーワード
be
を廃止し、新たにbecome
を予約 - RFC 0879 2進/8進リテラル直後の数字を禁止する (
0b012
を0b01
2
に分割せずにエラーにする)
構文
- RFC 0016 属性を
let
文、ブロック、式にも使えるようにする (#![feature(stmt_expr_attributes)]
) - RFC 0049 マッチ腕に属性を使えるようにする
- RFC 0059
~T
型と~x
式を削除し、Box
/box
で置き換える - RFC 0068
*T
型を*const T
にリネーム - RFC 0071
const
/static
内でも、一定条件下でブロックを使えるようにする - RFC 0087 トレイトオブジェクトの追加の境界を
&(Foo : Send + Sync)
ではなく&(Foo + Send + Sync)
のように指定するようにする - RFC 0092
if
やfor
などのブロックと紛らわしい場面では構造体の{}
を禁止する - RFC 0132 UFCS (
<T as Trait>::sth
/<T>::sth
) の導入 - RFC 0135
where
節の導入 (一部未実装) - RFC 0160
if let
構文 - RFC 0164 スライスパターンをfeature gateにする
- RFC 0168
{mod, ..}
によりモジュール自体とその中身を同時にインポートする (RFC 0532により廃止) - RFC 0169
use baz = foo::bar;
構文を廃止しuse foo::bar as baz;
で置き換える - RFC 0179
&p
パターンを&p
と&mut p
パターンに分割し、参照のミュータビリティーに応じて使い分けるようにする - RFC 0184
foo.0
のように、タプル/タプル構造体のフィールドに整数でアクセスできるようにする - RFC 0194
#[cfg(...)]
の構文の整理 - RFC 0198
foo[]
/foo[n..m]
/foo[n..]
/foo[..n]
のためのトレイトSlice
/SliceMut
を導入 (RFC 0439とRFC 0702により廃止:foo[]
はfoo[..]
になり、..
は[]
と独立な構文になった) - RFC 0202
[x, ..ys]
パターンを[x, ys..]
に変更 (#![feature(slice_patterns)]
/#![feature(advanced_slice_patterns)]
に注意) - RFC 0214
while let
構文 - RFC 0218 空のレコード構造体
struct A {}
を許可 - RFC 0243
e?
と(do) catch {}
構文によるエラー処理 (RFC 1859も参照。catch構文は#![feature(catch_expr)]
) - RFC 0339 バイト列リテラルの型を
&'static [u8]
から&'static [u8; N]
に変更 - RFC 0418
enum
のバリアントをレコード形式 (enum Foo { Bar {}}
) で宣言する機能を安定化 - RFC 0438 型における
&
と+
の優先順位を変更し、&(Foo + Bar)
のように書くようにする - RFC 0450 RFC 0184 (
foo.0
), RFC 0160 (if let
), RFC 0214 (while let
) の安定化,TupleN
トレイトの廃止 - RFC 0469
box p
パターンをfeature gateにし、安定化するまで使用を禁止 - RFC 0490
Sized? T
記法をT: ?Sized
に変更 - RFC 0520 配列型と繰り返しリテラルの構文
[x, ..N]
を[x; N]
に変更 - RFC 0522
Self
をimpl
内でも使えるようにする (RFC 1647も参照) - RFC 0532
use foo::{self, X};
によりモジュール自体とその中身を同時にインポートする。RFC 0168のキーワード置き換え - RFC 0534
#[deriving(Foo)]
を#[derive(Foo)]
にリネーム - RFC 0544
int
/uint
をisize
/usize
にリネーム。対応するリテラル接尾辞をis
/us
に変更 (リテラル接尾辞is
/us
はRFC 573で廃止) - RFC 0558 比較演算子を非結合的にし、
a == b == c
をどうしても書きたい場合は(a == b) == c
のように書くようにする - RFC 0572 将来の後方互換性のために、未知の属性(
#[foo]
等) をfeature gateにする(stableでの使用を禁止する) - RFC 0702
RangeFull
とその構文糖衣..
の導入。foo[]
記法を廃止してfoo[..]
に置き換え - RFC 0803 型帰属 (type ascription):
e: T
による型の明示 (#![feature(type_ascription)]
) - RFC 0809
box (place) expr
構文を廃止してin place { block }
に置き換える。かわりにbox expr
構文を導入する。 (#![feature(placement_in_syntax)]
,#![feature(box_syntax)]
, RFC 1228も参照) - RFC 0940 crate名のハイフンを禁止(cargoでは許可)し、
extern crate "foo";
をextern crate foo;
に変更 - RFC 0968 クロージャの戻り値型を指定したときは本体がブロックであることを要請する (
|| -> i32 1
とは書けず、|| -> i32 {1}
と書く必要がある) - RFC 1192 閉区間のための
x ... y
/x ..= y
構文 (どちらの構文になるかはまだ決定されていない) (#![feature(inclusive_range_syntax)]
) - RFC 1219
use foo::{bar as baz, Bar as Baz};
のように、{}
による複数インポート構文でのリネームを可能にする - RFC 1228 配置構文
in place { block }
の別構文place <- expr
(#![feature(placement_in_syntax)]
) - RFC 1331 Rustの権威的な文法はrustcの実装ではなく
src/grammar
内の形式文法であるとする (未実装) - RFC 1492
..
をタプルパターンやタプル構造体パターンの途中で使えるようにする - RFC 1506 タプル構造体/ユニット構造体を特殊なレコード構造体とみなし、タプル構造体を
A { 0: "foo", 1: bar }
のように初期化したり、同様のパターンマッチをしたりする
マクロ
- RFC 0085 パターンの位置でマクロを使えるようにする
- RFC 0378 文マクロには
{}
または;
を必須とし、どちらも持たないマクロは式マクロとして解釈する - RFC 0453 マクロのエクスポート (
#[macro_export]
/#[macro_reexport]
/#[macro_use]
)、$crate
メタ変数、プラグインのための#[plugin]
属性 - RFC 0550
macro_rules!
のマッチャーとして、非曖昧な(おそらくLL(1)な)マッチャーだけを許可する - RFC 0873 型の位置でマクロを使えるようにする
モジュール・名前解決・可視性・警告
- RFC 0001 構造体フィールドの可視性をデフォルトでprivateにする。
- RFC 0003 未使用の属性のチェック方法を改善する
- RFC 0026
enum
のバリアントの可視性を常にpublicにし、priv
キーワードを廃止する。 - RFC 0109 バージョン込みでcrateを指定できるcrate idを廃止して、ソースコードレベルではcrateの名前だけを指定するようにする
- RFC 0116
use
/let
等による同レベルシャドウイングの廃止 (現在はglob importの復活により、globのshadowingが可能) - RFC 0136 publicな定義の型にprivateな型を使うのを禁止する
- RFC 0155 固有実装は該当の型と同じモジュールでのみ可能 (RFC 0735により廃止)
- RFC 0234
enum
のバリアントは常に値名前空間と型名前空間の両方に属するようにする - RFC 0385 モジュールシステムの整理:
use
/mod
順の強制を廃止、pub extern crate
を許可、extern crate
のブロック内の出現を許可 - RFC 0390 バリアントを
enum
の名前空間の中に移動する。つまり、enum Foo { Bar }
でBar
ではなくFoo::Bar
とアクセスする - RFC 0459
impl
とその中のfn
の間での、生存期間変数と型変数のシャドウイングを禁止 - RFC 0501
#![no_implicit_prelude]
を#![no_prelude]
にリネームし、動作を変更 (RFC 1184も参照) - RFC 0735 固有実装は該当の型と異なるモジュールに置いてもよい
- RFC 0736 構造体の関数型レコード更新記法(FRU)
S { x: 42, ..old }
において、更新されないフィールドの可視性もチェックする - RFC 1023 トレイト実装の一貫性を保つため、orphan規則を厳しくする。
#[fundamental]
を導入する - RFC 1096
#[static_assert]
の廃止 (#[static_assert]
は、bool
型のstatic
アイテムにつけると、その値がfalse
だったときにコンパイルエラーとなる) - RFC 1184
#![no_std]
を#![no_std]
と#![no_core]
に分割した上で、#![no_std]
を安定化する。またlibcore
の名称を安定化(内容の安定化はしない) (RFC 0501も参照) - RFC 1193
#![deny(some_lint)]
を設定しているcrateがコンパイラのバージョンアップで破壊された場合に、lint levelを強制的に上書きできるオプション--cap-lints
を用意する - RFC 1229
static
などの定数文脈で、定数式評価の途中でエラーが発生しても、コンパイラは警告を出力して処理を続行する - RFC 1270
#[deprecated]
をユーザー定義のライブラリ内でも利用できるようにする - RFC 1422
pub(restricted)
構文 - RFC 1445 定数パターンの透明性を高めるための制限と
#[structural_match]
(網羅性チェックの制限は未実装)
型システム
- RFC 0019 既定実装
impl Send for .. {}
, 否定実装impl !Send for T {}
によりSend
/Sync
をライブラリレベルで実現する (#![feature(optin_builtin_traits)]
) - RFC 0034/0011
struct
/enum
の型引数に境界T: Trait
を書けるようにし、それが充足されていることを利用側で検査する。 - RFC 0048 トレイト周りの整理:
self
の一般化、coherence条件の整理、トレイト選択アルゴリズムの改善など - RFC 0111
Index
をIndex
/IndexMut
に分割する - RFC 0112/0033
Box<T>
から&mut T
への型強制の廃止(DerefMut型強制とは別) (RFC 0139も参照) - RFC 0115 整数リテラル型がデフォルトで
isize
にフォールバックしないようにする (RFC 0212により廃止) - RFC 0139
Box<T>
から&T
への型強制の廃止 (Deref型強制とは別) (RFC 0112も参照) - RFC 0195 関連型・関連定数・関連生存期間 (関連生存期間は未実装)
- RFC 0212 RFC 0115をリバートするが、整数型のデフォルトは
isize
ではなくi32
にする - RFC 0213
fn
/impl
でもデフォルト型引数を使えるようにする。_
を型引数のデフォルト値の意味で使えるようにする (#![feature(default_type_parameter_fallback)]
) - RFC 0241 Deref型強制:
&Rc<T>
を&T
に自動変換等 (RFC 0401も参照) - RFC 0255 トレイトにobject-safetyを課すようにする
- RFC 0341 virtual構造体と継承
virtual struct Foo {}
struct Bar : Foo {}
の削除 - RFC 0401 型強制とキャストの整理: スライスへの自動参照の削除、生ポインタ型強制、サブトレイト型強制、unsizedタプル型強制、推移的型強制、ユーザー定義型のunsize型強制など (RFC 0241, RFC 0982, RFC 1558も参照; いくつかの機能は未実装)
- RFC 0447 未使用だったり、一意でないような
impl
の型引数を禁止 - RFC 0495 スライスパターン
[x, xs..]
の変更:[T]
にはマッチするが&[T]
にはマッチしない。可変借用の分割に対応 (#![feature(slice_patterns)]
/#![feature(advanced_slice_patterns)]
に注意) - RFC 0546 トレイトをデフォルトで
?Sized
にする。Sized
なトレイトをobject-safeから外す。 - RFC 0982
CoerceUnsized
によるユーザー定義スマートポインタの型強制 - RFC 1210 特殊化。
default
弱キーワードの導入と、特定条件下での重複する実装の許可 (#![feature(specialization)]
) - RFC 1214 型システムをよりよくするための3つの変更: 長命(outlives)関係に関する規則を単純化。射影型の規則を整理。型の適格性(well-formedness)を要求する位置を明確化。 (実装途中)
- RFC 1216
!
をファーストクラスの型に昇格し、様々な位置で使えるようにする。 (#![feature(never_type)]
) - RFC 1268 マーカートレイトに対する実装が重複するのを許す (
#![feature(overlapping_marker_traits)]
) - RFC 1504
i128
,u128
型の追加 (#![feature(i128_type)]
) - RFC 1522 存在型のための
impl Trait
構文を限定的にサポート (#![feature(conservative_impl_trait)]
, RFC 1951により拡充)
クロージャ
- RFC 0114 クロージャの整理: unboxed closureのための
Fn
/FnMut
/FnOnce
トレイトの導入、proc
の削除、クロージャ型を削除して|_| -> _
を構文糖衣に変更(構文糖衣はRFC 0231により廃止)、キャプチャー方式の指定、レシーバモード|:|
|&:|
|&mut :|
の明示(RFC 0231により廃止) - RFC 0151 クロージャで
ref
を指定しない限りムーブキャプチャーする (RFC 0231により廃止) - RFC 0231 キャプチャーモードの推論方式を変更、
ref ||
を廃止してmove ||
を導入、|_| -> _
型構文を廃止、レシーバモード|:|
|&:|
|&mut :|
を廃止 - RFC 0587
Fn*
系トレイトの戻り値型を型引数ではなく関連型にする
生存期間/ボローチェッカー/部分型付け/const/mut
- RFC 0066 一時的な値に対する参照を間接的に取った場合も、直接取った場合と同様にそ の生存期間を延長できるようにする
- RFC 0107 パターンマッチのガード内でムーブ束縛された変数を使う (未実装)
- RFC 0130 ボローチェッカーにおける
Box<T>
の特別扱いの廃止 - RFC 0141 生存期間の省略規則の整理
- RFC 0192 トレイトオブジェクト型の生存期間 (RFC 0599, RFC 1156も参照)
- RFC 0246
static
をconst
/static
に分割 - RFC 0387 高階トレイト境界
T: for<'a> Trait
の導入 - RFC 0533 配列の特定要素からのムーブと要素ごとの初期化を廃止
- RFC 0599 トレイトオブジェクト型の生存期間の、外側の型にもとづくデフォルト値 (RFC 1156により上書き, RFC 0192も参照)
- RFC 0738 部分型付けにおける変性(variance)を推論するようにし、変性のためのラッパー型を削除する。未使用の型引数/生存期間引数(=双変 bivariant な引数)はエラーにする。
- RFC 0769 ドロップチェッカーの導入により、多相型の
Drop
を安全に実装できるようにする。 (RFC 1238, RFC 1327により上書き) - RFC 0911
const fn
による定数関数 - RFC 1066 safeなプログラムでもデストラクタが実行されないことがあることを明記し、
std::mem::forget
のunsafe
を外す - RFC 1156 トレイトオブジェクト型の生存期間のデフォルト値を定めたRFC 0599を上書きし、関数本体内でのbase defaultの規則を変更する (RFC 0192も参照)
- RFC 1238 RFC 0769が仮定している型のパラメトリシティーが特殊化によって崩れることを念頭に、ドロップチェッカーの動作を安全寄りに倒す (RFC 1327により上書き、
#![feature(dropck_parametricity)]
) - RFC 1327 RFC 0769とRFC 1238を上書きし、
#[unsafe_destructor_blind_to_params]
よりも子細に状況を指定できる#[may_dangle]
を導入 (#![feature(dropck_eyepatch)]
, 利用するには#![feature(generic_param_attrs)]
も必要) - RFC 1414
&42
など定数参照の生存期間を'static
に延長する (#![feature(rvalue_static_promotion)]
) - RFC 1440
const
/static
にデストラクタを持つ型を許可する (未実装)
コード生成/ABI
- RFC 0008
extern "rust-intrinsic"
の廃止 (破棄) - RFC 0079
#[repr(C)]
などで明示しない限り、構造体レイアウトは入れ替えられる可能性がある - RFC 0320 構造体等からdrop flagフィールドを削除、変数ごとのdrop flagに移行 (RFC 0533も参照)
- RFC 0379 ランタイムリフレクションと、それを用いた
{:?}
の削除、libdebug
/Poly
の削除 ({:?}
はRFC 0504により復活) - RFC 1201 関数プロローグとエピローグを省く
#[naked]
の追加 (#![feature(naked_functions)]
, RFC 1548も参照) - RFC 1240
#[repr(packed)]
な構造体のフィールドへの参照の取得はunsafe
であると取り決める - RFC 1260
::main()
がfn main() {}
ではなくuse foo::bar as main
の形で定義されていてもエントリポイントとみなす (未実装, PR 38312も参照) - RFC 1300
extern "rust-intrinsic"
/extern "platform-intrinsic"
は呼び出し側に直接コード生成されるものであり、関数ポインタ化はできないことを明記 - RFC 1358 アラインメントを指定する
#[repr(align = "N")]
属性 (#![feature(repr_align)]
) - RFC 1399
#[repr(packed)]
の一般化である#[repr(packed = "N")]
の導入 (未実装, おそらく#![feature(repr_packed)]
になる) - RFC 1444 共用体
union X { .. }
(#![feature(union)]
) - RFC 1513
panic
時にunwind(スタックを巻き戻してスレッドを終了)ではなくabort(その場でプログラムを終了)にするオプションを-C panic=abort
として安定化し、ユーザー定義のパニック戦略を提供できるようにする (ユーザー定義のパニック戦略は#![feature(panic_runtime)]
,#![feature(needs_panic_runtime)]
) - RFC 1535 整数オーバーフロー検査を有効化するためのオプションを
-C overflow-checks
として安定化 - RFC 1548 関数外でシンボルを定義するための
global_asm!()
マクロ (#![feature(global_asm)]
, RFC 1201も参照)
ライブラリ全般
- RFC 0040
libstd
の実装をlibcore
,liballoc
,liblibc
などのライブラリに分割する。 - RFC 0042/0007
regex
crateの同梱 (現在は同梱されていない, RFC 1242も参照) - RFC 0050 デバッグモードでのみ有効化される
debug_assert!()
の導入 - RFC 0060
StrBuf
をString
にリネーム - RFC 0093
println!
やformat!
から地域化の機能を削除し、構文を整理 - RFC 0100
PartialOrd::partial_cmp
を追加 - RFC 0123
Share
をSync
にリネーム - RFC 0201
std::error::Error
トレイトによるエラーの相互変換 - RFC 0216
HashMap
等でfindの結果を保持するEntry
型の導入 - RFC 0221
fail!()
をpanic!()
にリネーム - RFC 0230 標準ライブラリからグリーンスレッド関係の部分を削除
- RFC 0235 コレクション関連ライブラリの整理と慣例の確立:
Cow
を導入、Deque
などの抽象化用トレイトを削除しIterator
を中心にした枠組みを整備、各種関数の命名規則を統一 (RFC 0509により上書き, RFC 0580によりリネーム) - RFC 0256
Gc<T>
/@T
(Rc<T>
とは異なり、循環参照も解放される) の削除 - RFC 0356 型名にモジュール名を含めない慣習を定義し、
io::IoError
をio::Error
にリネーム - RFC 0369
std::num
にあった様々な抽象的な数値型トレイトの削除 (現在はSigned
も含め大部分が削除されnum
crateに移管済み) - RFC 0380
std::fmt
の安定化 - RFC 0439
std::cmp
とstd::ops
の整理: 演算子オーバーロードトレイトの整理、ヘテロジェニアスなEq
,Slice
/SliceMut
を削除してRange*
型を導入、IndexSet
の導入 (IndexSet
は実装されていない模様; RFC issue #997 も参照) - RFC 0458
Send: 'static
を削除、&T: Send
←→T: Sync
- RFC 0461 タスクローカル領域のための
std::local_data
を整理してスレッドローカル領域のためのstd::tls
を導入 (RFC 0909により、現在はstd::thread
に統合) - RFC 0474
std::path
の整理: 正規化の意味論を変更、UTF-8とは限らないパスのためにPathBuf
/OsPath
型を新たに導入 - RFC 0486
std::ascii::Ascii
型を削除してascii
外部crateに分離 - RFC 0494
std::c_vec
を廃止、std::c_str
をstd::ffi
にリネーム、CString
の所有権の扱いを変更 - RFC 0503
std::prelude
からいくつかの名前を削除し、安定化 - RFC 0504
Show
をString
(現在のDisplay
)とShow
(現在のDebug
)に分割し、新しいShow
のために{:?}
を割り当て (RFC 0565により現在の名前に変更) - RFC 0509 コレクション関連ライブラリの整備、RFC 0235の続き。いくつかのコレクションAPIの削除。コレクションAPIの安定化。 (RFC 0580によりリネーム)
- RFC 0517
std::io
とstd::os
の大改革。env
fs
io
net
os
os_str
process
への分割。アトミック性に関する意味論の整理。非utf-8文字列のサポート。ブロッキングI/Oに注力しつつ、ノンブロッキング/非同期IOのための前方互換性は確保するようにする。など - RFC 0526 任意のバイト列を出力できてしまう
std::fmt::Formatter::write
関数を削除することで、UTF-8チェックのコストを削減 - RFC 0528 文字列のパターン検索のための
Pattern
トレイトを導入 - RFC 0529 汎用的な変換トレイト
AsRef
,AsMut
,Into
,From
の導入 - RFC 0556
from_raw*
系関数のインターフェースを変更し、誤用を防ぐためドキュメントを充実させる - RFC 0560 整数演算オーバーフローの意味論を変更し、条件次第でpanicしうるとする。オーバーフロー時に常に巡回させたい場合のためのメソッド
wrapping_*
を用意する - RFC 0565
std::fmt::String
とstd::fmt::Show
をDisplay
,Debug
にリネーム - RFC 0574
Vec::drain
,String::drain
がバッファの一部だけをドレインできるようにする (RFC 1257により上書き) - RFC 0580 コレクション関連ライブラリのリネーム (
DList
→LinkedList
,RingBuf
→VecDeque
など) - RFC 0592
String
/str
に対して、CString
の対応物であるCStr
を導入する - RFC 0640
{:#?}
によるpretty printingの導入と、Debug
の実装のためのヘルパー型の整備 - RFC 0771
std::iter::once
とstd::iter::empty
の追加 - RFC 0823
std::hash
の整理:Hasher
トレイトとWriter
トレイトの統一write_u*
/write_i*
メソッドの導入、reset
メソッドの削除 - RFC 0832
vec![e; n]
記法のためのvec::from_elem
関数 (この関数は確かに追加され、現在はalloc::vec::from_elem
で公開されているが、#[doc(hidden)]
で隠されている) - RFC 0839 どんなコレクションでも、要素が
Copy
なら参照イテレータからextend
できるようにExtend
を実装する - RFC 0840
CString::from_slice
,CString::from_vec
はpanicせずにResult
を返す (実際のRust PR #22482 ではさらに、これらをCString::new
に統一している) - RFC 0888 コンパイラ用のメモリフェンス指令
std::intrinsics::atomic_singlethreadfence(_rel|_acq|_acqrel)?
を追加 - RFC 0909
std::thread_local
をstd::thread
に統合 - RFC 0921 コレクションの
Entry
のget
メソッドをor_insert
/or_insert_with
に置き換え - RFC 0953
+=
など複合代入演算子のためのトレイトAddAssign
etc. を追加 - RFC 0979
SliceExt::splitn
,StrExt::splitn
のn
の意味を、セパレーターの最大数ではなく要素の最大数と解釈するようにする - RFC 0980 規定量読むまで繰り返す
Read::read_exact
を追加 - RFC 1011 プロセスを即座に終了する
std::process::exit
(Cの_exit
相当)を追加 - RFC 1014
std::io::stdout
,std::io::stderr
,std::io::stdin
は、対応する入出力ストリームがなかった場合にエラーにせずにダミーを返すようにする - RFC 1030
Default
,IntoIterator
,ToOwned
をpreludeに追加 - RFC 1040
Duration
を整理し、一部を安定化 - RFC 1044
std::fs
で、プラットフォーム依存のファイル属性を扱えるようにstd::os::linux::fs::MetadataExt
のような拡張トレイトを追加、FileType
型の追加など - RFC 1047
TcpStream
,UdpSocket
に、タイムアウトを設定するメソッドを追加 - RFC 1048 プラットフォーム非依存の
soft_link
を廃止して、プラットフォームごとのシンボリックリンク作成関数のみを提供する - RFC 1054
str::words
を廃止して、std::split_whitespace
にリネーム - RFC 1057
io::Error
のカスタムエラーをerror::Error + Send
からerror::Error + Send + Sync
にすることで、io::Error: Sync
にする - RFC 1058 失敗時にパニックする
[T]::init
と[T]::tail
を廃止し、Option
を返す[T]::split_last
,[T]::split_first
で置き換える - RFC 1102
SliceConcatExt::connect
を、多くのプログラミング言語と同じ名称であるSliceConcatExt::join
にリネーム - RFC 1119
Result::expect
の追加 - RFC 1123
str::split_at
の追加 - RFC 1131
std::intrinsics::likely
、std::intrinsics::unlikely
の追加 (#![feature(core_intrinsics)]
) - RFC 1135 生ポインタ (
*const T
,*mut T
) が fat-pointerの場合でも、これらの比較をできるようにする (RFC中ではEq
に限定されているが、実際は一般のOrd
の関数が動作するようだ) - RFC 1152
str
と[T]
の対称性のために、str::into_string
とString::into_boxed_str
を追加 - RFC 1174
IntoRawFd
,IntoRawSocket
,IntoRawHandle
トレイトを追加 - RFC 1194
HashSet
やBTreeSet
のcontains
,remove
,insert
の一般化(削除/発見した要素を返す)であるget
,take
,replace
を追加 - RFC 1212
str::lines
,BufRead::lines
などの行処理関数の挙動を変更し、LFだけではなくCRLFも改行として扱うようにする - RFC 1236
panic!
によるunwindをキャッチするstd::thread::catch_panic
をstd::panic::catch_unwind
にリネームし、要請するトレイトをSend
から新しく導入するUnwindSafe
に変更する。これによりstd::panic::catch_unwind
を安定化する。 (RFC 1328も参照) - RFC 1242
regex
,uuid
など多数の同梱crateを@rust-langから分離、移管する (RFC 1291も参照) - RFC 1252
OpenOptions
の挙動の明確化とオプションの拡充 - RFC 1257 RFC 0574を拡充し、コレクションの種類に応じて
.drain(a..b)
または.drain()
を実装する - RFC 1288
std::time
を拡充し、Instant
,SystemTime
,Duration
を追加する - RFC 1291
libc
を @rust-lang-nurseryから@rust-langに昇格し、モジュール構造を整理する - RFC 1307
OsString
/OsStr
にlen
などいくつかのメソッドを追加 - RFC 1328 パニックハンドラーを指定する
std::panic::set_hook
,std::panic::take_hook
を追加 (RFC 1236も参照) - RFC 1359 Unix系特有のプロセス起動オプションを指定するための
CommandExt
トレイトと、CommandExt::exec
,CommandExt::before_exec
メソッドの追加 - RFC 1398 カスタムアロケーターのためのAPI (
#![feature(allocator_api)]
) - RFC 1415
std::os
内のプラットフォーム依存のデータ構造を廃止し、プラットフォーム依存の機能は拡張トレイトにより提供する - RFC 1419
memcpy
相当の機能を提供する[T]::copy_from_slice
- RFC 1432
Vec
,String
の一定範囲をイテレーターからの値で置き換えるsplice
メソッド (#![feature(splice)]
) - RFC 1434 値が範囲内かどうかを判定するための
Range::contains
etc. (#![feature(range_contains)]
) - RFC 1443
Atomic*
型に、compare_and_swap
の一般化であるcompare_and_exchange
,compare_and_exchange_weak
を追加する - RFC 1461
TcpStream
,TcpListener
,UdpSocket
に、ディレイ、TTL, IPv6, ブロッキングなどの設定をするメソッド (net2
crateに既に存在する機能) を追加 - RFC 1467
std::ptr::read_volatile
とstd::ptr::write_volatile
を安定化 - RFC 1479 Unixドメインソケットのための
std::os::unix::net
モジュールを追加 - RFC 1498
Ipv4Addr
,Ipv6Addr
と[u8; N]
との相互変換関数 - RFC 1521
Copy
な型のclone
の動作は単純コピーと一致しなければならないことを明記 - RFC 1542 失敗するかもしれない変換のための
TryFrom
,TryInto
トレイトを追加 (#![feature(try_from)]
) - RFC 1543
AtomicIsize
,AtomicUsize
の兄弟にあたるAtomicI8
,AtomicU8
,AtomicI16
,AtomicU16
,AtomicI32
,AtomicU32
,AtomicI64
,AtomicU64
,AtomicI128
,AtomicU128
を追加 (#![feature(integer_atomics)]
) - RFC 1552
VecDeque
,LinkedList
にある要素があるか調べるcontains
メソッドを追加
コンパイラ/リンカ/Cargo
- RFC 0086 手続きマクロの登録処理を一般化して、他のコンパイラプラグインの登録にも使えるようにする
- RFC 0089 リントをコンパイラプラグインとして追加できるようにする
- RFC 0131 ターゲットアーキテクチャーの指定の要件を緩める
- RFC 0403
cargo build
とネイティブライブラリとの相性を良くする:rustc -l
オプションの追加、Cargoマニフェストのキーの追加、build.rs
の導入など - RFC 0404 デフォルトで動的リンクよりも静的リンクを優先する
- RFC 0507 stable/beta/nightlyリリースチャンネルの導入、後方互換性のための
#![feature]
の強化 - RFC 0563
ndebug
コンフィグを削除し、debug_assertions
コンフィグに移行 - RFC 1183 アロケーターの実装(システムのmallocまたはjemalloc)をリンク時に選べるようにし、システムのmallocをデフォルトにする
- RFC 1191 高層中間表現HIRの導入。ASTから直接transせずに、AST→HIR→LLVM IRの順で翻訳する (RFC 1211も参照)
- RFC 1199 SIMDを外部crateで実現するためのコンパイラ側のサポートを整備する (
#[repr(simd)]
など) - RFC 1200
cargo install
,cargo uninstall
の追加 - RFC 1211 中層中間表現MIRを導入し、AST→HIR→MIR→LLVM IRの順で翻訳する (RFC 1191も参照)
- RFC 1241 crates.ioにおいて、
foo = "*"
のようなワイルドカード依存関係をもつcrateのアップロードを禁止 - RFC 1298 インクリメンタルコンパイルの提案
- RFC 1317 IDEサポートのためのRLS (Rust Language Server) の提案 (実装途中で不安定)
- RFC 1361 Cargoにおける、
[section.'cfg(..)']
による条件つき設定。Rustの#[cfg(..)]
と同じ構文 - RFC 1510 crate形式として、RustライブラリのCインターフェースをエクスポートするためのcdylib形式を追加
- RFC 1525
Cargo.toml
をプロジェクト内の複数crateで共有するためのworkspace機能を追加
Rustのコヒーレンス
概要: Rustの impl
が定義できる型にはコヒーレンスと呼ばれる制限がある。これについて説明する。なお、この記事では特殊化がない前提で説明する。
コヒーレンス初心者のための概説
以下のように impl
が重複していたり、自分のところ以外の型の impl
を定義しようとするとエラーになる場合がある。これをコヒーレンスという。
struct A; // overlap rule 違反 impl A { fn f(x: i32) {} } impl A { fn f(x: i8) {} } // orphan rule 違反 impl Option<A> { }
コヒーレンスの目的
コヒーレンスには以下の2つの目的がある。
- 同じトレイト/型に対して、状況に応じて異なる実装が採用されてしまうことを防ぐ。
- 将来の上流クレイトの変更による下流クレイトへの影響を最小限に留める。
コヒーレンスの分類
コヒーレンスは孤児規則 (orphan rule, オーファン規則) と重複規則 (overlap
rule, オーバーラップ規則) に分かれている。またこれに加えて、 impl
の適格性チェックで検査される引数の唯一性もコヒーレンスと目的を同じくするのでここで扱う。
引数の唯一性規則
impl
はそれ自体がジェネリック引数を持つが、これらの引数が入力から一意に特定できる必要がある。具体的には以下のように定義されている。
- 入力とは、以下の3つである。
Self
型- トレイトの型実引数 (トレイト実装の場合)
where
節に書ける境界
impl
の生存期間引数は、後方互換性のため原則としてチェックされない。ただし、関連型で使われている生存期間引数については、入力のどこかで使われている必要がある。- 型引数はRFC 0447に定めるとおりに制約されている (constrained) 必要がある。ただし、型引数が制約されているという性質は、以下の規則により帰納的に定義される。
Self
型またはトレイトの型実引数の一部(射影型、匿名型は除く)に出現する型引数は、制約されている。- トレイトが
<T as Trait<U>>::Output == V
のような射影型の制約を持っており、<T as Trait<U>>::Output
側に出現する型引数(射影型、匿名型も含む)が全て制約されているとき、V
側の一部(射影型、匿名型は除く)に出現する型引数は、制約されている。
struct A<X>(X); impl<X, Y> A<(X, Y)> {} // OK // impl<X> A<()> {} // Error // impl<X: Iterator> A<X::Item> {} // Error // impl<X: Iterator<Item=Y>, Y: Iterator<Item=X>> A<i32> {} // Error
孤児規則
孤児規則は、下流クレイトが定義できる実装を制限するものである。
固有実装の孤児規則
固有実装の孤児規則は以下の通りである。
- 固有実装の
Self
型は、ユーザー定義型またはトレイトオブジェクト型でなければならない。 (型別名は展開する) Self
の型コンストラクタは、impl
と同じクレイトで定義されたものでなければならない。
ただし、例外として、標準ライブラリで基本型に対する固有実装が定義されている。
struct A; impl A {} // impl Vec<A> {} // Error // impl Box<A> {} // Error // impl<'a> &'a A {} // Error
既定実装の孤児規則
既定実装は、同じクレイトで定義されたトレイトに対してのみ与えることができる。
#![feature(optin_builtin_traits)] impl Copy for .. {} // Error fn main() {}
トレイト実装の孤児規則
トレイト実装の孤児規則はRFC 1023で解説されており、やや複雑である。
impl<P1, .., Pm> T0 for Trait<T1, .., Tn>
が別のクレイトのトレイトに対して定義する場合は、以下の規則を満たさなければならない。
- ある
i
が存在して、Ti
は局所的である。 - 同じ
i
について、T0, T1, ..., T(i-1)
は型引数・射影型を持たない。
ただし、ある型が局所的であるとは、以下のいずれかである。
- 同じクレイトで定義されている構造体・列挙型・共用体または、同じクレイトで定義されているトレイトのトレイトオブジェクトである。
- 基礎型 (
&T
,&mut T
,Box<T>
,Fn<T>
,FnMut<T>
,FnOnce<T>
のいずれか)であり、T
は局所的である。
use std::ops::Add; // OK struct A; impl<'a, T> Add<T> for &'a A { type Output = (); fn add(self, _: T) {} }
use std::ops::Add; // Error // struct A; // impl<'a, T> Add<&'a A> for T { type Output = (); fn add(self, _: &'a A) {} }
ただし、該当トレイトが既定実装をもつ場合は制約が厳しくなる。この場合は &T
などの基礎型は局所性を継承しない。
#![feature(optin_builtin_traits)] use std::panic::UnwindSafe; struct A; // impl !UnwindSafe for Box<A> {} // Error
なお、 #[fundamental]
(現在は不安定な属性) を一般のライブラリが使う場合を考えると、規則はより複雑になる。
トレイト実装の孤児規則 (完全版)
より一般の #[fundamental]
型を考える場合の孤児規則は以下のようになる。
- ある
i
が存在して、Ti
は局所的 (local type) である。 - 同じ
i
について、T0, T1, .., Ti
は網羅的 (type without uncovered type parameters) である。
ただし、ある型が局所的であるとは、以下のいずれかである。
- 同じクレイトで定義されている構造体・列挙型・共用体または、同じクレイトで定義されているトレイトのトレイトオブジェクトである。
- 基礎型であり、その型引数も全て局所的である。
また、ある型が網羅的であるとは、以下のいずれかである。
- 同じクレイトで定義されている構造体・列挙型・共用体または、同じクレイトで定義されているトレイトのトレイトオブジェクトである。(型引数を持っていてもよい)
- 基礎型であり、その型実引数も全て網羅的である。
- 型仮引数・射影型を持たない。
ある型コンストラクターが基礎型であるとは、以下のいずれかである。
- 参照型
&T
,&mut T
である。 #[fundamental]
のついた構造体・列挙型・共用体または、#[fundamental]
のついたトレイトのトレイトオブジェクトである。
重複規則
重複規則は、既知の重複する実装を禁止する規則である。(未知の重複する実装は孤児規則により防がれる)
固有実装の重複規則
固有実装の重複規則は以下の通りである。
- 同じ型コンストラクタに対する
impl
は、それらが重複 (後述) すると判断された場合に限り、同じ名前のメソッド等を持つことができない。
struct A<X>(X); // OK impl A<i32> { fn f() {} } impl A<i8> { fn f(&self) {} } impl A<i8> { fn g() {} }
struct A<X>(X); // Error impl<X> A<(X, i32)> { fn f() {} } impl<X> A<(i32, X)> { fn f() {} }
既定実装の重複規則
#![feature(optin_builtin_traits)] trait Foo {} impl Foo for .. {} impl Foo for .. {}
トレイト実装の重複規則
トレイト実装の重複規則は以下の通りである。
- 同じトレイトに対する重複 (後述) する
impl
があってはいけない。 - トレイトオブジェクト型に対して、その祖先トレイトの実装を与えてはいけない。
trait Foo {} // Error impl<X> Foo for (i32, X) {} impl<X> Foo for (X, i32) {}
trait Foo<X> {} trait Bar<X> : Foo<X> {} impl Foo<i32> for Bar<i8> {} // Error
重複判定
2つの impl
が重複とみなされる条件は複雑で、場合によっては直感に反する挙動をすることがある。以下がその重複判定処理である。
- 2つの
impl
のトレイト/型の部分を単一化する。単一化に失敗したら排反である。 - 単一化に成功したら、それによって発生した制約 (元の
impl
に由来するwhere
境界や、射影型の制約) をそれぞれ解く。 (ある制約を解いた結果は、別の制約の判定には使わない) - 適用不可能な制約があったら、排反である。
- 全ての制約が適用可能(曖昧含む)ならば、重複である。
ここで出てくる制約の解決処理は、以前の記事で説明したトレイト選択によるものである。ただし、重複判定では、トレイト選択がクレイト際モード(intercrate mode)で行われる。
クレイト際モードでは、トレイト選択の動作が以下のように変化する
型変数を含むトレイト制約の扱い
クレイト際モードでは、いずれかのSelf
/実引数が型変数(型引数や射影型は型変数になる)であるようなトレイト制約は全て曖昧と解釈される。例えば、
trait Foo<X> {} trait Bar<X> {} impl<X, T> Foo<X> for T where T: Bar<X> {} impl<X> Foo<X> for i32 {}
は重複でエラーになる。この2つの impl
が重複するためには i32: Bar<?X>
が解決可能である必要があるが、これは下流クレイトで
struct A; impl Bar<A> for i32 {}
のような実装があったときに満たされうるからである。
ただし、型変数が何らかの型コンストラクタの内側にある場合は問題ない (これはバグの可能性がある)。
trait Foo<X> {} trait Bar<X> {} impl<X, T> Foo<X> for T where T: Bar<X> {} impl<X> Foo<(X,)> for i32 {} // OK
不可知なトレイト制約の扱い
(型変数を含むかもしれない)トレイト制約が不可知 (not knowable) であるとは、
- 局所的な型実引数をもたず、かつ
- 以下のどちらかの条件を満たす
- 自分以外のクレイトで定義された
#[fundamental]
でないトレイトに対する参照である。または - 型変数への代入の方法によっては局所的な型実引数を持ちうる (これが満たされることはない気がするが、よくわからない)
- 自分以外のクレイトで定義された
ことである。不可知なトレイト制約は強制的に曖昧と見なされる。
trait Foo {} impl<T> Foo for T where T: ::std::fmt::Octal {} impl Foo for () {} // Error
この例では、 (): ::std::fmt::Octal
が満たされることが重複する条件である。
孤児規則より、これが下流クレイトによって満たされることはないことはすぐにわかる。また、現時点では (): ::std::fmt::Octal
は満たされていない。しかし、このトレイト制約は不可知であるため、上記の impl
は重複と見なされてしまう。
この規則は、上流クレイトのバージョンアップを想定してのことである。 RFC 1105 で説明されているように、マイナーバージョンアップでも下流クレイトが壊れる可能性はゼロではないが、この規則により以下のようなbreakageが発生しないことが保証される。
#[fundamental]
でないトレイトに、局所的な型実引数を持ち、全ての型引数が網羅的であるような実装を追加することによる、下流クレイトの重複規則の破壊。
まとめ
- 重複規則は、同じクレイト内や、上流クレイトとの衝突を防ぐ。
- 孤児規則は、兄弟クレイトとの衝突を防ぐ。
- 重複規則ではクレイト際モードが採用される。これにより以下のような衝突を防ぐ。
- 下流クレイトが関与することによる、同じクレイト内や上流クレイトとの衝突。
- 上流クレイトのマイナーバージョンアップによる衝突。
RustのRFC一覧 (~1240)
概要: RustのRFCの一覧を作ろうとしたが、あまりに多いのでとりあえず1240までで公開することにした。なお、単に全てのRFCを列挙したいならばここを見ればよい。
このRFCはRustのコミュニティーが管理しているものであり、 “RFC” の元祖であるIETF RFCとは関係ない。いずれもrequest-for-commentの略である。
メタ
- RFC 0002 Rust RFCの提出プロセスの説明
- RFC 0531 Rust RFCが関与する範囲を Rust/Cargo/Crates.io/このRFCプロセス自身 の4つに限定
- RFC 1068 Rust開発者チームの組織構造を文書化したもの
- RFC 1105 標準ライブラリや
crates.io
上のライブラリについて、どのような変更がsemverの major change/minor changeにあたるかの基準を与える - RFC 1122 コンパイラのバージョニングについて、マイナーバージョンでの破壊的変更は「コンパイラのバグ」「型システム上の問題」の修正などに留めることを明記。破壊的変更の影響を最小限に抑えるための手続き (crater/cargobombツールの利用、
[breaking-change]
タグ、tracking issueの作成、warning cycleの実施など)を策定。
スタイル/慣習
- RFC 0199 似たような動作で、所有権/借用の種別だけが異なるようなメソッドの命名規則を定める
- RFC 0236
panic!
/Result
の使い分けの慣習を定義する、関連するメソッドの命名規則を定める - RFC 0240
unsafe
の慣習の整理:unsafe
関数をメソッドにする条件の定義、論理的な不変条件を壊すが未定義動作を引き起こさない関数はunsafe
ではなく*_unchecked
と命名することを定義、その他unsafe
関数の命名規則の定義 - RFC 0344 関数/メソッド名が型名に言及する際の命名規則 (
Prelude*
はRFC 0445により廃止され、Rust PR #23104により完全に不要になった) - RFC 0430 命名規則のケーシング(snake_case, CamelCase, etc.) と、
unwrap
/into_*
の命名規則を定義 - RFC 0445 拡張トレイトパターンに使うトレイトの名前を
*Ext
とする命名規則 - RFC 0505 doc-commentの慣習の確立:
///
を優先的に使う。Markdownを使う
ソースファイル処理と字句
- RFC 0063 二重インクルードによる混乱を防ぐため、
mod foo;
による外部ファイルの読み込みに制限をつける - RFC 0069 バイトリテラル
b'x'
とバイト列リテラルb"Foo"
の導入 - RFC 0090/0021 字句解析器をより単純にする
- RFC 0326 文字/文字列リテラルにおいて
\x00
-\x7F
に限定し\x80
-\xFF
を禁止 - RFC 0342
abstract
,final
,override
をキーワードとして予約する - RFC 0446 文字/文字列リテラルの
\uXXXX
/\UXXXXXXXX
を廃止し、\u{XXXXXX}
を導入 - RFC 0463 将来の互換性のために、リテラル直後の識別子の字句規則を変更
- RFC 0593
Self
をキーワードにする - RFC 0601 将来の末尾再帰のための予約キーワード
be
を廃止し、新たにbecome
を予約 - RFC 0879 2進/8進リテラル直後の数字を禁止する (
0b012
を0b01
2
に分割せずにエラーにする)
構文
- RFC 0016 属性を
let
文、ブロック、式にも使えるようにする (#![feature(stmt_expr_attributes)]
) - RFC 0049 マッチ腕に属性を使えるようにする
- RFC 0059
~T
型と~x
式を削除し、Box
/box
で置き換える - RFC 0068
*T
型を*const T
にリネーム - RFC 0071
const
/static
内でも、一定条件下でブロックを使えるようにする - RFC 0087 トレイトオブジェクトの追加の境界を
&(Foo : Send + Sync)
ではなく&(Foo + Send + Sync)
のように指定するようにする - RFC 0092
if
やfor
などのブロックと紛らわしい場面では構造体の{}
を禁止する - RFC 0132 UFCS (
<T as Trait>::sth
/<T>::sth
) の導入 - RFC 0135
where
節の導入 (一部未実装) - RFC 0160
if let
構文 - RFC 0164 スライスパターンをfeature gateにする
- RFC 0168
{mod, ..}
によりモジュール自体とその中身を同時にインポートする (RFC 0532により廃止) - RFC 0169
use baz = foo::bar;
構文を廃止しuse foo::bar as baz;
で置き換える - RFC 0179
&p
パターンを&p
と&mut p
パターンに分割し、参照のミュータビリティーに応じて使い分けるようにする - RFC 0184
foo.0
のように、タプル/タプル構造体のフィールドに整数でアクセスできるようにする - RFC 0194
#[cfg(...)]
の構文の整理 - RFC 0198
foo[]
/foo[n..m]
/foo[n..]
/foo[..n]
のためのトレイトSlice
/SliceMut
を導入 (RFC 0439とRFC 0702により廃止:foo[]
はfoo[..]
になり、..
は[]
と独立な構文になった) - RFC 0202
[x, ..ys]
パターンを[x, ys..]
に変更 (#![feature(slice_patterns)]
/#![feature(advanced_slice_patterns)]
に注意) - RFC 0214
while let
構文 - RFC 0218 空のレコード構造体
struct A {}
を許可 - RFC 0243
e?
と(do) catch {}
構文によるエラー処理 (RFC 1859も参照。catch構文は#![feature(catch_expr)]
) - RFC 0339 バイト列リテラルの型を
&'static [u8]
から&'static [u8; N]
に変更 - RFC 0418
enum
のバリアントをレコード形式 (enum Foo { Bar {}}
) で宣言する機能を安定化 - RFC 0438 型における
&
と+
の優先順位を変更し、&(Foo + Bar)
のように書くようにする - RFC 0450 RFC 0184 (
foo.0
), RFC 0160 (if let
), RFC 0214 (while let
) の安定化,TupleN
トレイトの廃止 - RFC 0469
box p
パターンをfeature gateにし、安定化するまで使用を禁止 - RFC 0490
Sized? T
記法をT: ?Sized
に変更 - RFC 0520 配列型と繰り返しリテラルの構文
[x, ..N]
を[x; N]
に変更 - RFC 0522
Self
をimpl
内でも使えるようにする (RFC 1647も参照) - RFC 0532
use foo::{self, X};
によりモジュール自体とその中身を同時にインポートする。RFC 0168のキーワード置き換え - RFC 0534
#[deriving(Foo)]
を#[derive(Foo)]
にリネーム - RFC 0544
int
/uint
をisize
/usize
にリネーム。対応するリテラル接尾辞をis
/us
に変更 (リテラル接尾辞is
/us
はRFC 573で廃止) - RFC 0558 比較演算子を非結合的にし、
a == b == c
をどうしても書きたい場合は(a == b) == c
のように書くようにする - RFC 0572 将来の後方互換性のために、未知の属性(
#[foo]
等) をfeature gateにする(stableでの使用を禁止する) - RFC 0702
RangeFull
とその構文糖衣..
の導入。foo[]
記法を廃止してfoo[..]
に置き換え - RFC 0803 型帰属 (type ascription):
e: T
による型の明示 (#![feature(type_ascription)]
) - RFC 0809
box (place) expr
構文を廃止してin place { block }
に置き換える。かわりにbox expr
構文を導入する。 (#![feature(placement_in_syntax)]
,#![feature(box_syntax)]
, RFC 1228も参照) - RFC 0940 crate名のハイフンを禁止(cargoでは許可)し、
extern crate "foo";
をextern crate foo;
に変更 - RFC 0968 クロージャの戻り値型を指定したときは本体がブロックであることを要請する (
|| -> i32 1
とは書けず、|| -> i32 {1}
と書く必要がある) - RFC 1192 閉区間のための
x ... y
/x ..= y
構文 (どちらの構文になるかはまだ決定されていない) (#![feature(inclusive_range_syntax)]
) - RFC 1219
use foo::{bar as baz, Bar as Baz};
のように、{}
による複数インポート構文でのリネームを可能にする - RFC 1228 配置構文
in place { block }
の別構文place <- expr
(#![feature(placement_in_syntax)]
)
マクロ
- RFC 0085 パターンの位置でマクロを使えるようにする
- RFC 0378 文マクロには
{}
または;
を必須とし、どちらも持たないマクロは式マクロとして解釈する - RFC 0453 マクロのエクスポート (
#[macro_export]
/#[macro_reexport]
/#[macro_use]
)、$crate
メタ変数、プラグインのための#[plugin]
属性 - RFC 0550
macro_rules!
のマッチャーとして、非曖昧な(おそらくLL(1)な)マッチャーだけを許可する - RFC 0873 型の位置でマクロを使えるようにする
モジュール・名前解決・可視性・警告
- RFC 0001 構造体フィールドの可視性をデフォルトでprivateにする。
- RFC 0003 未使用の属性のチェック方法を改善する
- RFC 0026
enum
のバリアントの可視性を常にpublicにし、priv
キーワードを廃止する。 - RFC 0109 バージョン込みでcrateを指定できるcrate idを廃止して、ソースコードレベルではcrateの名前だけを指定するようにする
- RFC 0116
use
/let
等による同レベルシャドウイングの廃止 (現在はglob importの復活により、globのshadowingが可能) - RFC 0136 publicな定義の型にprivateな型を使うのを禁止する
- RFC 0155 固有実装は該当の型と同じモジュールでのみ可能 (RFC 0735により廃止)
- RFC 0234
enum
のバリアントは常に値名前空間と型名前空間の両方に属するようにする - RFC 0385 モジュールシステムの整理:
use
/mod
順の強制を廃止、pub extern crate
を許可、extern crate
のブロック内の出現を許可 - RFC 0390 バリアントを
enum
の名前空間の中に移動する。つまり、enum Foo { Bar }
でBar
ではなくFoo::Bar
とアクセスする - RFC 0459
impl
とその中のfn
の間での、生存期間変数と型変数のシャドウイングを禁止 - RFC 0501
#![no_implicit_prelude]
を#![no_prelude]
にリネームし、動作を変更 (RFC 1184も参照) - RFC 0735 固有実装は該当の型と異なるモジュールに置いてもよい
- RFC 0736 構造体の関数型レコード更新記法(FRU)
S { x: 42, ..old }
において、更新されないフィールドの可視性もチェックする - RFC 1023 トレイト実装の一貫性を保つため、orphan規則を厳しくする。
#[fundamental]
を導入する - RFC 1096
#[static_assert]
の廃止 (#[static_assert]
は、bool
型のstatic
アイテムにつけると、その値がfalse
だったときにコンパイルエラーとなる) - RFC 1184
#![no_std]
を#![no_std]
と#![no_core]
に分割した上で、#![no_std]
を安定化する。またlibcore
の名称を安定化(内容の安定化はしない) (RFC 0501も参照) - RFC 1193
#![deny(some_lint)]
を設定しているcrateがコンパイラのバージョンアップで破壊された場合に、lint levelを強制的に上書きできるオプション--cap-lints
を用意する - RFC 1229
static
などの定数文脈で、定数式評価の途中でエラーが発生しても、コンパイラは警告を出力して処理を続行する
型システム
- RFC 0019 既定実装
impl Send for .. {}
, 否定実装impl !Send for T {}
によりSend
/Sync
をライブラリレベルで実現する (#![feature(optin_builtin_traits)]
) - RFC 0034/0011
struct
/enum
の型引数に境界T: Trait
を書けるようにし、それが充足されていることを利用側で検査する。 - RFC 0048 トレイト周りの整理:
self
の一般化、coherence条件の整理、トレイト選択アルゴリズムの改善など - RFC 0111
Index
をIndex
/IndexMut
に分割する - RFC 0112/0033
Box<T>
から&mut T
への型強制の廃止(DerefMut型強制とは別) (RFC 0139も参照) - RFC 0115 整数リテラル型がデフォルトで
isize
にフォールバックしないようにする (RFC 0212により廃止) - RFC 0139
Box<T>
から&T
への型強制の廃止 (Deref型強制とは別) (RFC 0112も参照) - RFC 0195 関連型・関連定数・関連生存期間 (関連生存期間は未実装)
- RFC 0212 RFC 0115をリバートするが、整数型のデフォルトは
isize
ではなくi32
にする - RFC 0213
fn
/impl
でもデフォルト型引数を使えるようにする。_
を型引数のデフォルト値の意味で使えるようにする (#![feature(default_type_parameter_fallback)]
) - RFC 0241 Deref型強制:
&Rc<T>
を&T
に自動変換等 (RFC 0401も参照) - RFC 0255 トレイトにobject-safetyを課すようにする
- RFC 0341 virtual構造体と継承
virtual struct Foo {}
struct Bar : Foo {}
の削除 - RFC 0401 型強制とキャストの整理: スライスへの自動参照の削除、生ポインタ型強制、サブトレイト型強制、unsizedタプル型強制、推移的型強制、ユーザー定義型のunsize型強制など (RFC 0241, RFC 0982, RFC 1558も参照; いくつかの機能は未実装)
- RFC 0447 未使用だったり、一意でないような
impl
の型引数を禁止 - RFC 0495 スライスパターン
[x, xs..]
の変更:[T]
にはマッチするが&[T]
にはマッチしない。可変借用の分割に対応 (#![feature(slice_patterns)]
/#![feature(advanced_slice_patterns)]
に注意) - RFC 0546 トレイトをデフォルトで
?Sized
にする。Sized
なトレイトをobject-safeから外す。 - RFC 0982
CoerceUnsized
によるユーザー定義スマートポインタの型強制 - RFC 1210 特殊化。
default
弱キーワードの導入と、特定条件下での重複する実装の許可 (#![feature(specialization)]
) - RFC 1214 型システムをよりよくするための3つの変更: 長命(outlives)関係に関する規則を単純化。射影型の規則を整理。型の適格性(well-formedness)を要求する位置を明確化。 (実装途中)
- RFC 1216
!
をファーストクラスの型に昇格し、様々な位置で使えるようにする。 (#![feature(never_type)]
)
クロージャ
- RFC 0114 クロージャの整理: unboxed closureのための
Fn
/FnMut
/FnOnce
トレイトの導入、proc
の削除、クロージャ型を削除して|_| -> _
を構文糖衣に変更(構文糖衣はRFC 0231により廃止)、キャプチャー方式の指定、レシーバモード|:|
|&:|
|&mut :|
の明示(RFC 0231により廃止) - RFC 0151 クロージャで
ref
を指定しない限りムーブキャプチャーする (RFC 0231により廃止) - RFC 0231 キャプチャーモードの推論方式を変更、
ref ||
を廃止してmove ||
を導入、|_| -> _
型構文を廃止、レシーバモード|:|
|&:|
|&mut :|
を廃止 - RFC 0587
Fn*
系トレイトの戻り値型を型引数ではなく関連型にする
生存期間/ボローチェッカー/部分型付け/const/mut
- RFC 0066 一時的な値に対する参照を間接的に取った場合も、直接取った場合と同様にそ の生存期間を延長できるようにする
- RFC 0107 パターンマッチのガード内でムーブ束縛された変数を使う (未実装)
- RFC 0130 ボローチェッカーにおける
Box<T>
の特別扱いの廃止 - RFC 0141 生存期間の省略規則の整理
- RFC 0192 トレイトオブジェクト型の生存期間 (RFC 0599, RFC 1156も参照)
- RFC 0246
static
をconst
/static
に分割 - RFC 0387 高階トレイト境界
T: for<'a> Trait
の導入 - RFC 0533 配列の特定要素からのムーブと要素ごとの初期化を廃止
- RFC 0599 トレイトオブジェクト型の生存期間の、外側の型にもとづくデフォルト値 (RFC 1156により上書き, RFC 0192も参照)
- RFC 0738 部分型付けにおける変性(variance)を推論するようにし、変性のためのラッパー型を削除する。未使用の型引数/生存期間引数(=双変 bivariant な引数)はエラーにする。
- RFC 0769 ドロップチェッカーの導入により、多相型の
Drop
を安全に実装できるようにする。 (RFC 1238, RFC 1327により上書き) - RFC 0911
const fn
による定数関数 - RFC 1066 safeなプログラムでもデストラクタが実行されないことがあることを明記し、
std::mem::forget
のunsafe
を外す - RFC 1156 トレイトオブジェクト型の生存期間のデフォルト値を定めたRFC 0599を上書きし、関数本体内でのbase defaultの規則を変更する (RFC 0192も参照)
- RFC 1238 RFC 0769が仮定している型のパラメトリシティーが特殊化によって崩れることを念頭に、ドロップチェッカーの動作を安全寄りに倒す (RFC 1327により上書き、
#![feature(dropck_parametricity)]
)
コード生成/ABI
- RFC 0008
extern "rust-intrinsic"
の廃止 (破棄) - RFC 0079
#[repr(C)]
などで明示しない限り、構造体レイアウトは入れ替えられる可能性がある - RFC 0320 構造体等からdrop flagフィールドを削除、変数ごとのdrop flagに移行 (RFC 0533も参照)
- RFC 0379 ランタイムリフレクションと、それを用いた
{:?}
の削除、libdebug
/Poly
の削除 ({:?}
はRFC 0504により復活) - RFC 1201 関数プロローグとエピローグを省く
#[naked]
の追加 (#![feature(naked_functions)]
) - RFC 1240
#[repr(packed)]
な構造体のフィールドへの参照の取得はunsafe
であると取り決める
ライブラリ全般
- RFC 0040
libstd
の実装をlibcore
,liballoc
,liblibc
などのライブラリに分割する。 - RFC 0042/0007
regex
crateの同梱 (現在は同梱されていない) - RFC 0050 デバッグモードでのみ有効化される
debug_assert!()
の導入 - RFC 0060
StrBuf
をString
にリネーム - RFC 0093
println!
やformat!
から地域化の機能を削除し、構文を整理 - RFC 0100
PartialOrd::partial_cmp
を追加 - RFC 0123
Share
をSync
にリネーム - RFC 0201
std::error::Error
トレイトによるエラーの相互変換 - RFC 0216
HashMap
等でfindの結果を保持するEntry
型の導入 - RFC 0221
fail!()
をpanic!()
にリネーム - RFC 0230 標準ライブラリからグリーンスレッド関係の部分を削除
- RFC 0235 コレクション関連ライブラリの整理と慣例の確立:
Cow
を導入、Deque
などの抽象化用トレイトを削除しIterator
を中心にした枠組みを整備、各種関数の命名規則を統一 (RFC 0509により上書き, RFC 0580によりリネーム) - RFC 0256
Gc<T>
/@T
(Rc<T>
とは異なり、循環参照も解放される) の削除 - RFC 0356 型名にモジュール名を含めない慣習を定義し、
io::IoError
をio::Error
にリネーム - RFC 0369
std::num
にあった様々な抽象的な数値型トレイトの削除 (現在はSigned
も含め大部分が削除されnum
crateに移管済み) - RFC 0380
std::fmt
の安定化 - RFC 0439
std::cmp
とstd::ops
の整理: 演算子オーバーロードトレイトの整理、ヘテロジェニアスなEq
,Slice
/SliceMut
を削除してRange*
型を導入、IndexSet
の導入 (IndexSet
は実装されていない模様; RFC issue #997 も参照) - RFC 0458
Send: 'static
を削除、&T: Send
←→T: Sync
- RFC 0461 タスクローカル領域のための
std::local_data
を整理してスレッドローカル領域のためのstd::tls
を導入 (RFC 0909により、現在はstd::thread
に統合) - RFC 0474
std::path
の整理: 正規化の意味論を変更、UTF-8とは限らないパスのためにPathBuf
/OsPath
型を新たに導入 - RFC 0486
std::ascii::Ascii
型を削除してascii
外部crateに分離 - RFC 0494
std::c_vec
を廃止、std::c_str
をstd::ffi
にリネーム、CString
の所有権の扱いを変更 - RFC 0503
std::prelude
からいくつかの名前を削除し、安定化 - RFC 0504
Show
をString
(現在のDisplay
)とShow
(現在のDebug
)に分割し、新しいShow
のために{:?}
を割り当て (RFC 0565により現在の名前に変更) - RFC 0509 コレクション関連ライブラリの整備、RFC 0235の続き。いくつかのコレクションAPIの削除。コレクションAPIの安定化。 (RFC 0580によりリネーム)
- RFC 0517
std::io
とstd::os
の大改革。env
fs
io
net
os
os_str
process
への分割。アトミック性に関する意味論の整理。非utf-8文字列のサポート。ブロッキングI/Oに注力しつつ、ノンブロッキング/非同期IOのための前方互換性は確保するようにする。など - RFC 0526 任意のバイト列を出力できてしまう
std::fmt::Formatter::write
関数を削除することで、UTF-8チェックのコストを削減 - RFC 0528 文字列のパターン検索のための
Pattern
トレイトを導入 - RFC 0529 汎用的な変換トレイト
AsRef
,AsMut
,Into
,From
の導入 - RFC 0556
from_raw*
系関数のインターフェースを変更し、誤用を防ぐためドキュメントを充実させる - RFC 0560 整数演算オーバーフローの意味論を変更し、条件次第でpanicしうるとする。オーバーフロー時に常に巡回させたい場合のためのメソッド
wrapping_*
を用意する - RFC 0565
std::fmt::String
とstd::fmt::Show
をDisplay
,Debug
にリネーム - RFC 0574
Vec::drain
,String::drain
がバッファの一部だけをドレインできるようにする - RFC 0580 コレクション関連ライブラリのリネーム (
DList
→LinkedList
,RingBuf
→VecDeque
など) - RFC 0592
String
/str
に対して、CString
の対応物であるCStr
を導入する - RFC 0640
{:#?}
によるpretty printingの導入と、Debug
の実装のためのヘルパー型の整備 - RFC 0771
std::iter::once
とstd::iter::empty
の追加 - RFC 0823
std::hash
の整理:Hasher
トレイトとWriter
トレイトの統一write_u*
/write_i*
メソッドの導入、reset
メソッドの削除 - RFC 0832
vec![e; n]
記法のためのvec::from_elem
関数 (この関数は確かに追加され、現在はalloc::vec::from_elem
で公開されているが、#[doc(hidden)]
で隠されている) - RFC 0839 どんなコレクションでも、要素が
Copy
なら参照イテレータからextend
できるようにExtend
を実装する - RFC 0840
CString::from_slice
,CString::from_vec
はpanicせずにResult
を返す (実際のRust PR #22482 ではさらに、これらをCString::new
に統一している) - RFC 0888 コンパイラ用のメモリフェンス指令
std::intrinsics::atomic_singlethreadfence(_rel|_acq|_acqrel)?
を追加 - RFC 0909
std::thread_local
をstd::thread
に統合 - RFC 0921 コレクションの
Entry
のget
メソッドをor_insert
/or_insert_with
に置き換え - RFC 0953
+=
など複合代入演算子のためのトレイトAddAssign
etc. を追加 - RFC 0979
SliceExt::splitn
,StrExt::splitn
のn
の意味を、セパレーターの最大数ではなく要素の最大数と解釈するようにする - RFC 0980 規定量読むまで繰り返す
Read::read_exact
を追加 - RFC 1011 プロセスを即座に終了する
std::process::exit
(Cの_exit
相当)を追加 - RFC 1014
std::io::stdout
,std::io::stderr
,std::io::stdin
は、対応する入出力ストリームがなかった場合にエラーにせずにダミーを返すようにする - RFC 1030
Default
,IntoIterator
,ToOwned
をpreludeに追加 - RFC 1040
Duration
を整理し、一部を安定化 - RFC 1044
std::fs
で、プラットフォーム依存のファイル属性を扱えるようにstd::os::linux::fs::MetadataExt
のような拡張トレイトを追加、FileType
型の追加など - RFC 1047
TcpStream
,UdpSocket
に、タイムアウトを設定するメソッドを追加 - RFC 1048 プラットフォーム非依存の
soft_link
を廃止して、プラットフォームごとのシンボリックリンク作成関数のみを提供する - RFC 1054
str::words
を廃止して、std::split_whitespace
にリネーム - RFC 1057
io::Error
のカスタムエラーをerror::Error + Send
からerror::Error + Send + Sync
にすることで、io::Error: Sync
にする - RFC 1058 失敗時にパニックする
[T]::init
と[T]::tail
を廃止し、Option
を返す[T]::split_last
,[T]::split_first
で置き換える - RFC 1102
SliceConcatExt::connect
を、多くのプログラミング言語と同じ名称であるSliceConcatExt::join
にリネーム - RFC 1119
Result::expect
の追加 - RFC 1123
str::split_at
の追加 - RFC 1131
std::intrinsics::likely
、std::intrinsics::unlikely
の追加 (#![feature(core_intrinsics)]
) - RFC 1135 生ポインタ (
*const T
,*mut T
) が fat-pointerの場合でも、これらの比較をできるようにする (RFC中ではEq
に限定されているが、実際は一般のOrd
の関数が動作するようだ) - RFC 1152
str
と[T]
の対称性のために、str::into_string
とString::into_boxed_str
を追加 - RFC 1174
IntoRawFd
,IntoRawSocket
,IntoRawHandle
トレイトを追加 - RFC 1194
HashSet
やBTreeSet
のcontains
,remove
,insert
の一般化(削除/発見した要素を返す)であるget
,take
,replace
を追加 - RFC 1212
str::lines
,BufRead::lines
などの行処理関数の挙動を変更し、LFだけではなくCRLFも改行として扱うようにする - RFC 1236
panic!
によるunwindをキャッチするstd::thread::catch_panic
をstd::panic::catch_unwind
にリネームし、要請するトレイトをSend
から新しく導入するUnwindSafe
に変更する。これによりstd::panic::catch_unwind
を安定化する。
コンパイラ/リンカ/Cargo
- RFC 0086 手続きマクロの登録処理を一般化して、他のコンパイラプラグインの登録にも使えるようにする
- RFC 0089 リントをコンパイラプラグインとして追加できるようにする
- RFC 0131 ターゲットアーキテクチャーの指定の要件を緩める
- RFC 0403
cargo build
とネイティブライブラリとの相性を良くする:rustc -l
オプションの追加、Cargoマニフェストのキーの追加、build.rs
の導入など - RFC 0404 デフォルトで動的リンクよりも静的リンクを優先する
- RFC 0507 stable/beta/nightlyリリースチャンネルの導入、後方互換性のための
#![feature]
の強化 - RFC 0563
ndebug
コンフィグを削除し、debug_assertions
コンフィグに移行 - RFC 1183 アロケーターの実装(システムのmallocまたはjemalloc)をリンク時に選べるようにし、システムのmallocをデフォルトにする
- RFC 1191 高層中間表現HIRの導入。ASTから直接transせずに、AST→HIR→LLVM IRの順で翻訳する (RFC 1211も参照)
- RFC 1199 SIMDを外部crateで実現するためのコンパイラ側のサポートを整備する (
#[repr(simd)]
など) - RFC 1200
cargo install
,cargo uninstall
の追加 - RFC 1211 中層中間表現MIRを導入し、AST→HIR→MIR→LLVM IRの順で翻訳する (RFC 1191も参照)
RustBelt試行中: get_x の一般化
RustBeltの examples/get_x.v
をいじってみた。
From iris.proofmode Require Import tactics. From lrust.typing Require Import typing. Set Default Proof Using "Type". Section get_x. Context `{typeG Σ}. Definition get_x : val := funrec: <> ["p"] := let: "p'" := !"p" in letalloc: "r" <- "p'" +ₗ #0 in delete [ #1; "p"] ;; return: ["r"]. Lemma get_x_type : typed_val get_x (fn(∀ α, ∅; &uniq{α} Π[int; int]) → &shr{α} int). Proof. intros E L. iApply type_fn; [solve_typing..|]. iIntros "/= !#". iIntros (α ϝ ret p). inv_vec p=>p. simpl_subst. iApply type_deref; [solve_typing..|]. iIntros (p'); simpl_subst. iApply (type_letalloc_1 (&shr{α}int)); [solve_typing..|]. iIntros (r). simpl_subst. iApply type_delete; [solve_typing..|]. iApply type_jump; solve_typing. Qed. End get_x.
これはだいたい以下のようなプログラムを表しているようだ。
fn get_x<'a>(p: &'a mut (i32, i32)) -> &'a i32 { &p.0 }
ただし、現在のλRustでは整数型はひとつしかなく、無限に大きな整数を保持可能で、サイズは1である (ポインタのサイズも1)。
これを
fn fst<'a, T, U>(p: &'a mut (T, U)) -> &'a T { &p.0 }
に一般化してみた。試行錯誤の結果、以下のようにすると上手くいくことがわかった。
From iris.proofmode Require Import tactics. From lrust.typing Require Import typing. Set Default Proof Using "Type". Section get_x. Context `{typeG Σ}. Definition get_x T U `{!TyWf T} `{!TyWf U} : val := funrec: <> ["p"] := let: "p'" := !"p" in letalloc: "r" <- "p'" +ₗ #0 in delete [ #1; "p"] ;; return: ["r"]. Lemma get_x_type T U `{!TyWf T} `{!TyWf U} : typed_val (get_x T U) (fn(∀ α, ∅; &uniq{α} Π[T; U]) → &shr{α} T). Proof. intros E L. iApply type_fn; [solve_typing..|]. iIntros "/= !#". iIntros (α ϝ ret p). inv_vec p=>p. simpl_subst. iApply type_deref; [solve_typing..|]. iIntros (p'); simpl_subst. iApply (type_letalloc_1 (&shr{α}T)); [solve_typing..|]. iIntros (r). simpl_subst. iApply type_delete; [solve_typing..|]. iApply type_jump; solve_typing. Qed. End get_x.
同様に、
fn snd<'a, T, U>(p: &'a mut (T, U)) -> &'a U { &p.1 }
は以下のように定義できた。
From iris.proofmode Require Import tactics. From lrust.typing Require Import typing. Set Default Proof Using "Type". Section snd. Context `{typeG Σ}. Definition snd T U `{!TyWf T} `{!TyWf U} : val := funrec: <> ["p"] := let: "p'" := !"p" in letalloc: "r" <- "p'" +ₗ #(T.(ty_size)) in delete [ #1; "p"] ;; return: ["r"]. Lemma snd_type T U `{!TyWf T} `{!TyWf U} : typed_val (snd T U) (fn(∀ α, ∅; &uniq{α} Π[T; U]) → &shr{α} U). Proof. intros E L. iApply type_fn; [solve_typing..|]. iIntros "/= !#". iIntros (α ϝ ret p). inv_vec p=>p. simpl_subst. iApply type_deref; [solve_typing..|]. iIntros (p'); simpl_subst. iApply (type_letalloc_1 (&shr{α}U)); [solve_typing..|]. iIntros (r). simpl_subst. iApply type_delete; [solve_typing..|]. iApply type_jump; solve_typing. Qed. End snd.
わかったこと
lrust.typing.typing
をインポートするとよくて、lrust.typing.lib.*
にCell
等のライブラリがあるlrust.typing.examples
に例がある`{typeG Σ}
は共通のコンテキストとして出てくる- まずMIRもどきを
Definition
で与え、あとからLemma
で型をつける。 - ライフタイムの多相性はλRustで扱われているが、型多相性はメタレベルで表現する。
funrec
は関数定義。!
はメモリを読む。delete
はサイズと先頭番地を引数に取りヒープまたはスタックを解放する。 (ヒープとスタックは同等に扱われる)#x
は定数リテラル。+ₗ
はポインタと整数の足し算。- 型は
type
で、これは@type _ H
(H
は冒頭のContext
で宣言されているやつ) - 不正な再帰型を避けるために、各型がwell-formedであることの保証を持ち回す必要がある。これは
`{!TyWf T}
で実現できる。 ∀α, ∅; T
は生存期間に関する量化で、∅
は多分境界がないことを意味している。&uniq{α} T
と&shr{α} T
は&'a mut T
と&'a T
。Π[A; B; C]
は(A, B, C)
std::mem::size_of::<T>()
が欲しいときは#(T.(ty_size))
と書く- unsized typeのサポートは今のところなくて、
type
は全部Sized
な型を表す