From 88b66f82aae2d7784002b07bfc7877932da3ec94 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Sun, 19 Mar 2023 00:47:11 +0900 Subject: fix(content): fix XML notations --- .../rust-where-are-primitive-types-from/index.html | 116 ++++++++++----------- 1 file changed, 58 insertions(+), 58 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 5bb46a0..9e77a85 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 @@ -9,7 +9,7 @@ Rust のプリミティブ型はどこからやって来るか | REPL: Rest-Eat-Program Loop - + @@ -54,7 +54,7 @@

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

@@ -65,7 +65,7 @@

前置き

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

#![allow(non_camel_case_types)]
@@ -90,12 +90,12 @@
 struct str;

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

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

@@ -103,7 +103,7 @@

調査

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

@@ -111,15 +111,15 @@

- どのようにして調べるか。rustc の構造には詳しくないため、すぐに当たりをつけるのは難しい。 + どのようにして調べるか。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
@@ -132,7 +132,7 @@ $ git grep "\bbool\b" | wc      # cf. bool の結果
 3563   23577  294659

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

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

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

/// Interns the names of the primitive types.
@@ -149,84 +149,84 @@ rustc_resolve/src/lib.rs:        table.insert(sym::i128, Int(IntTy::I128));
 /// All other types are defined somewhere and possibly imported, but the primitive ones need
 /// special handling, since they have no place of origin.
 struct PrimitiveTypeTable {
-primitive_types: FxHashMap<Symbol, PrimTy>,
+    primitive_types: FxHashMap<Symbol, PrimTy>,
 }
 
 impl PrimitiveTypeTable {
-fn new() -> PrimitiveTypeTable {
-let mut table = FxHashMap::default();
+    fn new() -> PrimitiveTypeTable {
+        let mut table = FxHashMap::default();
 
-table.insert(sym::bool, Bool);
-table.insert(sym::char, Char);
-table.insert(sym::f32, Float(FloatTy::F32));
-table.insert(sym::f64, Float(FloatTy::F64));
-table.insert(sym::isize, Int(IntTy::Isize));
-table.insert(sym::i8, Int(IntTy::I8));
-table.insert(sym::i16, Int(IntTy::I16));
-table.insert(sym::i32, Int(IntTy::I32));
-table.insert(sym::i64, Int(IntTy::I64));
-table.insert(sym::i128, Int(IntTy::I128));
-table.insert(sym::str, Str);
-table.insert(sym::usize, Uint(UintTy::Usize));
-table.insert(sym::u8, Uint(UintTy::U8));
-table.insert(sym::u16, Uint(UintTy::U16));
-table.insert(sym::u32, Uint(UintTy::U32));
-table.insert(sym::u64, Uint(UintTy::U64));
-table.insert(sym::u128, Uint(UintTy::U128));
-Self { primitive_types: table }
-}
+        table.insert(sym::bool, Bool);
+        table.insert(sym::char, Char);
+        table.insert(sym::f32, Float(FloatTy::F32));
+        table.insert(sym::f64, Float(FloatTy::F64));
+        table.insert(sym::isize, Int(IntTy::Isize));
+        table.insert(sym::i8, Int(IntTy::I8));
+        table.insert(sym::i16, Int(IntTy::I16));
+        table.insert(sym::i32, Int(IntTy::I32));
+        table.insert(sym::i64, Int(IntTy::I64));
+        table.insert(sym::i128, Int(IntTy::I128));
+        table.insert(sym::str, Str);
+        table.insert(sym::usize, Uint(UintTy::Usize));
+        table.insert(sym::u8, Uint(UintTy::U8));
+        table.insert(sym::u16, Uint(UintTy::U16));
+        table.insert(sym::u32, Uint(UintTy::U32));
+        table.insert(sym::u64, Uint(UintTy::U64));
+        table.insert(sym::u128, Uint(UintTy::U128));
+        Self { primitive_types: table }
+    }
 }

- これは初めに列挙したプリミティブ型の一覧と一致している。doc comment にも、 + これは初めに列挙したプリミティブ型の一覧と一致している。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. + All other types are defined somewhere and possibly imported, but the primitive ones need special handling, since they have no place of origin.

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

-
    /// This resolves the identifier `ident` in the namespace `ns` in the current lexical scope.
+            
/// This resolves the identifier `ident` in the namespace `ns` in the current lexical scope.
 /// (略)
 fn resolve_ident_in_lexical_scope(
-&mut self,
-mut ident: Ident,
-ns: Namespace,
-// (略)
+    &mut self,
+    mut ident: Ident,
+    ns: Namespace,
+    // (略)
 ) -> Option<LexicalScopeBinding<'a>> {
-// (略)
+    // (略)
 
-if ns == TypeNS {
-if let Some(prim_ty) = self.primitive_type_table.primitive_types.get(&ident.name) {
-let binding =
-(Res::PrimTy(*prim_ty), ty::Visibility::Public, DUMMY_SP, ExpnId::root())
-.to_name_binding(self.arenas);
-return Some(LexicalScopeBinding::Item(binding));
-}
-}
+    if ns == TypeNS {
+        if let Some(prim_ty) = self.primitive_type_table.primitive_types.get(&ident.name) {
+            let binding =
+                (Res::PrimTy(*prim_ty), ty::Visibility::Public, DUMMY_SP, ExpnId::root())
+                  .to_name_binding(self.arenas);
+            return Some(LexicalScopeBinding::Item(binding));
+        }
+    }
 
-None
+    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)]
@@ -234,18 +234,18 @@ ns: Namespace,
 struct bool;
 
 fn main() {
-let _: bool = bool;
+    let _: bool = bool;
 }

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

まとめ

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

-- cgit v1.2.3-70-g09d2