型エイリアスの定義/参照の順序関係について

Foo を定義しているタイミングに注目してほしいのだけど、以下の実装がエラーや警告もなく普通に動く1

fn main() {
    let a: Foo = 10;
    println!("{}", a);
    type Foo = u32; // Fooの利用箇所より下の行で定義している
}

(変数の定義なんかと同じで)使うタイミングより前で定義しておかないとだめだと思いこんでいたけど、どうやらそんなことはないらしい。ちょっとびっくりした 2

話は以上なんだけど、気になった点をいくつか試したので以下にメモを残しておく

エイリアスの定義を消してみる

上の場合だと type 文がいらないという可能性がなくはないので念の為確認してみる

fn main() {
    let a: Foo = 10;
    println!("{}", a);
}
$ rustc main.rs
error[E0412]: cannot find type `Foo` in this scope
 --> main.rs:2:12
  |
2 |     let a: Foo = 10;
  |            ^^^ not found in this scope

error: aborting due to previous error

For more information about this error, try `rustc --explain E0412`.

普通にエラーになった。やっぱり単に先に定義が反映されているだけっぽい

エイリアス間の順序関係を確認してみる

どうやら type は先に反映されるっぽいことはわかったが、それなら type 間の順序関係はどうなるのか気になった

fn main() {
    let a: Bar = 10;
    type Foo = u32;
    type Bar = Foo;
    println!("{}", a);
}
fn main() {
    let a: Bar = 10;
    type Bar = Foo;
    type Foo = u32;
    println!("{}", a);
}

この2つの実装はどちらも正常に機能する。 Foo を先に定義してないと type Bar = Foo がエラーになるのではと思っていたが(つまり type 間には順序関係があるのではと思っていたが)、そういうわけではなさそう

エイリアス間の順序関係を確認してみる_2

順不同で反映されるなら、同じ名前のエイリアスを複数指定したらどうなるのか気になった

fn main() {
    let a: Foo = 10;
    type Foo = u32;
    type Foo = f32;
    println!("{}", a);
}
$ rustc main.rs
error[E0428]: the name `Foo` is defined multiple times
 --> main.rs:4:5
  |
3 |     type Foo = u32;
  |     --------------- previous definition of the type `Foo` here
4 |     type Foo = f32;
  |     ^^^^^^^^^^^^^^^ `Foo` redefined here
  |
  = note: `Foo` must be defined only once in the type namespace of this block

error: aborting due to previous error

For more information about this error, try `rustc --explain E0428`.

これはエラーになる

エイリアスのスコープを確認してみる

もしかしてブロックよりも大きな単位でエイリアス反映されちゃったりするのかなと不安になったので確認しておく

fn main() {
    let a: Foo = 10;
    {
        type Foo = f32;
    }
    println!("{}", a);
}
$ rustc main.rs
error[E0412]: cannot find type `Foo` in this scope
 --> main.rs:2:12
  |
2 |     let a: Foo = 10;
  |            ^^^ not found in this scope

error: aborting due to previous error

For more information about this error, try `rustc --explain E0412`.

これはエラーになる。ブロックのstatementを上から順番にみていくちょうど前のタイミングで、ブロックの中の type を一通り見ているっぽい

補足


  1. バージョンは rustc 1.42.0 (b8cedc004 2020-03-09) です

  2. rust-analyzer の実装をみてる限りどうにも type の順序を考慮している気がしなくて、実際に試してみたら……という感じでした。見ていたのはこのあたり rust-analyzer/expr.rs at e0de2475208765a171f335dfffde764f96243d41 · rust-analyzer/rust-analyzer · GitHub