Swiftの数値リテラルをﾁｮｯﾄﾀﾞｹ詳しく調べた話

こんにちは、[freddi](https://twitter.com/___freddi___)と申します。Swiftを始めて8ヶ月少々、最近は周囲の影響からかSwiftコンパイラやSILについてちょっと勉強し始めています。

この記事は、「Swift Advent Calendar 2018」の14日目の記事として、Swiftの数値リテラルを、基本的なところから、普段のSwiftコードよりもちょっと低いレイヤーを覗いたり、実際に触れ合って見た話をします。
皆様、どうか最後までよろしくお願いいたします。

この記事では以下のSwiftコンパイラを利用して検証を行っています。

```
$ swiftc --version
Apple Swift version 4.2.1 (swiftlang-1000.11.42 clang-1000.11.45.1)
Target: x86_64-apple-darwin17.7.0
```

# Swiftの数値リテラルの基本
この項目では、数値リテラルの基本をおさらいします。一部の方々には復習になるとは思いますので、ちょっとだけお付き合いください。

## 数値リテラルの種類(n進数)
Swiftでは、数値リテラルと言ってもいくつか種類があります。Swift.orgの[Language Guide](https://docs.swift.org/swift-book/LanguageGuide/TheBasics.html)を見れば、17を表すリテラルにも以下の４種類が存在することが確認できます。

```swift
// Language GuideのThe BasicsのNumeric Literalsから引用しています
let decimalInteger = 17           // 17 を10進数(decimal number)で表したもの
let binaryInteger = 0b10001       // 17 を2進数(binary number)で表したもの
let octalInteger = 0o21           // 17 を8進数(octal number)で表したもの
let hexadecimalInteger = 0x11     // 17 を16進数(hexadecimal)で表したもの
```
10進数は**接頭詞がなく**、それ以外は**接頭詞がある**というのが、それぞれの特徴ですね。

## 小数を含んだ数値の表現

また、10進数と16進数は、小数点以下の数を含んだ表現が可能です。

10進数では`.`を利用した表現と、`e`($ 10^e $の指数部 $ e $)を利用した表現があります。これらは馴染みが深いと思います。

```swift
let decimal0Point01Value = 0.01       // 0.01 を10進数で表したもの
let decimal0Point01ValueWithE = 1e-2  // 0.01 をeを利用して10進数で表したもの -> 1 * 10^-2
let decimal100ValueWithE = 1e+2       // 100  をeを利用して10進数で表したもの -> 1 * 10^2
```

16進数では`.`を利用した表現はありません。試しに`let someValue = 0x0b.1b`をコンパイルしたら、以下のようなエラーが出ます。[^1]

```
hexadecimal floating point literal must end with an exponent
翻訳: 16進浮動小数点リテラルは指数で終わらなければならなりません
```

ですが、**`p`($ 2^p $の指数部 $ p $)を利用して小数点を表現することが可能です。**　
上記のエラーで出ている`指数で終わらなければならなりません`の**指数**は`p`のことのようです。また、指数部は10進数しか指定できません。

```swift
let hexadecimal0Point25ValueWithP = 0x01p-2  // 0.25 をpを利用して16進数で表したもの -> 1 * 2^-2
```

また、**eとpを利用した数値リテラル単体は、Double型になるようです**。

```swift
let someHexValue = 0x0p0
print(type(of: someHexValue)) // -> Double

let someDecValue = 0e0
print(type(of: someDecValue)) // -> Double
```

## 数値リテラルの可読性を上げる書き方
数値の桁の可読性が上がる表現として、`_`を利用した桁区切りの表記もあります。これは小数点以下の桁にも、どの進数の表記でも利用できます（この場合、`_`は、コンパイル時には無視されます）。

```swift
let someBigValue = 1_000_000.000_001
```

また、0を利用したパディング(余白詰め)も利用できます。これは10進数のみのようです。

```swift
let someBigValue1 = 000010
let someBigValue2 = 012000
```

# 数値リテラルの取り扱われ方
では、ここから数値リテラルについてもう少し掘り下げて探検してみます。ここからは私達が普段いるSwiftコードよりも、もう少し低い中間言語の部分から見て行くことが少々多くなりますが、必要なところだけ解説を入れているので、そこだけ読んでもらっても結構です。

## 整数リテラルと浮動小数点リテラル
数値リテラルには、宣言時にデフォルトで設定される型があります。

たとえば、以下のように小数点が現れない数値リテラルはすべて整数型(`Int`)として設定されます。これらは **整数リテラル** と呼ばれていることが多いです。

```swift
let someValue1 = 0
print(type(of: someValue1)) // -> Int

let someValue2 = 0x0
print(type(of: someValue2)) // -> Int

let someValue3 = 0o0
print(type(of: someValue3)) // -> Int
```

以下のように「小数点が出る、指数がついている」数値リテラルはすべて浮動小数点型(`Int`)として設定されます。これらは **浮動小数点リテラル** と呼ばれていることが多いです。

```swift
let someValue1 = 0.0
print(type(of: someValue1)) // -> Double

let someValue2 = 0e1
print(type(of: someValue2)) // -> Double

let someValue3 = 0x0p0
print(type(of: someValue3)) // -> Double
```

では、整数リテラルと浮動小数点リテラルは、コンパイルされているときにどのように扱われるのでしょうか？以下のソースコードのSIL[^2]を読んで考察してみようと思います。

```swift
let someIntValue    = 3
let someDoubleValue = 4.1
```

出力されたSILを見てみましょう（読みやすいようにSwiftのシンタックスハイライトを入れてます）。
まず、`someIntValue`の宣言のSILを見てみます。

```swift
  alloc_global @$S4test12someIntValueSivp         // id: %2
  %3 = global_addr @$S4test12someIntValueSivp : $*Int // user: %8
  %4 = metatype $@thin Int.Type                   // user: %7
  %5 = integer_literal $Builtin.Int2048, 3        // user: %7
  // function_ref Int.init(_builtinIntegerLiteral:)
  %6 = function_ref @$SSi22_builtinIntegerLiteralSiBi2048__tcfC : $@convention(method) (Builtin.Int2048, @thin Int.Type) -> Int // user: %7
  %7 = apply %6(%5, %4) : $@convention(method) (Builtin.Int2048, @thin Int.Type) -> Int // user: %8
  store %7 to [trivial] %3 : $*Int                // id: %8
```

このSILコードをざっくり解説すると、

1. 最初の方に出てくる`%5 = integer_literal $Builtin.Int2048, 3`がいわゆる整数リテラルです。
1. そのリテラルを、`Int.init(_builtinIntegerLiteral:)`でIntに変換しています(`%6 = ...`と`%7 = ...`の部分)。
1. そして、変換したものをsomeIntValueに格納しています。（`store %7 to [trivial] %3 : $*Int`）

次に`someDoubleValue`の宣言のSILを見てみます。

```swift
  alloc_global @$S4test15someDoubleValueSdvp      // id: %9
  %10 = global_addr @$S4test15someDoubleValueSdvp : $*Double // user: %15
  %11 = metatype $@thin Double.Type               // user: %14
  %12 = float_literal $Builtin.FPIEEE80, 0x40018333333333333333 // 4.09999999999999999991 // user: %14
  // function_ref Double.init(_builtinFloatLiteral:)
  %13 = function_ref @$SSd20_builtinFloatLiteralSdBf80__tcfC : $@convention(method) (Builtin.FPIEEE80, @thin Double.Type) -> Double // user: %14
  %14 = apply %13(%12, %11) : $@convention(method) (Builtin.FPIEEE80, @thin Double.Type) -> Double // user: %15
  store %14 to [trivial] %10 : $*Double           // id: %15
```

最初の方に出てくる`%12 = float_literal $Builtin.FPIEEE80, 0x40018333333333333333`がいわゆる浮動小数点リテラルです。
※ `0x40018333333333333333`は`4.1`を80bit浮動小数点数に変換したものです。どうやらSILになる時点では浮動小数点リテラルは80bit浮動小数点数に変換されるらしいです。[^3]また、[環境によっては64bitになるかもしれません](https://github.com/apple/swift/blob/44f0b0519fcf57b15c665bf4646a6727a8ee9771/stdlib/public/core/Policy.swift#L107-L114)。

そのリテラルを、`Double.init(_builtinFloatLiteral:)`で... とIntのときと同じようにリテラルを`Double`のイニシャライザで変換しています。

このように、型アノテーションがない限りは、各リテラルはコンパイラ側でデフォルトで決まっている型になるようです。数値にかかわらず、どのリテラルがデフォルトでどの型になるかは、[**ここを見ればわかると思います**](https://github.com/apple/swift/blob/44f0b0519fcf57b15c665bf4646a6727a8ee9771/stdlib/public/core/Policy.swift#L77-L105)。

これらのことから、**数値リテラルは、型アノテーションがない限りは、指定されたデフォルトの型の（リテラルを引数に取る）イニシャライザを通して、デフォルトの型になる** と考えられます。


# `ExpressibleByIntegerLiteral`プロトコルについて

最後にですが、数値リテラルと関係のある`protocol`である`ExpressibleByIntegerLiteral`を使ってちょっと遊んでみた話をします。

## `ExpressibleByIntegerLiteral`とは？
ここで、ちょっと皆さんに質問です。以下のコードは、コンパイル可能でしょうか？

```swift
let someValue: CGFloat = 10
```

ほとんどの人が知っていると思いますが、**このコードはコンパイルが可能です**。（当然と思った方はすいません。）

私自身、この一行がコンパイルが通ることには、最初はかなり疑問点を抱きました。CGFloatはかなり使っていましたが、リテラルを直接代入できることを知らない間はずっと

```swift
let someValue: CGFloat = CGFloat(10)
```
のように書いていました。どのようにすれば、自分が作った型で直接数値リテラルを代入して変数宣言ができるようになるのでしょうか。

例として、`OriginalWrappingValueType`という型を作ってみます。この型は整数リテラルをイコールで代入する形で宣言できるようにするのが目標です。

```swift
import Foundation

struct OriginalWrappingValueType {
  var value: Int
}

let someValue: OriginalWrappingValueType = 10 // 目標！だけどコンパイルはできません
```

知っている人もいるかも知れませんが、`Numeric`プロトコルに準拠させればできないことはないです。

```swift
struct OriginalWrappingValueType: Numeric {
  ...
```


しかし、整数リテラルの直接代入は`Numeric`の機能ではなく、**[`Numeric`がさらに準拠している`ExpressibleByIntegerLiteral`の準拠によって可能になります](https://developer.apple.com/documentation/swift/expressiblebyintegerliteral)**。

ちなみに、**[`ExpressibleByIntegerLiteral`は、コメントで組み込みプロトコル(Intrinsic protocols)と書かれるほど、コンパイラのコアな部分に繋がりのあるプロトコルです](https://github.com/apple/swift/blob/e94361e642907675c8fce9248c6b5a39d01746b0/stdlib/public/core/CompilerProtocols.swift)。**

では、早速`OriginalWrappingValueType`を作り、`ExpressibleByIntegerLiteral`に準拠させてみましょう。

```swift
import Foundation

struct OriginalWrappingValueType: ExpressibleByIntegerLiteral {
  var value: Int
}

let someValue: OriginalWrappingValueType = 10
```

コンパイルするとエラーが出ます。どうやら、準拠するには必要なことがありそうですね。

```swift
test.swift:3:8: error: type 'OriginalWrappingValueType' does not conform to protocol 'ExpressibleByIntegerLiteral'
struct OriginalWrappingValueType: ExpressibleByIntegerLiteral {
       ^
Swift.ExpressibleByIntegerLiteral:2:20: note: protocol requires nested type 'IntegerLiteralType'; do you want to add it?
    associatedtype IntegerLiteralType : _ExpressibleByBuiltinIntegerLiteral
```

実は`init(integerLiteral:)`だけを実装すればよいです。

```swift
struct OriginalWrappingValueType: ExpressibleByIntegerLiteral {
  var value: Int

  public init(integerLiteral value: Int) {
    self.value = value
  }
}
```

これで、コンパイルエラーも出なくなり、`OriginalWrappingValueType`型の変数は整数リテラルをイコールで代入する形で宣言できるようになりました。

```swift
import Foundation

struct OriginalWrappingValueType: ExpressibleByIntegerLiteral {
  var value: Int

  public init(integerLiteral value: Int) {
    self.value = value
  }
}

let someValue: OriginalWrappingValueType = 10 // = でセットできるようになった！
```

コンパイラ側では、もしリテラルが`OriginalWrappingValueType`型の変数に=代入される際に、先程実装した`init(integerLiteral value: Int)`を呼び出して変換しているそうです。

SILを出力してみたところ、`init(integerLiteral value: Int)`が確かに呼ばれていることがわかりました。

```swift
  alloc_global @$S4test9someValueAA016OriginalWrappingC4TypeVvp // id: %2
  %3 = global_addr @$S4test9someValueAA016OriginalWrappingC4TypeVvp : $*OriginalWrappingValueType // user: %11
  %4 = metatype $@thin OriginalWrappingValueType.Type // user: %10
  %5 = metatype $@thin Int.Type                   // user: %8
  %6 = integer_literal $Builtin.Int2048, 10       // user: %8
  // function_ref Int.init(_builtinIntegerLiteral:)
  %7 = function_ref @$SSi22_builtinIntegerLiteralSiBi2048__tcfC : $@convention(method) (Builtin.Int2048, @thin Int.Type) -> Int // user: %8
  %8 = apply %7(%6, %5) : $@convention(method) (Builtin.Int2048, @thin Int.Type) -> Int // user: %10
  // function_ref OriginalWrappingValueType.init(integerLiteral:)
  // しっかりとここでExpressibleByIntegerLiteralのinit(integerLiteral:)が呼ばれている！！
  %9 = function_ref @$S4test25OriginalWrappingValueTypeV14integerLiteralACSi_tcfC : $@convention(method) (Int, @thin OriginalWrappingValueType.Type) -> OriginalWrappingValueType // user: %10
  %10 = apply %9(%8, %4) : $@convention(method) (Int, @thin OriginalWrappingValueType.Type) -> OriginalWrappingValueType // user: %11
  store %10 to [trivial] %3 : $*OriginalWrappingValueType // id: %11
```

先程の項で話した整数リテラルがInt型の変数になるフローと似ている気がします。
浮動小数点リテラルに関しては、`ExpressibleByFloatLiteral`に同じように準拠すればよいです。

## `ExpressibleBy...Literal`と型チェックの考察
`ExpressibleBy...Literal`で遊んでいると、おもしろい面をもう一つ発見しました。

[CGFloatとリテラルの演算で型チェックに時間がかかってしまったという記事も紹介されています](https://engineering.linecorp.com/ja/blog/swift-compile-build-time/)が、この記事では、以下のようなリテラルとCGFloatの混ざった計算で、型チェックにかなり時間がかかっていました。

```swift
let width = (view.bounds.width - 10 * 2 - collectionViewLayout.minimumInteritemSpacing * 4) / 4
```
この記事では、結局はコード内の数値リテラルを`CGFloat`に明示的に変換することで、型チェックの時間を削減に成功していました。

実際に、個人の環境で同じようなシチュエーションを再現しようとしました。しかし、実装中のコンパイル時に不思議な問題に直面しました。

以下が、私が問題に直面したコードです。

```swift
import Foundation

struct OriginalWrappingValueType: ExpressibleByIntegerLiteral {

  var value: Int

  public init(value: Int) {
    self.value = value
  }

  public init(integerLiteral value: Int) {
    self.value = value
  }

  static func +(lhs: OriginalWrappingValueType, rhs: OriginalWrappingValueType) -> OriginalWrappingValueType {
    return OriginalWrappingValueType(integerLiteral: lhs.value + rhs.value)
  }
  // 演算子のどれかの実装をあえて抜くのがポイント
  // static func -(lhs: OriginalWrappingValueType, rhs: OriginalWrappingValueType) -> OriginalWrappingValueType {
  //   return OriginalWrappingValueType(integerLiteral: lhs.value - rhs.value)
  // }

  static func /(lhs: OriginalWrappingValueType, rhs: OriginalWrappingValueType) -> OriginalWrappingValueType {
    return OriginalWrappingValueType(integerLiteral: lhs.value / rhs.value)
  }

  static func *(lhs: OriginalWrappingValueType, rhs: OriginalWrappingValueType) -> OriginalWrappingValueType {
    return OriginalWrappingValueType(integerLiteral: lhs.value * rhs.value)
  }
}

let someValue1 = (OriginalWrappingValueType(value: 10) * 5 - 5) / 4 - 5
let someValue2 = (OriginalWrappingValueType(value: 10) * 5 - OriginalWrappingValueType(value: 10)) / 4 - 5
```
コンパイルは失敗します。最後の計算時に`OriginalWrappingValueType`の`-`の演算の実装が見つからないからです。

このコードは私の環境では、コンパイル結果が出るまでに700~1200ミリ秒時間を要していました。
試しに、以下のような複雑な演算で試してみました。

```swift
let someValue = (OriginalWrappingValueType(value: 10 / 5) + (5 * 4) - 4 * 5 + OriginalWrappingValueType(value: 4) / 2) / 5 - 10
```

すると、コンパイルエラーはもちろん、**型チェックに35秒**要するという結果になりました。

最後のコードで、コンパイルオプションで`-dump-ast`を指定して、抽象構文木を出力するようにしました。すると、**各ノードで大量の型を列挙している構文木が出力されました**。[^3]

以下がその構文木です。(見やすくなるようにswiftのシンタックスハイライトを適用しています。)

```swift
  (top_level_code_decl
    (brace_stmt
      (pattern_binding_decl
        (pattern_named type='<<error type>>' 'someValue')
        (binary_expr type='<<error type>>' location=test.swift:32:124 range=[test.swift:32:17 - line:32:126]
          (overloaded_decl_ref_expr type='<null>' name=- number_of_decls=29 function_ref=unapplied decls=[
            Swift.(file).Float.-,
            Swift.(file).Double.-,
            Swift.(file).Float80.-,
            Swift.(file).UInt8.-,
            Swift.(file).Int8.-,
            Swift.(file).UInt16.-,
            Swift.(file).Int16.-,
            Swift.(file).UInt32.-,
            Swift.(file).Int32.-,
            Swift.(file).UInt64.-,
            Swift.(file).Int64.-,
            Swift.(file).UInt.-,
            Swift.(file).Int.-,
            Foundation.(file).Date.-,
            Foundation.(file).Decimal.-,
            Dispatch.(file).-,
            Dispatch.(file).-,
            Dispatch.(file).-,
            Dispatch.(file).-,
            CoreGraphics.(file).CGFloat.-,
            Swift.(file).FloatingPoint.-,
            Swift.(file).Numeric.-,
            Swift.(file).BinaryInteger.-,
            Swift.(file).Strideable.-,
            Swift.(file).Strideable.-,
            Swift.(file).Strideable.-,
            Swift.(file).Strideable.-,
            Foundation.(file).Measurement.-,
            Foundation.(file).Measurement.-])
          (tuple_expr implicit type='<null>'
            (binary_expr type='<null>'
              (overloaded_decl_ref_expr type='<null>' name=/ number_of_decls=20 function_ref=unapplied decls=[
                test.(file).OriginalWrappingValueType./@test.swift:23:15,
                Swift.(file).Float./,
                Swift.(file).Double./,
                Swift.(file).Float80./,
                Swift.(file).UInt8./,
                Swift.(file).Int8./,
                Swift.(file).UInt16./,

// かなり長いので中略
// かなり長いので中略
// かなり長いので中略
                              Swift.(file).FloatingPoint.*,
                              Swift.(file).Numeric.*,
                              Swift.(file).BinaryInteger.*,
                              Foundation.(file).Measurement.*,
                              Foundation.(file).Measurement.*])
                            (tuple_expr implicit type='<null>'
                              (integer_literal_expr type='<null>' value=4)
                              (integer_literal_expr type='<null>' value=5)))))
                      (binary_expr type='<null>'
                        (overloaded_decl_ref_expr type='<null>' name=/ number_of_decls=20 function_ref=unapplied decls=[
                          test.(file).OriginalWrappingValueType./@test.swift:23:15,
                          Swift.(file).Float./,
                          Swift.(file).Double./,
                          Swift.(file).Float80./,
                          Swift.(file).UInt8./,
                          Swift.(file).Int8./,
                          Swift.(file).UInt16./,
                          Swift.(file).Int16./,
                          Swift.(file).UInt32./,
                          Swift.(file).Int32./,
                          Swift.(file).UInt64./,
                          Swift.(file).Int64./,
                          Swift.(file).UInt./,
                          Swift.(file).Int./,
                          Foundation.(file).Decimal./,
                          CoreGraphics.(file).CGFloat./,
                          Swift.(file).FloatingPoint./,
                          Swift.(file).BinaryInteger./,
                          Foundation.(file).Measurement./,
                          Foundation.(file).Measurement./])
                        (tuple_expr implicit type='<null>'
                          (call_expr type='<null>' arg_labels=value:
                            (type_expr type='<null>' typerepr='OriginalWrappingValueType')
                            (tuple_expr type='<null>' names=value
                              (integer_literal_expr type='<null>' value=4)))
                          (integer_literal_expr type='<null>' value=2))))))
                (integer_literal_expr type='<null>' value=5)))
            (integer_literal_expr type='<null>' value=10))))
```
`Swift.(file).Float./`や`Swift.(file).FloatingPoint.*`の一番最後の記号は、それぞれ`+-*/`が確認できるので演算子だと考えられます。
`OriginalWrappingValueType`も演算子の列挙に含まれていましたが、`-`が列挙されている場所にはありませんでした。
また、`-`演算子を実装すれば、エラーも出ずコンパイルもすぐに終了します。

これらから、型チェックに時間がかかる理由は、

- **「`ExpressibleByIntegerLiteral`に準拠していて」かつ「四則演算のうちどれかを実装している」型は、式中の数値リテラルの変換先の型のパターンマッチングに利用されている[^4]**
- **式が複雑になる、リテラルが増える、といったリテラルの型がすぐに決めづらい状況になればなるほど、パターンマッチングの走査の時間も増えてしまう**

これらが原因なのかな、と考えています。まだ予測の段階なので、今後コンパイラのコードを読んでみて結論をつけたいと思っています。

# 最後に
数値リテラルを基本的な部分から、普段は意識しないようなちょっとレイヤーの低いところまで見ることで、数値リテラルがコンパイラでどのように取り扱われているかを知ることができました。役に立つ役に立たない関係なく、数値リテラルの世界やちょっと低いレイヤーに興味を持ってもらえれば、私として嬉しいです。もしミス等が発見されましたら、お気軽に修正リクエストやコメントをお願いします。


最後の項目では、（まだ考察ですが）ちょっとリテラルに対してマイナスなイメージを持ってしまった方々もいるかも知れません。
ですが、[数日前のSwiftアドカレ](https://qiita.com/tattn/items/3b90bb01e9771ec27b00#%E3%82%B3%E3%83%B3%E3%83%91%E3%82%A4%E3%83%A9%E3%81%AB%E5%84%AA%E3%81%97%E3%81%84%E3%82%B3%E3%83%BC%E3%83%89%E3%82%92%E6%9B%B8%E3%81%8F%E4%BA%8B%E3%82%82%E5%BF%85%E8%A6%81)にも書いてあるとおり、Swiftコンパイラに優しいコードを書けば、私が今回挙げた不思議な問題点も簡単に解決できると思っています（例えば、紹介したCGFloatの記事では明示的に数値リテラルを変換して、コンパイラの型チェックを円滑に行えるようにしています）。

本日はここまでです。皆様本当にありがとうございました！

明日は[kateinoigakukun](https://qiita.com/kateinoigakukun)さんがメタデータ周りに付いて書いてくださるそうです。メタデータの話はあまり聞いたことが無いので、とても楽しみです。皆さんもお楽しみください！

# 追記解説
@omochimetaru さんからのコメントを紹介します。最後の章には特に大きく関わります。


> Swiftの型推論において、オーバーロードされた関数があると、オーバーロードのうちのどれを選択すれば型推論が成功するのかを全て試さねばなりません。正解が複数ある場合はambiguousであるとしてエラー報告も必要です。ある式の中にk個オーバーロードされた関数がn個含まれているとき、k^nのパターンのチェックが必要になるわけです。演算子というのは見かけ上は中置していますが本質的にトップレベル関数なので、対応している型の数だけオーバーロードされているのと同じです。また、ある種類のリテラルからある型への暗黙変換も、変換先の型の数だけ候補があります。なので、演算子やリテラルを混ぜた式を作るとあっという間に組み合わせ爆発しまって推論が終わらなくなる、ということが起きているようです。

このことについて解説します。

## 型チェック時に、オーバーロードされた関数はすべてコンパイル可能か走査される
このことは、[apple/swiftのdoc/Literals.rst](https://github.com/apple/swift/blob/master/docs/Literals.rst#the-_expressiblebybuiltinstringliteral-protocol) でも言及されていました。

> In order to make this actually happen, the type-checker has to do some fancy footwork. Remember, at this point all we have is a string literal and an expected type; **if the function were overloaded, we would have to try all the types.**

> This algorithm can go forwards or backwards, since it's actually defined in terms of constraints, but it's easiest to understand as a linear process.

Swiftでは、コメントにもある通り**演算子も関数**です。最後の章の実験では`OriginalWrappingValueType`で各四則演算の関数をオーバーロードしてましたね。

実際に、オーバーロードする四則演算を関数を増やすと、



[^1]: 0x0b.bのように`.`以下がアルファベットで始まる際は、`Int`のメンバを呼び出ししているようにコンパイラに認識されるので、別のエラーが出ます(例: `error: value of type 'Int' has no member 'b'`) 。 10進数以外で`.`が使えない理由は、メンバの呼び出しかそうでないかの構文解析時の判断が難しいからかな、と考えています（**これは私の憶測なのでご注意ください**）。

[^2]: Swift Intermediate Languageの略。Swiftの中間言語のことです。詳しくは https://blog.waft.me/2018/01/09/swift-sil-1/ のSIL (Swift Intermediate Language)という項目を見てください。この記事では主に、`-emit-silgen`で出力したrawSILを載せています。

[^3]: 余談ですが、抽象構文木の時点では、指数表現があるリテラル以外はすべて10進数に変換されます。SILのときは指数部分も展開されますか、浮動小数点リテラルは先程も述べたとおり80bit浮動小数点数データで表記されます。

[^4]: `OriginalWrappingValueType`をリネームしただけの`AnotherOriginalWrappingValueType`を別途用意したところ、最後の行の式で`AnotherOriginalWrappingValueType`が関連している演算が無いのにもかかわらず、**構文木中の型の列挙には`AnotherOriginalWrappingValueType`がありました**