Rustの基本型の名前解決

Rustの基本型の名前はキーワードではない。したがって基本型の名前は名前解決と同時に処理されることになる。ところがややこしい点として、基本型と同名のモジュールに解決される場合もある。この挙動について調べた。

基本型の名前は PrimitiveTypeTable::new で列挙されており、以下の名前を含んでいる。

  • bool
  • char
  • i8, i16, i32, i64, i128, isize
  • u8, u16, u32, u64, u128, usize
  • f32, f64
  • str

なお、これらに含まれない(記号で表される)基本型としては、&'a T, &mut 'a T, *const T, *mut T, [T; n], [T] がある。処理系が特別扱いする Box<T>, PhantomData<T>, NonZero<T>, UnsafeCell<T> なども基本型に準じると考える場合があるかもしれない。

基本型の名前の処理は resolve_qpathの中 で行われている。QPathは式や型などに出てくるものであり、例えば use のパスはこの処理の対象外であり、常に通常の名前として解決されるということになる。

このコードによると、パスの最初の要素が基本型として処理される条件は

  • パスはQSelf (<A as Foo>:: のような部分) を含まない。
  • パスの最初の要素が、上記の基本型の名前のいずれかである。
  • パスの最初の要素が、型名前空間で解決されようとしている。
  • 通常の方法でのパスの解決に失敗したか、またはパス全体が正規モジュール(ルートモジュールまたは mod)に解決された。

である。

これにより、例えば

use std::f64;

fn main() {
    let x : f64 = 0.0f64;
    println!("{}", f64::sin(f64::consts::PI + x));
}

というコードがうまく動作することになる。ここで、 x の型と、 f64::sinf64 は、基本型に解決される。一方、 f64::consts::PIf64 は、 ::std::f64 モジュールとして解決される。

ソースコードには、この挙動は「後方互換性のため」と書いてあるが、これが将来のサポート廃止を意図しているのか、そうではないのかは、判断がつかない。(少なくともサポート廃止という話を聞いたことはない)

なお、以下の2つは別の場所で解決される。

  • 0.0f64 のように、リテラルの型を明示する機能で出てくる型名は、構文解析のタイミングで処理される。
  • 標準ライブラリの impl f64 は、実際にはSelf型の部分は関係なく、 #[lang="f64"] により発見される。