【Solidity】Stack too deep で 変数は消さなくていい

##エラーの要因
**Solidity** で変数を使いすぎると、下記の **"Stack too deep"** エラーが発生します。

> CompilerError: Stack too deep, try removing local variables.

このエラーは、同時に利用される変数が一定を超えると発生します。

<details><summary>エラーサンプル（クリックで開閉します）</summary><div>

```solidity:関数内の変数は１６個でエラー
function testA() public pure{
    uint a =  1;
    uint b =  2;
    uint c =  3;
    uint d =  4;
    uint e =  5;
    uint f =  6;
    uint g =  7;
    uint h =  8;
    uint i =  9;
    uint j = 10;
    uint k = 11;
    uint l = 12;
    uint m = 13;
    uint n = 14;
    uint o = 15;
    uint p = 16;  // ここで "Stack too deep"

    a += b;
    a += c;
    a += d;
    a += e;
    a += f;
    a += g;
    a += h;
    a += i;
    a += j;
    a += k;
    a += l;
    a += m;
    a += n;
    a += o;
    a += p;
}
```
</div></details>

エラー文言から、「利用している変数を消さないといけない」という印象を受けますが、そんなことはありません。エラー回避のために押さえておきたいポイントが「同時に利用される変数」という点です。

###ポイント.１
変数としてカウントされるのは、関数内で宣言した変数は当然ですが、引数や、返値もカウントされます。

<details><summary>引数によるエラーサンプル（クリックで開閉します）</summary><div>

```solidity:引数を増やせば利用可能な変数は減る
function testB( uint v, uint w, uint x, uint y, uint z ) public pure{
    uint a =  1;
    uint b =  2;
    uint c =  3;
    uint d =  4;
    uint e =  5;
    uint f =  6;
    uint g =  7;
    uint h =  8;
    uint i =  9;
    uint j = 10;
    uint k = 11;
    uint l = 12;  // ここで "Stack too deep"

    a += v;
    a += w;
    a += x;
    a += y;
    a += z;

    a += b;
    a += c;
    a += d;
    a += e;
    a += f;
    a += g;
    a += h;
    a += i;
    a += j;
    a += k;
    a += l;
}
```
</div></details>

<details><summary>返値によるエラーサンプル（クリックで開閉します）</summary><div>

```solidity:返値をふやしても利用可能な変数は減る
function testC() public pure returns (uint, uint, uint, uint, uint){
    uint a =  1;
    uint b =  2;
    uint c =  3;
    uint d =  4;
    uint e =  5;
    uint f =  6;
    uint g =  7;
    uint h =  8;
    uint i =  9;
    uint j = 10;
    uint k = 11;
    uint l = 12;  // ここで "Stack too deep"

    a += b;
    a += c;
    a += d;
    a += e;
    a += f;
    a += g;
    a += h;
    a += i;
    a += j;
    a += k;
    a += l;

    return( a, b, c, d, e );
}
```
</div></details>

これは、引数や返値が増えるほど、**"Stack too deep"** エラーが起こりやすくなることを意味します。

###ポイント.２

下記のコードにおいて、変数 **i** や **temp** は **for** ブロック内でのみ存在します。

```solidity
for( uint i=0; i<10; i++ ){
	uint temp = i * i;
	// 何かしらの処理
}
```

これは、ブロック内で宣言された変数は、ブロック外では数にカウントされないことを意味します。

##ブロックによる回避
利用が局所的な変数であれば、**{ }** で囲んでブロック内に閉じ込めることで、関数全体で「同時に利用する変数」の数を減らすことができます。

<details><summary>回避策サンプル（クリックで開閉します）</summary><div>

```solidity:ブロックで回避しているのでエラーは出ない
function testD( uint aa, uint bb, uint cc, uint dd, uint ee ) public pure returns ( uint, uint, uint, uint, uint ){
    uint a =  1;

    {
        uint b =  2;
        a += b;
    }

    {
        uint c =  3;
        a += c;
    }

    {
        uint d =  4;
        a += d;
    }

    {
        uint e =  5;
        a += e;
    }

    {
        uint f =  6;
        a += f;
    }

    {
        uint g =  7;
        a += g;
    }

    {
        uint h =  8;
        a += h;
    }

    {
        uint i =  9;
        a += i;
    }

    {
        uint j = 10;
        a += j;
    }

    {
        uint k = 11;
        a += k;
    }

    {
        uint l = 12;
        a += l;
    }

    {
        uint m = 13;
        a += m;            
    }

    {
        uint n = 14;
        a += n;
    }

    {
        uint o = 15;
        a += o;
    }

    {
        uint p = 16;
        a += p;
    }

    {
        uint q = 17;
        a += q;
    }

    {
        uint r = 18;
        a += r;
    }

    {
        uint s = 19;
        a += s;
    }

    {
        uint t = 20;
        a += t;
    }

    {
        uint u = 21;
        a += u;
    }

    {
        uint v = 22;
        a += v;
    }

    {
        uint w = 23;
        a += w;
    }

    {
        uint x = 24;
        a += x;
    }

    {
        uint y = 25;
        a += y;
    }

    {
        uint z = 26;
        a += z;
    }

    a += aa;
    a += bb;
    a += cc;
    a += dd;
    a += ee;
    return( a, a, a, a, a );
}
```
</div></details>

**"Stack too deep"** エラーが出た際は、局所的な変数を探してブロックに閉じ込めてしまいましょう。

##補足
**"Stack too deep"** エラーは型による影響はうけません。

例えば、**uint(256bit)** の変数を、より小さい **uint8(8bit)** に変更しても、同じようにエラーとなります。

<details><summary>エラーサンプル（クリックで開閉します）</summary><div>

```solidity:uint8にしても１６個でエラー
function testE() public pure{
    uint8 a =  1;
    uint8 b =  2;
    uint8 c =  3;
    uint8 d =  4;
    uint8 e =  5;
    uint8 f =  6;
    uint8 g =  7;
    uint8 h =  8;
    uint8 i =  9;
    uint8 j = 10;
    uint8 k = 11;
    uint8 l = 12;
    uint8 m = 13;
    uint8 n = 14;
    uint8 o = 15;
    uint8 p = 16;  // ここで "Stack too deep"

    a += b;
    a += c;
    a += d;
    a += e;
    a += f;
    a += g;
    a += h;
    a += i;
    a += j;
    a += k;
    a += l;
    a += m;
    a += n;
    a += o;
    a += p;
}
```
</div></details>