-emit-silgenで見るSwift4.1からのenumとEquatable

※バージョンが間違えてたので修正・・・すいません

# `Equatable`がSwift4.1から使いやすくなりました 🎉🎉🎉🎉
みなさんご存知の通り、Swift4.1から`Equatable`が使いやすくなりました。
Swift4までは、`Equatable`プロトコルに準拠するときは、以下のように`static public func ==(lhs:rhs:) -> Bool`を自分で書き上げないといけませんでしたね。

```swift
enum Nyan: Equatable {
  case hoge
  case fuga
    
  static public func ==(lhs: Nyan, rhs: Nyan) -> Bool {
    switch (lhs, rhs) {
    case (.hoge, .hoge), (.fuga, .fuga):
      return true
    default:
      return false
    }
  }
}
```

もしメンバ変数や`case`の数が膨大になれば、`switch`文中の比較はその分必要になりますので、当然コードの量も膨大になります。
値付きの`case`(e.g. `case hoge(Int)`)になると、中の値まで比較しないといけなくなりますね・・・。

でも大丈夫！Swift4.1から、`static public func　== (lhs:rhs:) -> Bool`を自分で書かなくて良くなりました。
わーい！コード量が減るよ！劇的BeforeAfterだね！

```swift
enum Nyan: Equatable { // Equatableに準拠しますよ〜ということだけを言えばいい
  case hoge
  case fuga
}
```

# ・・・なんで書かないでよくなったの？
さて、このときですが`Nyan`では何が起こっているのでしょうか？:thinking_face::thinking_face::thinking_face:
今まで書くべきだった`static public func ==(lhs:rhs:) -> Bool`は果たしてどこに？！
では、以下のコードをつかって、Swift4.1からの新しい`Equatable`を覗いてみましょう！

```swift
enum Nyan: Equatable {
  case hoge
  case fuga
}
```

