diff options
| author | nsfisis <nsfisis@gmail.com> | 2022-08-31 23:30:53 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2022-08-31 23:32:02 +0900 |
| commit | 5d5367ed00c22cc194b8a2411b2b4b828751003b (patch) | |
| tree | 02392cbb201091853c58ffccea81dbc8f9102854 /docs/posts/2021-10-02/rust-where-are-primitive-types-from | |
| parent | 8c071f04a749d2cf7ca7a23bff49d94738aa6b6d (diff) | |
| download | nsfisis.github.io-5d5367ed00c22cc194b8a2411b2b4b828751003b.tar.gz nsfisis.github.io-5d5367ed00c22cc194b8a2411b2b4b828751003b.tar.zst nsfisis.github.io-5d5367ed00c22cc194b8a2411b2b4b828751003b.zip | |
update hugo
Diffstat (limited to 'docs/posts/2021-10-02/rust-where-are-primitive-types-from')
| -rw-r--r-- | docs/posts/2021-10-02/rust-where-are-primitive-types-from/index.html | 178 |
1 files changed, 89 insertions, 89 deletions
diff --git a/docs/posts/2021-10-02/rust-where-are-primitive-types-from/index.html b/docs/posts/2021-10-02/rust-where-are-primitive-types-from/index.html index 5c1fcc5..3aba89f 100644 --- a/docs/posts/2021-10-02/rust-where-are-primitive-types-from/index.html +++ b/docs/posts/2021-10-02/rust-where-are-primitive-types-from/index.html @@ -15,7 +15,7 @@ <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet"> <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg"> - <meta name="generator" content="Hugo 0.88.1" /> + <meta name="generator" content="Hugo 0.102.1" /> </head> @@ -47,27 +47,27 @@ <hr> <h1 id="前置き">前置き</h1> <p>Rust において、プリミティブ型の名前は予約語でない。したがって、次のコードは合法である。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-rust" data-lang="rust"><span style="color:#75715e">#![allow(non_camel_case_types)]</span> -<span style="color:#75715e">#![allow(dead_code)]</span> - -<span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">bool</span>; -<span style="color:#66d9ef">struct</span> <span style="color:#a6e22e">char</span>; -<span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">i8</span>; -<span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">i16</span>; -<span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">i32</span>; -<span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">i64</span>; -<span style="color:#66d9ef">struct</span> <span style="color:#a6e22e">i128</span>; -<span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">isize</span>; -<span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">u8</span>; -<span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">u16</span>; -<span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">u32</span>; -<span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">u64</span>; -<span style="color:#66d9ef">struct</span> <span style="color:#a6e22e">u128</span>; -<span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">usize</span>; -<span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">f32</span>; -<span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">f64</span>; -<span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">str</span>; -</code></pre></div><p>では、普段単に <code>bool</code> と書いたとき、この <code>bool</code> は一体どこから来ているのか。rustc のソースを追ってみた。</p> +<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span><span style="color:#75715e">#![allow(non_camel_case_types)]</span> +</span></span><span style="display:flex;"><span><span style="color:#75715e">#![allow(dead_code)]</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">bool</span>; +</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">char</span>; +</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">i8</span>; +</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">i16</span>; +</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">i32</span>; +</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">i64</span>; +</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">i128</span>; +</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">isize</span>; +</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">u8</span>; +</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">u16</span>; +</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">u32</span>; +</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">u64</span>; +</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">u128</span>; +</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">usize</span>; +</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">f32</span>; +</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">f64</span>; +</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">str</span>; +</span></span></code></pre></div><p>では、普段単に <code>bool</code> と書いたとき、この <code>bool</code> は一体どこから来ているのか。rustc のソースを追ってみた。</p> <blockquote> <p>前提知識: 一般的なコンパイラの構造、用語。<code>rustc</code> そのものの知識は不要 (というよりも筆者自身がよく知らない)</p> </blockquote> @@ -78,91 +78,91 @@ <p>大雑把な構造としては、<code>compiler</code> フォルダ以下に <code>rustc_*</code> という名前のクレートが数十個入っている。これがどうやら <code>rustc</code> コマンドの実装部のようだ。</p> <p><code>rustc</code> はセルフホストされている (= <code>rustc</code> 自身が Rust で書かれている) ので、<code>bool</code> や <code>char</code> などで適当に検索をかけてもノイズが多すぎて話にならない。 しかし、お誂え向きなことに <code>i128</code>/<code>u128</code> というコンパイラ自身が使うことがなさそうな型が存在するのでこれを使って <code>git grep</code> してみる。</p> -<pre tabindex="0"><code>$ git grep "\bi128\b" | wc # i128 +<pre tabindex="0"><code>$ git grep "\bi128\b" | wc # i128 165 1069 15790 -$ git grep "\bu128\b" | wc # u128 +$ git grep "\bu128\b" | wc # u128 293 2127 26667 -$ git grep "\bbool\b" | wc # cf. bool の結果 +$ git grep "\bbool\b" | wc # cf. bool の結果 3563 23577 294659 </code></pre><p>165 程度であれば探すことができそうだ。今回は、クレート名を見ておおよその当たりをつけた。</p> -<pre tabindex="0"><code>$ git grep "\bi128\b" +<pre tabindex="0"><code>$ git grep "\bi128\b" ... rustc_resolve/src/lib.rs: table.insert(sym::i128, Int(IntTy::I128)); ... </code></pre><p><code>rustc_resolve</code> というのはいかにも名前解決を担いそうなクレート名である。該当箇所を見てみる。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-rust" data-lang="rust"><span style="color:#e6db74">/// Interns the names of the primitive types. -</span><span style="color:#e6db74">/// -</span><span style="color:#e6db74">/// All other types are defined somewhere and possibly imported, but the primitive ones need -</span><span style="color:#e6db74">/// special handling, since they have no place of origin. -</span><span style="color:#e6db74"></span><span style="color:#66d9ef">struct</span> <span style="color:#a6e22e">PrimitiveTypeTable</span> { - primitive_types: <span style="color:#a6e22e">FxHashMap</span><span style="color:#f92672"><</span>Symbol, PrimTy<span style="color:#f92672">></span>, -} - -<span style="color:#66d9ef">impl</span> PrimitiveTypeTable { - <span style="color:#66d9ef">fn</span> <span style="color:#a6e22e">new</span>() -> <span style="color:#a6e22e">PrimitiveTypeTable</span> { - <span style="color:#66d9ef">let</span> <span style="color:#66d9ef">mut</span> table <span style="color:#f92672">=</span> FxHashMap::default(); - - table.insert(sym::<span style="color:#66d9ef">bool</span>, Bool); - table.insert(sym::char, Char); - table.insert(sym::<span style="color:#66d9ef">f32</span>, Float(FloatTy::F32)); - table.insert(sym::<span style="color:#66d9ef">f64</span>, Float(FloatTy::F64)); - table.insert(sym::<span style="color:#66d9ef">isize</span>, Int(IntTy::Isize)); - table.insert(sym::<span style="color:#66d9ef">i8</span>, Int(IntTy::I8)); - table.insert(sym::<span style="color:#66d9ef">i16</span>, Int(IntTy::I16)); - table.insert(sym::<span style="color:#66d9ef">i32</span>, Int(IntTy::I32)); - table.insert(sym::<span style="color:#66d9ef">i64</span>, Int(IntTy::I64)); - table.insert(sym::<span style="color:#66d9ef">i128</span>, Int(IntTy::I128)); - table.insert(sym::<span style="color:#66d9ef">str</span>, Str); - table.insert(sym::<span style="color:#66d9ef">usize</span>, Uint(UintTy::Usize)); - table.insert(sym::<span style="color:#66d9ef">u8</span>, Uint(UintTy::U8)); - table.insert(sym::<span style="color:#66d9ef">u16</span>, Uint(UintTy::U16)); - table.insert(sym::<span style="color:#66d9ef">u32</span>, Uint(UintTy::U32)); - table.insert(sym::<span style="color:#66d9ef">u64</span>, Uint(UintTy::U64)); - table.insert(sym::<span style="color:#66d9ef">u128</span>, Uint(UintTy::U128)); - Self { primitive_types: <span style="color:#a6e22e">table</span> } - } -} -</code></pre></div><p>これは初めに列挙したプリミティブ型の一覧と一致している。doc comment にも、</p> +<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span><span style="color:#e6db74">/// Interns the names of the primitive types. +</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">/// +</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">/// All other types are defined somewhere and possibly imported, but the primitive ones need +</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">/// special handling, since they have no place of origin. +</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"></span><span style="color:#66d9ef">struct</span> <span style="color:#a6e22e">PrimitiveTypeTable</span> { +</span></span><span style="display:flex;"><span> primitive_types: <span style="color:#a6e22e">FxHashMap</span><span style="color:#f92672"><</span>Symbol, PrimTy<span style="color:#f92672">></span>, +</span></span><span style="display:flex;"><span>} +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#66d9ef">impl</span> PrimitiveTypeTable { +</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">fn</span> <span style="color:#a6e22e">new</span>() -> <span style="color:#a6e22e">PrimitiveTypeTable</span> { +</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">let</span> <span style="color:#66d9ef">mut</span> table <span style="color:#f92672">=</span> FxHashMap::default(); +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">bool</span>, Bool); +</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">char</span>, Char); +</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">f32</span>, Float(FloatTy::F32)); +</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">f64</span>, Float(FloatTy::F64)); +</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">isize</span>, Int(IntTy::Isize)); +</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">i8</span>, Int(IntTy::I8)); +</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">i16</span>, Int(IntTy::I16)); +</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">i32</span>, Int(IntTy::I32)); +</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">i64</span>, Int(IntTy::I64)); +</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">i128</span>, Int(IntTy::I128)); +</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">str</span>, Str); +</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">usize</span>, Uint(UintTy::Usize)); +</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">u8</span>, Uint(UintTy::U8)); +</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">u16</span>, Uint(UintTy::U16)); +</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">u32</span>, Uint(UintTy::U32)); +</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">u64</span>, Uint(UintTy::U64)); +</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">u128</span>, Uint(UintTy::U128)); +</span></span><span style="display:flex;"><span> Self { primitive_types: <span style="color:#a6e22e">table</span> } +</span></span><span style="display:flex;"><span> } +</span></span><span style="display:flex;"><span>} +</span></span></code></pre></div><p>これは初めに列挙したプリミティブ型の一覧と一致している。doc comment にも、</p> <blockquote> <p>All other types are defined somewhere and possibly imported, but the primitive ones need special handling, since they have no place of origin.</p> </blockquote> <p>とある。次はこの struct の使用箇所を追う。追うと言っても使われている箇所は次の一箇所しかない。なお説明に不要な箇所は大きく削っている。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-rust" data-lang="rust"> <span style="color:#e6db74">/// This resolves the identifier `ident` in the namespace `ns` in the current lexical scope. -</span><span style="color:#e6db74"></span> <span style="color:#e6db74">/// (略) -</span><span style="color:#e6db74"></span> <span style="color:#66d9ef">fn</span> <span style="color:#a6e22e">resolve_ident_in_lexical_scope</span>( - <span style="color:#f92672">&</span><span style="color:#66d9ef">mut</span> self, - <span style="color:#66d9ef">mut</span> ident: <span style="color:#a6e22e">Ident</span>, - ns: <span style="color:#a6e22e">Namespace</span>, - <span style="color:#75715e">// (略) -</span><span style="color:#75715e"></span> ) -> Option<span style="color:#f92672"><</span>LexicalScopeBinding<span style="color:#f92672"><</span><span style="color:#a6e22e">'a</span><span style="color:#f92672">>></span> { - <span style="color:#75715e">// (略) -</span><span style="color:#75715e"></span> - <span style="color:#66d9ef">if</span> ns <span style="color:#f92672">==</span> TypeNS { - <span style="color:#66d9ef">if</span> <span style="color:#66d9ef">let</span> Some(prim_ty) <span style="color:#f92672">=</span> self.primitive_type_table.primitive_types.get(<span style="color:#f92672">&</span>ident.name) { - <span style="color:#66d9ef">let</span> binding <span style="color:#f92672">=</span> - (Res::PrimTy(<span style="color:#f92672">*</span>prim_ty), ty::Visibility::Public, DUMMY_SP, ExpnId::root()) - .to_name_binding(self.arenas); - <span style="color:#66d9ef">return</span> Some(LexicalScopeBinding::Item(binding)); - } - } - - None - } -</code></pre></div><p>関数名や doc comment が示している通り、この関数は識別子 (identifier, ident) を現在のレキシカルスコープ内で解決 (resolve) する。 +<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span> <span style="color:#e6db74">/// This resolves the identifier `ident` in the namespace `ns` in the current lexical scope. +</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"></span> <span style="color:#e6db74">/// (略) +</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"></span> <span style="color:#66d9ef">fn</span> <span style="color:#a6e22e">resolve_ident_in_lexical_scope</span>( +</span></span><span style="display:flex;"><span> <span style="color:#f92672">&</span><span style="color:#66d9ef">mut</span> self, +</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">mut</span> ident: <span style="color:#a6e22e">Ident</span>, +</span></span><span style="display:flex;"><span> ns: <span style="color:#a6e22e">Namespace</span>, +</span></span><span style="display:flex;"><span> <span style="color:#75715e">// (略) +</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> ) -> Option<span style="color:#f92672"><</span>LexicalScopeBinding<span style="color:#f92672"><'</span><span style="color:#a6e22e">a</span><span style="color:#f92672">>></span> { +</span></span><span style="display:flex;"><span> <span style="color:#75715e">// (略) +</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> +</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> ns <span style="color:#f92672">==</span> TypeNS { +</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#66d9ef">let</span> Some(prim_ty) <span style="color:#f92672">=</span> self.primitive_type_table.primitive_types.get(<span style="color:#f92672">&</span>ident.name) { +</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">let</span> binding <span style="color:#f92672">=</span> +</span></span><span style="display:flex;"><span> (Res::PrimTy(<span style="color:#f92672">*</span>prim_ty), ty::Visibility::Public, DUMMY_SP, ExpnId::root()) +</span></span><span style="display:flex;"><span> .to_name_binding(self.arenas); +</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> Some(LexicalScopeBinding::Item(binding)); +</span></span><span style="display:flex;"><span> } +</span></span><span style="display:flex;"><span> } +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> None +</span></span><span style="display:flex;"><span> } +</span></span></code></pre></div><p>関数名や doc comment が示している通り、この関数は識別子 (identifier, ident) を現在のレキシカルスコープ内で解決 (resolve) する。 <code>if ns == TypeNS</code> のブロック内では、<code>primitive_type_table</code> (上記の <code>PrimitiveTypeTable::new()</code> で作られた変数) に含まれている識別子 (<code>bool</code>、<code>i32</code> など) かどうか判定し、そうであればそれに紐づけられたプリミティブ型を返している。</p> <p>なお、<code>ns</code> は「名前空間」を示す変数である。Rust における名前空間はC言語におけるそれとほとんど同じで、今探している名前が関数名/変数名なのか型なのかマクロなのかを区別している。この <code>if</code> は、プリミティブ型に解決されるのは型を探しているときだけだ、と言っている。</p> <p>重要なのは、これが <code>resolve_ident_in_lexical_scope()</code> の最後に書かれている点である。つまり、最初に挙げたプリミティブ型の識別子は、「名前解決の最終段階で」、「他に同名の型が見つかっていなければ」プリミティブ型として解決される。</p> <p>動作がわかったところで、例として次のコードを考える。</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-rust" data-lang="rust"><span style="color:#75715e">#![allow(non_camel_case_types)]</span> - -<span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">bool</span>; - -<span style="color:#66d9ef">fn</span> <span style="color:#a6e22e">main</span>() { - <span style="color:#66d9ef">let</span> _: <span style="color:#66d9ef">bool</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">bool</span>; -} -</code></pre></div><p>ここで <code>main()</code> の <code>bool</code> は <code>struct bool</code> として解決される。なぜなら、プリミティブ型の判定をする前に <code>bool</code> という名前の別の型が見つかるからだ。</p> +<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span><span style="color:#75715e">#![allow(non_camel_case_types)]</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">bool</span>; +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fn</span> <span style="color:#a6e22e">main</span>() { +</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">let</span> _: <span style="color:#66d9ef">bool</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">bool</span>; +</span></span><span style="display:flex;"><span>} +</span></span></code></pre></div><p>ここで <code>main()</code> の <code>bool</code> は <code>struct bool</code> として解決される。なぜなら、プリミティブ型の判定をする前に <code>bool</code> という名前の別の型が見つかるからだ。</p> <h1 id="まとめ">まとめ</h1> <p>Rust のプリミティブ型は予約語ではない。名前解決の最終段階で特別扱いされ、他に同名の型が見つかっていなければ対応するプリミティブ型に解決される。</p> |
