関数の宣言まわりで地雷踏んでUnityのmonoでInternalCompilerErrorが出てしまったのを解決した話
問題
以下の様なコードをUnityのmonoでコンパイルしたらInternalCompilerErrorを出してしまった。
コード
public class Bomb { public void Explosion(float radius = 10f){} public void Explosion(Vector3 worldPos, float radius = 10f){} } public class BomberMan { public void ExecuteExplosion() { var bomb = new Bomb(); bomb.Explosion(radius: 100f); } }
InternalCompilerErrorの一部
Internal compiler error. See the console log for more information. output ----- UnityEngine.dllとかで握りつぶされてた大量のwarningが書かれてた ----- Unhandled Exception: Mono.CSharp.InternalErrorException: VerifyArgumentsCompat didn't find any problem with rejected candidate MethodBuilder [{エラーが出てる関数名}] at Mono.CSharp.MethodGroupExpr.OverloadResolve (Mono.CSharp.ResolveContext ec, Mono.CSharp.Arguments& Arguments, Boolean may_fail, Location loc) [0x00000] in <filename unknown>:0 at Mono.CSharp.Invocation.DoResolveOverload (Mono.CSharp.ResolveContext ec) [0x00000] in <filename unknown>:0 at Mono.CSharp.Invocation.DoResolve (Mono.CSharp.ResolveContext ec) [0x00000] in <filename unknown>:0 at Mono.CSharp.Expression.Resolve (Mono.CSharp.ResolveContext ec, ResolveFlags flags) [0x00000] in <filename unknown>:0 at Mono.CSharp.Expression.Resolve (Mono.CSharp.ResolveContext ec) [0x00000] in <filename unknown>:0 at Mono.CSharp.Argument.Resolve (Mono.CSharp.ResolveContext ec) [0x00000] in <filename unknown>:0 at Mono.CSharp.Arguments.Resolve (Mono.CSharp.ResolveContext ec, System.Boolean& dynamic) [0x00000] in <filename unknown>:0 at Mono.CSharp.Invocation.DoResolve (Mono.CSharp.ResolveContext ec) [0x00000] in <filename unknown>:0 at Mono.CSharp.Expression.Resolve (Mono.CSharp.ResolveContext ec, ResolveFlags flags) [0x00000] in <filename unknown>:0 at Mono.CSharp.Expression.Resolve (Mono.CSharp.ResolveContext ec) [0x00000] in <filename unknown>:0 at Mono.CSharp.ExpressionStatement.ResolveStatement (Mono.CSharp.BlockContext ec) [0x00000] in <filename unknown>:0 at Mono.CSharp.StatementExpression.Resolve (Mono.CSharp.BlockContext ec) [0x00000] in <filename unknown>:0 at Mono.CSharp.Block.Resolve (Mono.CSharp.BlockContext ec) [0x00000] in <filename unknown>:0 at Mono.CSharp.ToplevelBlock.Resolve (Mono.CSharp.FlowBranching parent, Mono.CSharp.BlockContext rc, Mono.CSharp.ParametersCompiled ip, IMethodData md) [0x00000] in <filename unknown>:0
原因
以下の条件が重なるとダメっぽい
- 引数をOptionalにしてる
- ex.
float radius = 10f
- オーバーロードした関数が元の関数と引数の順番が違う
- 今回の場合はオーバーロードする時に『第一引数の
worldPos
をOptionalにしたくない』という理由で引数の順番を変えてしまっていた様子- (前の引数がOptinalだった場合には以降の引数もOptinoalにしないとコンパイルエラーになるので)
- 呼び出し側が引数のパラメータ名付きで引数を送ってる
- ex.
bomb.Explosion(radius: 100f);
- ex.
解決方法
以下のどれかの方法を取れば解決する
BomberMan.ExecuteExplosion()
でbomb.Explosion()
の引数指定にパラメータ名を添えるのをやめるBomb.Explosion
の引数であるradius
をOptionalにしない
public class Bomb { // `Bomb.Explosion`の引数である`radius`をOptionalにしない public void Explosion(float radius){} public void Explosion(Vector3 worldPos, float radius){} } public class BomberMan { public void ExecuteExplosion() { var bomb = new Bomb(); // `BomberMan.ExecuteExplosion()`で`bomb.Explosion()`の引数指定にパラメータ名を添えるのをやめる bomb.Explosion(100); } }
追加情報
@shogo82148 が調べてくれてた
monoのrepositoryでは、既に修正が入ってるっぽい https://github.com/mono/mono/commit/7ad366c25a7fc180a57dcf88f28064ec3db619b6
でも、Unityの中のmonoにはこの修正はまだ取り込まれていない様だった https://github.com/Unity-Technologies/mono/blob/unity-staging/mcs/mcs/ecore.cs#L3794
StackOverFlowだとここら辺の情報が今回の件に該当しそう http://stackoverflow.com/questions/4495108/mono-named-optional-parameters-compiler-bug