# `enum`による`Equatable`を、`-emit-silgen`で覗いてみる
こういうときは[SIL](https://blog.waft.me/2018/01/09/swift-sil-1/)を見るのがいいかもしれません。
では、`enum`による`Equatable`を、早速`-emit-silgen`でraw SILを生成して覗いてみましょう！

```bash
swiftc -emit-silgen nyan.swift
```
で、出力されたraw SILがこちらです！（この時点でraw SILは読み流して結構です）

```
sil_stage raw

import Builtin
import Swift
import SwiftShims

enum Nyan : Equatable {
  case hoge
  case fuga
  var hashValue: Int { get }
  func hash(into hasher: inout Hasher)
  @_implements(Equatable, ==(_:_:)) static func __derived_enum_equals(_ a: Nyan, _ b: Nyan) -> Bool
}

// main
sil @main : $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 {
bb0(%0 : $Int32, %1 : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>):
  %2 = integer_literal $Builtin.Int32, 0          // user: %3
  %3 = struct $Int32 (%2 : $Builtin.Int32)        // user: %4
  return %3 : $Int32                              // id: %4
} // end sil function 'main'

// Nyan.hashValue.getter
sil hidden @$S1A4NyanO9hashValueSivg : $@convention(method) (Nyan) -> Int {
// %0                                             // users: %3, %1
bb0(%0 : $Nyan):
  debug_value %0 : $Nyan, let, name "self", argno 1 // id: %1
  %2 = alloc_stack $Nyan                          // users: %6, %5, %3
  store %0 to [trivial] %2 : $*Nyan               // id: %3
  // function_ref _hashValue<A>(for:)
  %4 = function_ref @$Ss10_hashValue3forSix_tSHRzlF : $@convention(thin) <τ_0_0 where τ_0_0 : Hashable> (@in_guaranteed τ_0_0) -> Int // user: %5
  %5 = apply %4<Nyan>(%2) : $@convention(thin) <τ_0_0 where τ_0_0 : Hashable> (@in_guaranteed τ_0_0) -> Int // user: %7
  dealloc_stack %2 : $*Nyan                       // id: %6
  return %5 : $Int                                // id: %7
} // end sil function '$S1A4NyanO9hashValueSivg'

// _hashValue<A>(for:)
sil [serialized] [always_inline] @$Ss10_hashValue3forSix_tSHRzlF : $@convention(thin) <τ_0_0 where τ_0_0 : Hashable> (@in_guaranteed τ_0_0) -> Int

// Nyan.hash(into:)
sil hidden @$S1A4NyanO4hash4intoys6HasherVz_tF : $@convention(method) (@inout Hasher, Nyan) -> () {
// %0                                             // users: %29, %2
// %1                                             // users: %7, %3
bb0(%0 : $*Hasher, %1 : $Nyan):
  debug_value_addr %0 : $*Hasher, var, name "hasher", argno 1 // id: %2
  debug_value %1 : $Nyan, let, name "self", argno 2 // id: %3
  %4 = alloc_box ${ var Int }, var, name "discriminator" // user: %5
  %5 = mark_uninitialized [var] %4 : ${ var Int } // users: %34, %6
  %6 = project_box %5 : ${ var Int }, 0           // users: %24, %20, %12
  switch_enum %1 : $Nyan, case #Nyan.hoge!enumelt: bb1, case #Nyan.fuga!enumelt: bb2 // id: %7

bb1:                                              // Preds: bb0
  %8 = metatype $@thin Int.Type                   // user: %11
  %9 = integer_literal $Builtin.Int2048, 0        // user: %11
  // function_ref Int.init(_builtinIntegerLiteral:)
  %10 = function_ref @$SSi22_builtinIntegerLiteralSiBi2048__tcfC : $@convention(method) (Builtin.Int2048, @thin Int.Type) -> Int // user: %11
  %11 = apply %10(%9, %8) : $@convention(method) (Builtin.Int2048, @thin Int.Type) -> Int // user: %13
  %12 = begin_access [modify] [unknown] %6 : $*Int // users: %14, %13
  assign %11 to %12 : $*Int                       // id: %13
  end_access %12 : $*Int                          // id: %14
  br bb3                                          // id: %15

bb2:                                              // Preds: bb0
  %16 = metatype $@thin Int.Type                  // user: %19
  %17 = integer_literal $Builtin.Int2048, 1       // user: %19
  // function_ref Int.init(_builtinIntegerLiteral:)
  %18 = function_ref @$SSi22_builtinIntegerLiteralSiBi2048__tcfC : $@convention(method) (Builtin.Int2048, @thin Int.Type) -> Int // user: %19
  %19 = apply %18(%17, %16) : $@convention(method) (Builtin.Int2048, @thin Int.Type) -> Int // user: %21
  %20 = begin_access [modify] [unknown] %6 : $*Int // users: %22, %21
  assign %19 to %20 : $*Int                       // id: %21
  end_access %20 : $*Int                          // id: %22
  br bb3                                          // id: %23

bb3:                                              // Preds: bb2 bb1
  %24 = begin_access [read] [unknown] %6 : $*Int  // users: %26, %25
  %25 = load [trivial] %24 : $*Int                // user: %28
  end_access %24 : $*Int                          // id: %26
  %27 = alloc_stack $Int                          // users: %33, %31, %28
  store %25 to [trivial] %27 : $*Int              // id: %28
  %29 = begin_access [modify] [unknown] %0 : $*Hasher // users: %32, %31
  // function_ref Hasher.combine<A>(_:)
  %30 = function_ref @$Ss6HasherV7combineyyxSHRzlF : $@convention(method) <τ_0_0 where τ_0_0 : Hashable> (@in_guaranteed τ_0_0, @inout Hasher) -> () // user: %31
  %31 = apply %30<Int>(%27, %29) : $@convention(method) <τ_0_0 where τ_0_0 : Hashable> (@in_guaranteed τ_0_0, @inout Hasher) -> ()
  end_access %29 : $*Hasher                       // id: %32
  dealloc_stack %27 : $*Int                       // id: %33
  destroy_value %5 : ${ var Int }                 // id: %34
  %35 = tuple ()                                  // user: %36
  return %35 : $()                                // id: %36
} // end sil function '$S1A4NyanO4hash4intoys6HasherVz_tF'

// Int.init(_builtinIntegerLiteral:)
sil [transparent] [serialized] @$SSi22_builtinIntegerLiteralSiBi2048__tcfC : $@convention(method) (Builtin.Int2048, @thin Int.Type) -> Int

// Hasher.combine<A>(_:)
sil [serialized] [always_inline] @$Ss6HasherV7combineyyxSHRzlF : $@convention(method) <τ_0_0 where τ_0_0 : Hashable> (@in_guaranteed τ_0_0, @inout Hasher) -> ()

// static Nyan.__derived_enum_equals(_:_:)
sil hidden @$S1A4NyanO21__derived_enum_equalsySbAC_ACtFZ : $@convention(method) (Nyan, Nyan, @thin Nyan.Type) -> Bool {
// %0                                             // users: %9, %3
// %1                                             // users: %29, %4
// %2                                             // user: %5
bb0(%0 : $Nyan, %1 : $Nyan, %2 : $@thin Nyan.Type):
  debug_value %0 : $Nyan, let, name "a", argno 1  // id: %3
  debug_value %1 : $Nyan, let, name "b", argno 2  // id: %4
  debug_value %2 : $@thin Nyan.Type, let, name "self", argno 3 // id: %5
  %6 = alloc_box ${ var Int }, var, name "index_a" // user: %7
  %7 = mark_uninitialized [var] %6 : ${ var Int } // users: %56, %8
  %8 = project_box %7 : ${ var Int }, 0           // users: %47, %22, %14
  switch_enum %0 : $Nyan, case #Nyan.hoge!enumelt: bb1, case #Nyan.fuga!enumelt: bb2 // id: %9

bb1:                                              // Preds: bb0
  %10 = metatype $@thin Int.Type                  // user: %13
  %11 = integer_literal $Builtin.Int2048, 0       // user: %13
  // function_ref Int.init(_builtinIntegerLiteral:)
  %12 = function_ref @$SSi22_builtinIntegerLiteralSiBi2048__tcfC : $@convention(method) (Builtin.Int2048, @thin Int.Type) -> Int // user: %13
  %13 = apply %12(%11, %10) : $@convention(method) (Builtin.Int2048, @thin Int.Type) -> Int // user: %15
  %14 = begin_access [modify] [unknown] %8 : $*Int // users: %16, %15
  assign %13 to %14 : $*Int                       // id: %15
  end_access %14 : $*Int                          // id: %16
  br bb3                                          // id: %17

bb2:                                              // Preds: bb0
  %18 = metatype $@thin Int.Type                  // user: %21
  %19 = integer_literal $Builtin.Int2048, 1       // user: %21
  // function_ref Int.init(_builtinIntegerLiteral:)
  %20 = function_ref @$SSi22_builtinIntegerLiteralSiBi2048__tcfC : $@convention(method) (Builtin.Int2048, @thin Int.Type) -> Int // user: %21
  %21 = apply %20(%19, %18) : $@convention(method) (Builtin.Int2048, @thin Int.Type) -> Int // user: %23
  %22 = begin_access [modify] [unknown] %8 : $*Int // users: %24, %23
  assign %21 to %22 : $*Int                       // id: %23
  end_access %22 : $*Int                          // id: %24
  br bb3                                          // id: %25

bb3:                                              // Preds: bb2 bb1
  %26 = alloc_box ${ var Int }, var, name "index_b" // user: %27
  %27 = mark_uninitialized [var] %26 : ${ var Int } // users: %55, %28
  %28 = project_box %27 : ${ var Int }, 0         // users: %50, %42, %34
  switch_enum %1 : $Nyan, case #Nyan.hoge!enumelt: bb4, case #Nyan.fuga!enumelt: bb5 // id: %29

bb4:                                              // Preds: bb3
  %30 = metatype $@thin Int.Type                  // user: %33
  %31 = integer_literal $Builtin.Int2048, 0       // user: %33
  // function_ref Int.init(_builtinIntegerLiteral:)
  %32 = function_ref @$SSi22_builtinIntegerLiteralSiBi2048__tcfC : $@convention(method) (Builtin.Int2048, @thin Int.Type) -> Int // user: %33
  %33 = apply %32(%31, %30) : $@convention(method) (Builtin.Int2048, @thin Int.Type) -> Int // user: %35
  %34 = begin_access [modify] [unknown] %28 : $*Int // users: %36, %35
  assign %33 to %34 : $*Int                       // id: %35
  end_access %34 : $*Int                          // id: %36
  br bb6                                          // id: %37

bb5:                                              // Preds: bb3
  %38 = metatype $@thin Int.Type                  // user: %41
  %39 = integer_literal $Builtin.Int2048, 1       // user: %41
  // function_ref Int.init(_builtinIntegerLiteral:)
  %40 = function_ref @$SSi22_builtinIntegerLiteralSiBi2048__tcfC : $@convention(method) (Builtin.Int2048, @thin Int.Type) -> Int // user: %41
  %41 = apply %40(%39, %38) : $@convention(method) (Builtin.Int2048, @thin Int.Type) -> Int // user: %43
  %42 = begin_access [modify] [unknown] %28 : $*Int // users: %44, %43
  assign %41 to %42 : $*Int                       // id: %43
  end_access %42 : $*Int                          // id: %44
  br bb6                                          // id: %45

bb6:                                              // Preds: bb5 bb4
  %46 = metatype $@thin Int.Type                  // user: %54
  %47 = begin_access [read] [unknown] %8 : $*Int  // users: %49, %48
  %48 = load [trivial] %47 : $*Int                // user: %54
  end_access %47 : $*Int                          // id: %49
  %50 = begin_access [read] [unknown] %28 : $*Int // users: %52, %51
  %51 = load [trivial] %50 : $*Int                // user: %54
  end_access %50 : $*Int                          // id: %52
  // function_ref static Int.== infix(_:_:)
  %53 = function_ref @$SSi2eeoiySbSi_SitFZ : $@convention(method) (Int, Int, @thin Int.Type) -> Bool // user: %54
  %54 = apply %53(%48, %51, %46) : $@convention(method) (Int, Int, @thin Int.Type) -> Bool // user: %57
  destroy_value %27 : ${ var Int }                // id: %55
  destroy_value %7 : ${ var Int }                 // id: %56
  return %54 : $Bool                              // id: %57
} // end sil function '$S1A4NyanO21__derived_enum_equalsySbAC_ACtFZ'

// static Int.== infix(_:_:)
sil [transparent] [serialized] @$SSi2eeoiySbSi_SitFZ : $@convention(method) (Int, Int, @thin Int.Type) -> Bool

// protocol witness for Hashable.hashValue.getter in conformance Nyan
sil private [transparent] [thunk] @$S1A4NyanOSHAASH9hashValueSivgTW : $@convention(witness_method: Hashable) (@in_guaranteed Nyan) -> Int {
// %0                                             // user: %1
bb0(%0 : $*Nyan):
  %1 = load [trivial] %0 : $*Nyan                 // user: %3
  // function_ref Nyan.hashValue.getter
  %2 = function_ref @$S1A4NyanO9hashValueSivg : $@convention(method) (Nyan) -> Int // user: %3
  %3 = apply %2(%1) : $@convention(method) (Nyan) -> Int // user: %4
  return %3 : $Int                                // id: %4
} // end sil function '$S1A4NyanOSHAASH9hashValueSivgTW'

// protocol witness for Hashable.hash(into:) in conformance Nyan
sil private [transparent] [thunk] @$S1A4NyanOSHAASH4hash4intoys6HasherVz_tFTW : $@convention(witness_method: Hashable) (@inout Hasher, @in_guaranteed Nyan) -> () {
// %0                                             // user: %4
// %1                                             // user: %2
bb0(%0 : $*Hasher, %1 : $*Nyan):
  %2 = load [trivial] %1 : $*Nyan                 // user: %4
  // function_ref Nyan.hash(into:)
  %3 = function_ref @$S1A4NyanO4hash4intoys6HasherVz_tF : $@convention(method) (@inout Hasher, Nyan) -> () // user: %4
  %4 = apply %3(%0, %2) : $@convention(method) (@inout Hasher, Nyan) -> ()
  %5 = tuple ()                                   // user: %6
  return %5 : $()                                 // id: %6
} // end sil function '$S1A4NyanOSHAASH4hash4intoys6HasherVz_tFTW'

// protocol witness for static Equatable.== infix(_:_:) in conformance Nyan
sil private [transparent] [thunk] @$S1A4NyanOSQAASQ2eeoiySbx_xtFZTW : $@convention(witness_method: Equatable) (@in_guaranteed Nyan, @in_guaranteed Nyan, @thick Nyan.Type) -> Bool {
// %0                                             // user: %3
// %1                                             // user: %4
bb0(%0 : $*Nyan, %1 : $*Nyan, %2 : $@thick Nyan.Type):
  %3 = load [trivial] %0 : $*Nyan                 // user: %7
  %4 = load [trivial] %1 : $*Nyan                 // user: %7
  %5 = metatype $@thin Nyan.Type                  // user: %7
  // function_ref static Nyan.__derived_enum_equals(_:_:)
  %6 = function_ref @$S1A4NyanO21__derived_enum_equalsySbAC_ACtFZ : $@convention(method) (Nyan, Nyan, @thin Nyan.Type) -> Bool // user: %7
  %7 = apply %6(%3, %4, %5) : $@convention(method) (Nyan, Nyan, @thin Nyan.Type) -> Bool // user: %8
  return %7 : $Bool                               // id: %8
} // end sil function '$S1A4NyanOSQAASQ2eeoiySbx_xtFZTW'

sil_witness_table hidden Nyan: Hashable module A {
  base_protocol Equatable: Nyan: Equatable module A
  method #Hashable.hashValue!getter.1: <Self where Self : Hashable> (Self) -> () -> Int : @$S1A4NyanOSHAASH9hashValueSivgTW	// protocol witness for Hashable.hashValue.getter in conformance Nyan
  method #Hashable.hash!1: <Self where Self : Hashable> (Self) -> (inout Hasher) -> () : @$S1A4NyanOSHAASH4hash4intoys6HasherVz_tFTW	// protocol witness for Hashable.hash(into:) in conformance Nyan
}

sil_witness_table hidden Nyan: Equatable module A {
  method #Equatable."=="!1: <Self where Self : Equatable> (Self.Type) -> (Self, Self) -> Bool : @$S1A4NyanOSQAASQ2eeoiySbx_xtFZTW	// protocol witness for static Equatable.== infix(_:_:) in conformance Nyan
}
```

むむ！なにやらたくさんソースがあるぞ！では、随所随所抜粋して、読んで考えていきましょう。
まず、もとの`enum`っぽいソースがありますね。抜粋してみます！

```
enum Nyan : Equatable {
  case hoge
  case fuga
  var hashValue: Int { get }
  func hash(into hasher: inout Hasher)
  @_implements(Equatable, ==(_:_:)) static func __derived_enum_equals(_ a: Nyan, _ b: Nyan) -> Bool
}
```
この中に、今まで実装していた`static func　==　(lhs:rhs:)`と同じと思われる`@_implements(Equatable, ==(_:_:)) static func __derived_enum_equals(_ a: Nyan, _ b: Nyan) -> Bool`がありました。

では、SILをもうちょっと覗いてみます。最後の方に、`Nyan`型の引数を２つとってBoolを返す関数のように見えるコードが見えました！

```
// protocol witness for static Equatable.== infix(_:_:) in conformance Nyan
sil private [transparent] [thunk] @$S1A4NyanOSQAASQ2eeoiySbx_xtFZTW : $@convention(witness_method: Equatable) (@in_guaranteed Nyan, @in_guaranteed Nyan, @thick Nyan.Type) -> Bool {
// %0                                             // user: %3
// %1                                             // user: %4
bb0(%0 : $*Nyan, %1 : $*Nyan, %2 : $@thick Nyan.Type):
  %3 = load [trivial] %0 : $*Nyan                 // user: %7
  %4 = load [trivial] %1 : $*Nyan                 // user: %7
  %5 = metatype $@thin Nyan.Type                  // user: %7
  // function_ref static Nyan.__derived_enum_equals(_:_:)
  %6 = function_ref @$S1A4NyanO21__derived_enum_equalsySbAC_ACtFZ : $@convention(method) (Nyan, Nyan, @thin Nyan.Type) -> Bool // user: %7
  %7 = apply %6(%3, %4, %5) : $@convention(method) (Nyan, Nyan, @thin Nyan.Type) -> Bool // user: %8
  return %7 : $Bool                               // id: %8
} // end sil function '$S1A4NyanOSQAASQ2eeoiySbx_xtFZTW'
```
`// protocol witness for static Equatable.== infix(_:_:) in conformance Nyan`というコメントから、これは`Equatable`の準拠によって生成された`==`のコードだと考えられます。


ここで`__derived_enum_equals`が

```
%6 = function_ref @$S1A4NyanO21__derived_enum_equalsySbAC_ACtFZ : $@convention(method) (Nyan, Nyan, @thin Nyan.Type) -> Bool // user: %7
```
で呼ばれているのがわかりますね。実際に`__derived_enum_equals`のコードと思われる場所を見てみると以下のようになっていることがわかります。

```
// static Nyan.__derived_enum_equals(_:_:)
sil hidden @$S1A4NyanO21__derived_enum_equalsySbAC_ACtFZ : $@convention(method) (Nyan, Nyan, @thin Nyan.Type) -> Bool {
// %0                                             // users: %9, %3
// %1                                             // users: %29, %4
// %2                                             // user: %5
bb0(%0 : $Nyan, %1 : $Nyan, %2 : $@thin Nyan.Type):
  debug_value %0 : $Nyan, let, name "a", argno 1  // id: %3
  debug_value %1 : $Nyan, let, name "b", argno 2  // id: %4
  debug_value %2 : $@thin Nyan.Type, let, name "self", argno 3 // id: %5
  %6 = alloc_box ${ var Int }, var, name "index_a" // user: %7
  %7 = mark_uninitialized [var] %6 : ${ var Int } // users: %56, %8
  %8 = project_box %7 : ${ var Int }, 0           // users: %47, %22, %14
  switch_enum %0 : $Nyan, case #Nyan.hoge!enumelt: bb1, case #Nyan.fuga!enumelt: bb2 // id: %9
```
最後の行を見てみましょう。`switch_enum`で1つめの引数`%0`によって処理を分岐させており、

- `case #Nyan.hoge!enumelt:`(つまり `case hoge`)の場合はラベル`bb1`へ、
- `case #Nyan.fuga!enumelt:`(つまり `case fuga`)の場合はラベル`bb2`へ、

処理を引き継いでいます。`bb1`と`bb2`では、各処理の最後にラベル`bb3`へ飛び、最後に`switch_enum`で2つめの引数`%1`を比較して処理を分岐している事がわかります。

```
bb1:                                              // Preds: bb0
  %10 = metatype $@thin Int.Type                  // user: %13
  %11 = integer_literal $Builtin.Int2048, 0       // user: %13
  // function_ref Int.init(_builtinIntegerLiteral:)
  %12 = function_ref @$SSi22_builtinIntegerLiteralSiBi2048__tcfC : $@convention(method) (Builtin.Int2048, @thin Int.Type) -> Int // user: %13
  %13 = apply %12(%11, %10) : $@convention(method) (Builtin.Int2048, @thin Int.Type) -> Int // user: %15
  %14 = begin_access [modify] [unknown] %8 : $*Int // users: %16, %15
  assign %13 to %14 : $*Int                       // id: %15
  end_access %14 : $*Int                          // id: %16
  br bb3                                          // id: %17

bb2:                                              // Preds: bb0
  %18 = metatype $@thin Int.Type                  // user: %21
  %19 = integer_literal $Builtin.Int2048, 1       // user: %21
  // function_ref Int.init(_builtinIntegerLiteral:)
  %20 = function_ref @$SSi22_builtinIntegerLiteralSiBi2048__tcfC : $@convention(method) (Builtin.Int2048, @thin Int.Type) -> Int // user: %21
  %21 = apply %20(%19, %18) : $@convention(method) (Builtin.Int2048, @thin Int.Type) -> Int // user: %23
  %22 = begin_access [modify] [unknown] %8 : $*Int // users: %24, %23
  assign %21 to %22 : $*Int                       // id: %23
  end_access %22 : $*Int                          // id: %24
  br bb3                                          // id: %25

bb3:                                              // Preds: bb2 bb1
  %26 = alloc_box ${ var Int }, var, name "index_b" // user: %27
  %27 = mark_uninitialized [var] %26 : ${ var Int } // users: %55, %28
  %28 = project_box %27 : ${ var Int }, 0         // users: %50, %42, %34
  switch_enum %1 : $Nyan, case #Nyan.hoge!enumelt: bb4, case #Nyan.fuga!enumelt: bb5 // id: %29
```
これ以降の解説は割愛しますが、これらから私達が以前まで書いていた`switch`による`==`の実装と同様の実装を、コンパイラが生成していると考えられます！

# まとめ
以上のことから以下のことがわかりました！

- Swift4.1では、Equatableの`static public func ==(lhs:rhs:) -> Bool`はコンパイラによって生成されている。
- `enum`の場合、今まで作っていた`switch-case`と同じような比較をコンパイラが生成してくれていると考えられる。

新しい`Equatable`では、従来私達が書いていた`==`による比較をコンパイラが生成してくれていることがわかりました！

これから先、この`Equatable`で私達のコーディングライフがもっと楽しくなればいいですね！

今回のこの機能の実装と解説は[Synthesizing Equatable and Hashable conformance](https://github.com/apple/swift-evolution/blob/master/proposals/0185-synthesize-equatable-hashable.md)で見れますので、チェックしてみるのも良いかもしれません！

間違い等があれば、コメントをよろしくおねがいします！