From 7f15e0b8277ac8b101b4f71ce57c1c5442927141 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Sat, 18 Mar 2023 19:51:06 +0900 Subject: fix(nuldoc): fix whitespaces being trimmed --- .../rust-where-are-primitive-types-from/index.html | 78 +++++++++++----------- 1 file changed, 39 insertions(+), 39 deletions(-) (limited to 'public/posts/2021-10-02/rust-where-are-primitive-types-from') diff --git a/public/posts/2021-10-02/rust-where-are-primitive-types-from/index.html b/public/posts/2021-10-02/rust-where-are-primitive-types-from/index.html index 7f1e989..5bb46a0 100644 --- a/public/posts/2021-10-02/rust-where-are-primitive-types-from/index.html +++ b/public/posts/2021-10-02/rust-where-are-primitive-types-from/index.html @@ -54,20 +54,20 @@

- この記事は Qiita から移植してきたものです。 元 URL:https://qiita.com/nsfisis/items/9a429432258bbcd6c565 + この記事は Qiita から移植してきたものです。 元 URL: https://qiita.com/nsfisis/items/9a429432258bbcd6c565

- +


- +
-

前置き

+

前置き

Rust において、プリミティブ型の名前は予約語でない。したがって、次のコードは合法である。

- +
#![allow(non_camel_case_types)]
 #![allow(dead_code)]
 
@@ -88,40 +88,40 @@
 struct f32;
 struct f64;
 struct str;
- +

- では、普段単にboolと書いたとき、このboolは一体どこから来ているのか。rustc のソースを追ってみた。 + では、普段単に bool と書いたとき、この bool は一体どこから来ているのか。rustc のソースを追ってみた。

- +

- 前提知識: 一般的なコンパイラの構造、用語。rustcそのものの知識は不要 (というよりも筆者自身がよく知らない) + 前提知識: 一般的なコンパイラの構造、用語。rustc そのものの知識は不要 (というよりも筆者自身がよく知らない)

- +
-

調査

+

調査

調査に使用したソース (調査時点での最新 master)

- +

https://github.com/rust-lang/rust/tree/511ed9f2356af365ad8affe046b3dd33f7ac3c98

- +

どのようにして調べるか。rustc の構造には詳しくないため、すぐに当たりをつけるのは難しい。

- +

- 大雑把な構造としては、compilerフォルダ以下にrustc_*という名前のクレートが数十個入っている。これがどうやらrustcコマンドの実装部のようだ。 + 大雑把な構造としては、compiler フォルダ以下に rustc_* という名前のクレートが数十個入っている。これがどうやら rustc コマンドの実装部のようだ。

- +

- rustcはセルフホストされている (=rustc自身が Rust で書かれている) ので、boolcharなどで適当に検索をかけてもノイズが多すぎて話にならない。 しかし、お誂え向きなことにi128/u128というコンパイラ自身が使うことがなさそうな型が存在するのでこれを使ってgit grepしてみる。 + rustc はセルフホストされている (= rustc 自身が Rust で書かれている) ので、boolchar などで適当に検索をかけてもノイズが多すぎて話にならない。 しかし、お誂え向きなことに i128/u128 というコンパイラ自身が使うことがなさそうな型が存在するのでこれを使って git grep してみる。

- +
$ git grep "\bi128\b" | wc      # i128
 165    1069   15790
 
@@ -130,20 +130,20 @@ $ git grep "\bu128\b" | wc      # u128
 
 $ git grep "\bbool\b" | wc      # cf. bool の結果
 3563   23577  294659
- +

165 程度であれば探すことができそうだ。今回は、クレート名を見ておおよその当たりをつけた。

- +
$ git grep "\bi128\b"
 ...
 rustc_resolve/src/lib.rs:        table.insert(sym::i128, Int(IntTy::I128));
 ...
- +

- rustc_resolveというのはいかにも名前解決を担いそうなクレート名である。該当箇所を見てみる。 + rustc_resolve というのはいかにも名前解決を担いそうなクレート名である。該当箇所を見てみる。

- +
/// Interns the names of the primitive types.
 ///
 /// All other types are defined somewhere and possibly imported, but the primitive ones need
@@ -176,21 +176,21 @@ table.insert(sym::Self { primitive_types: table }
 }
 }
- +

これは初めに列挙したプリミティブ型の一覧と一致している。doc comment にも、

- +

All other types are defined somewhere and possibly imported, but the primitive ones need special handling, since they have no place of origin.

- +

とある。次はこの struct の使用箇所を追う。追うと言っても使われている箇所は次の一箇所しかない。なお説明に不要な箇所は大きく削っている。

- +
    /// This resolves the identifier `ident` in the namespace `ns` in the current lexical scope.
 /// (略)
 fn resolve_ident_in_lexical_scope(
@@ -212,23 +212,23 @@ ns: Namespace,
 
 None
 }
- +

- 関数名や doc comment が示している通り、この関数は識別子 (identifier, ident) を現在のレキシカルスコープ内で解決 (resolve) する。if ns == TypeNSのブロック内では、primitive_type_table(上記のPrimitiveTypeTable::new()で作られた変数) に含まれている識別子 (booli32など) かどうか判定し、そうであればそれに紐づけられたプリミティブ型を返している。 + 関数名や doc comment が示している通り、この関数は識別子 (identifier, ident) を現在のレキシカルスコープ内で解決 (resolve) する。 if ns == TypeNS のブロック内では、primitive_type_table (上記の PrimitiveTypeTable::new() で作られた変数) に含まれている識別子 (booli32 など) かどうか判定し、そうであればそれに紐づけられたプリミティブ型を返している。

- +

- なお、nsは「名前空間」を示す変数である。Rust における名前空間はC言語におけるそれとほとんど同じで、今探している名前が関数名/変数名なのか型なのかマクロなのかを区別している。このifは、プリミティブ型に解決されるのは型を探しているときだけだ、と言っている。 + なお、ns は「名前空間」を示す変数である。Rust における名前空間はC言語におけるそれとほとんど同じで、今探している名前が関数名/変数名なのか型なのかマクロなのかを区別している。この if は、プリミティブ型に解決されるのは型を探しているときだけだ、と言っている。

- +

- 重要なのは、これがresolve_ident_in_lexical_scope()の最後に書かれている点である。つまり、最初に挙げたプリミティブ型の識別子は、「名前解決の最終段階で」、「他に同名の型が見つかっていなければ」プリミティブ型として解決される。 + 重要なのは、これが resolve_ident_in_lexical_scope() の最後に書かれている点である。つまり、最初に挙げたプリミティブ型の識別子は、「名前解決の最終段階で」、「他に同名の型が見つかっていなければ」プリミティブ型として解決される。

- +

動作がわかったところで、例として次のコードを考える。

- +
#![allow(non_camel_case_types)]
 
 struct bool;
@@ -236,14 +236,14 @@ ns: Namespace,
 fn main() {
 let _: bool = bool;
 }
- +

- ここでmain()boolstruct boolとして解決される。なぜなら、プリミティブ型の判定をする前にboolという名前の別の型が見つかるからだ。 + ここで main()boolstruct bool として解決される。なぜなら、プリミティブ型の判定をする前に bool という名前の別の型が見つかるからだ。

- +
-

まとめ

+

まとめ

Rust のプリミティブ型は予約語ではない。名前解決の最終段階で特別扱いされ、他に同名の型が見つかっていなければ対応するプリミティブ型に解決される。

-- cgit v1.2.3-70-g09d2