aboutsummaryrefslogtreecommitdiffhomepage
path: root/content/posts/2021-10-02/rust-where-are-primitive-types-from.xml
diff options
context:
space:
mode:
Diffstat (limited to 'content/posts/2021-10-02/rust-where-are-primitive-types-from.xml')
-rw-r--r--content/posts/2021-10-02/rust-where-are-primitive-types-from.xml84
1 files changed, 42 insertions, 42 deletions
diff --git a/content/posts/2021-10-02/rust-where-are-primitive-types-from.xml b/content/posts/2021-10-02/rust-where-are-primitive-types-from.xml
index 7c19fc5..5902450 100644
--- a/content/posts/2021-10-02/rust-where-are-primitive-types-from.xml
+++ b/content/posts/2021-10-02/rust-where-are-primitive-types-from.xml
@@ -15,19 +15,19 @@
</revision>
</revhistory>
</info>
- <simpara>
+ <para>
この記事は Qiita から移植してきたものです。 元 URL:
<link xl:href="https://qiita.com/nsfisis/items/9a429432258bbcd6c565">https://qiita.com/nsfisis/items/9a429432258bbcd6c565</link>
- </simpara>
- <simpara>
+ </para>
+ <para>
<hr/>
- </simpara>
+ </para>
<section xml:id="intro">
<title>前置き</title>
- <simpara>
+ <para>
Rust
において、プリミティブ型の名前は予約語でない。したがって、次のコードは合法である。
- </simpara>
+ </para>
<programlisting language="rust" linenumbering="unnumbered">
<![CDATA[
#![allow(non_camel_case_types)]
@@ -52,42 +52,42 @@
struct str;
]]>
</programlisting>
- <simpara>
+ <para>
では、普段単に <literal>bool</literal> と書いたとき、この <literal>bool</literal>
は一体どこから来ているのか。rustc のソースを追ってみた。
- </simpara>
+ </para>
<blockquote>
- <simpara>
+ <para>
前提知識: 一般的なコンパイラの構造、用語。<literal>rustc</literal> そのものの知識は不要
(というよりも筆者自身がよく知らない)
- </simpara>
+ </para>
</blockquote>
</section>
<section xml:id="code-reading">
<title>調査</title>
- <simpara>
+ <para>
調査に使用したソース (調査時点での最新 master)
- </simpara>
- <simpara>
+ </para>
+ <para>
<link xl:href="https://github.com/rust-lang/rust/tree/511ed9f2356af365ad8affe046b3dd33f7ac3c98">https://github.com/rust-lang/rust/tree/511ed9f2356af365ad8affe046b3dd33f7ac3c98</link>
- </simpara>
- <simpara>
+ </para>
+ <para>
どのようにして調べるか。rustc
の構造には詳しくないため、すぐに当たりをつけるのは難しい。
- </simpara>
- <simpara>
+ </para>
+ <para>
大雑把な構造としては、<literal>compiler</literal> フォルダ以下に <literal>rustc_*</literal>
という名前のクレートが数十個入っている。これがどうやら <literal>rustc</literal>
コマンドの実装部のようだ。
- </simpara>
- <simpara>
+ </para>
+ <para>
<literal>rustc</literal> はセルフホストされている (= <literal>rustc</literal> 自身が Rust で書かれている)
ので、<literal>bool</literal> や <literal>char</literal>
などで適当に検索をかけてもノイズが多すぎて話にならない。
しかし、お誂え向きなことに <literal>i128</literal>/<literal>u128</literal>
というコンパイラ自身が使うことがなさそうな型が存在するのでこれを使って
<literal>git grep</literal> してみる。
- </simpara>
+ </para>
<literallayout class="monospaced">
<![CDATA[
$ git grep "\bi128\b" | wc # i128
@@ -100,10 +100,10 @@
3563 23577 294659
]]>
</literallayout>
- <simpara>
+ <para>
165
程度であれば探すことができそうだ。今回は、クレート名を見ておおよその当たりをつけた。
- </simpara>
+ </para>
<literallayout class="monospaced">
<![CDATA[
$ git grep "\bi128\b"
@@ -112,10 +112,10 @@
...
]]>
</literallayout>
- <simpara>
+ <para>
<literal>rustc_resolve</literal>
というのはいかにも名前解決を担いそうなクレート名である。該当箇所を見てみる。
- </simpara>
+ </para>
<programlisting language="rust" linenumbering="unnumbered">
<![CDATA[
/// Interns the names of the primitive types.
@@ -152,21 +152,21 @@
}
]]>
</programlisting>
- <simpara>
+ <para>
これは初めに列挙したプリミティブ型の一覧と一致している。doc comment
にも、
- </simpara>
+ </para>
<blockquote>
- <simpara>
+ <para>
All other types are defined somewhere and possibly imported, but the
primitive ones need special handling, since they have no place of
origin.
- </simpara>
+ </para>
</blockquote>
- <simpara>
+ <para>
とある。次はこの struct
の使用箇所を追う。追うと言っても使われている箇所は次の一箇所しかない。なお説明に不要な箇所は大きく削っている。
- </simpara>
+ </para>
<programlisting language="rust" linenumbering="unnumbered">
<![CDATA[
/// This resolves the identifier `ident` in the namespace `ns` in the current lexical scope.
@@ -192,27 +192,27 @@
}
]]>
</programlisting>
- <simpara>
+ <para>
関数名や doc comment が示している通り、この関数は識別子 (identifier,
ident) を現在のレキシカルスコープ内で解決 (resolve) する。
<literal>if ns == TypeNS</literal> のブロック内では、<literal>primitive_type_table</literal> (上記の
<literal>PrimitiveTypeTable::new()</literal> で作られた変数) に含まれている識別子
(<literal>bool</literal>、<literal>i32</literal> など)
かどうか判定し、そうであればそれに紐づけられたプリミティブ型を返している。
- </simpara>
- <simpara>
+ </para>
+ <para>
なお、<literal>ns</literal> は「名前空間」を示す変数である。Rust
における名前空間はC言語におけるそれとほとんど同じで、今探している名前が関数名/変数名なのか型なのかマクロなのかを区別している。この
<literal>if</literal>
は、プリミティブ型に解決されるのは型を探しているときだけだ、と言っている。
- </simpara>
- <simpara>
+ </para>
+ <para>
重要なのは、これが <literal>resolve_ident_in_lexical_scope()</literal>
の最後に書かれている点である。つまり、最初に挙げたプリミティブ型の識別子は、「名前解決の最終段階で」、「他に同名の型が見つかっていなければ」プリミティブ型として解決される。
- </simpara>
- <simpara>
+ </para>
+ <para>
動作がわかったところで、例として次のコードを考える。
- </simpara>
+ </para>
<programlisting language="rust" linenumbering="unnumbered">
<![CDATA[
#![allow(non_camel_case_types)]
@@ -224,17 +224,17 @@
}
]]>
</programlisting>
- <simpara>
+ <para>
ここで <literal>main()</literal> の <literal>bool</literal> は <literal>struct bool</literal>
として解決される。なぜなら、プリミティブ型の判定をする前に <literal>bool</literal>
という名前の別の型が見つかるからだ。
- </simpara>
+ </para>
</section>
<section xml:id="outro">
<title>まとめ</title>
- <simpara>
+ <para>
Rust
のプリミティブ型は予約語ではない。名前解決の最終段階で特別扱いされ、他に同名の型が見つかっていなければ対応するプリミティブ型に解決される。
- </simpara>
+ </para>
</section>
</article>