aboutsummaryrefslogtreecommitdiffhomepage
path: root/docs/posts/rust-where-are-primitive-types-from/index.html
blob: ea601b3295168fcec862d8d97367790f4a7c6809 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
<!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="この記事は Qiita から移植してきたものです。 元 URL: https://qiita.com/nsfisis/items/9a429432258bbcd6c565 前置き Rust において、プリミティブ型の名前は予約語でない。したがって、次のコードは合法である。 #![allow(non_camel_case_types)] #![allow(dead_code)] struct">
    <meta name="author" content="">
    
    <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="apple-touch-icon" href="https://blog.nsfisis.dev/apple-touch-icon.png">
    <link rel="icon" href="https://blog.nsfisis.dev/favicon.ico">
    <meta name="generator" content="Hugo 0.88.1" />
    
    
    
    <script>
      function setTheme() {
        if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
          document.body.classList.add('dark');
          return;
        }

        const time = new Date();
        const prev = localStorage.getItem('date');
        const date = String(time.getMonth() + 1) + '.' + String(time.getDate());

        const now = time.getTime();
        let sunrise;
        let sunset;

        function setBodyClass() {
          if (now > sunrise && now < sunset) return;
          document.body.classList.add('dark');
        }

        if (date !== prev) {
          fetch('https://api.ipgeolocation.io/astronomy?apiKey=5ed37d85103e4defa5df4c5298ed5215')
            .then((res) => res.json())
            .then((data) => {
              sunrise = data.sunrise.split(':').map(Number);
              sunset = data.sunset.split(':').map(Number);
            })
            .catch(() => {
              sunrise = [7, 0];
              sunset = [19, 0];
            })
            .finally(() => {
              sunrise = time.setHours(sunrise[0], sunrise[1], 0);
              sunset = time.setHours(sunset[0], sunset[1], 0);
              setBodyClass();
              localStorage.setItem('sunrise', sunrise);
              localStorage.setItem('sunset', sunset);
            });
          localStorage.setItem('date', date);
        } else {
          sunrise = Number(localStorage.getItem('sunrise'));
          sunset = Number(localStorage.getItem('sunset'));
          setBodyClass();
        }
      }
    </script>
  </head>
  <body class="single">
    <script>
      setTheme();
    </script>
    <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>
    <div class="post-meta">October 2, 2021</div>
  </header>
  <div class="post-content"><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="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>
<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 &quot;\bi128\b&quot; | wc      # i128
     165    1069   15790

$ git grep &quot;\bu128\b&quot; | wc      # u128
     293    2127   26667

$ git grep &quot;\bbool\b&quot; | wc      # cf. bool の結果
    3563   23577  294659
</code></pre><p>165 程度であれば探すことができそうだ。今回は、クレート名を見ておおよその当たりをつけた。</p>
<pre tabindex="0"><code>$ git grep &quot;\bi128\b&quot;
...
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">&lt;</span>Symbol, PrimTy<span style="color:#f92672">&gt;</span>,
}

<span style="color:#66d9ef">impl</span> PrimitiveTypeTable {
    <span style="color:#66d9ef">fn</span> <span style="color:#a6e22e">new</span>() -&gt; <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>
<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">&amp;</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>    ) -&gt; Option<span style="color:#f92672">&lt;</span>LexicalScopeBinding<span style="color:#f92672">&lt;</span><span style="color:#a6e22e">&#39;a</span><span style="color:#f92672">&gt;&gt;</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">&amp;</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) する。
<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>
<h1 id="まとめ">まとめ</h1>
<p>Rust のプリミティブ型は予約語ではない。名前解決の最終段階で特別扱いされ、他に同名の型が見つかっていなければ対応するプリミティブ型に解決される。</p>
</div>
  <footer class="post-footer">
    <ul class="post-tags">
      <li><a href="https://blog.nsfisis.dev/tags/rust">rust</a></li>
    </ul>
  </footer>
  
</article></main>
<footer class="footer">
  <span>&copy; 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span>
  <span>&middot;</span>
  <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span>
  <span>&middot;</span>
  <span>Theme️ <a href="https://github.com/nanxiaobei/hugo-paper" rel="noopener" target="_blank">Paper</a></span>
</footer>
<script src="https://blog.nsfisis.dev/highlight.min.js"></script>
<script>
  hljs.initHighlightingOnLoad();
</script>
</body>
</html>