diff options
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 | 182 |
1 files changed, 0 insertions, 182 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 deleted file mode 100644 index 3aba89f..0000000 --- a/docs/posts/2021-10-02/rust-where-are-primitive-types-from/index.html +++ /dev/null @@ -1,182 +0,0 @@ -<!DOCTYPE html> -<html lang="ja-JP"> - <head> - <meta charset="utf-8"> - <meta http-equiv="X-UA-Compatible" content="IE=edge"> - <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> - - <title>Rust のプリミティブ型はどこからやって来るか | REPL: Rest-Eat-Program Loop</title> - - <meta name="description" content="Rust のプリミティブ型は予約語ではなく普通の識別子である。どのようにこれが名前解決されるのかを調べた。"> - <meta name="author" content="nsfisis"> - - <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet"> - <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet"> - <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.102.1" /> - - - </head> - <body class="single"> - <header class="header"> - <nav class="nav"> - <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p> - </nav> - </header> - <main class="main"> - - -<article class="post-single"> - <header class="post-header"> - <h1 class="post-title">Rust のプリミティブ型はどこからやって来るか</h1> - <ul class="post-tags"> - <li><a href="https://blog.nsfisis.dev/tags/rust">rust</a></li> - </ul> - </header> - <div class="post-content"> - <section> - <h1>更新履歴</h1> - <ul> - <li>2021-10-02: Qiita から移植</li> - </ul> - </section> - <p>この記事は Qiita から移植してきたものです。 -元 URL: <a href="https://qiita.com/nsfisis/items/9a429432258bbcd6c565">https://qiita.com/nsfisis/items/9a429432258bbcd6c565</a></p> -<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="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> -<h1 id="調査">調査</h1> -<p>調査に使用したソース (調査時点での最新 master)</p> -<p><a href="https://github.com/rust-lang/rust/tree/511ed9f2356af365ad8affe046b3dd33f7ac3c98">https://github.com/rust-lang/rust/tree/511ed9f2356af365ad8affe046b3dd33f7ac3c98</a></p> -<p>どのようにして調べるか。rustc の構造には詳しくないため、すぐに当たりをつけるのは難しい。</p> -<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 - 165 1069 15790 - -$ git grep "\bu128\b" | wc # u128 - 293 2127 26667 - -$ git grep "\bbool\b" | wc # cf. bool の結果 - 3563 23577 294659 -</code></pre><p>165 程度であれば探すことができそうだ。今回は、クレート名を見ておおよその当たりをつけた。</p> -<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="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="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="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> - - </div> -</article></main> -<footer class="footer"> - <span>© 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span> - <span>·</span> - <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span> -</footer> -<script src="https://blog.nsfisis.dev/highlight.min.js"></script> -<script> - hljs.initHighlightingOnLoad(); -</script> -</body> -</html> - |
