Boo.Lang exception in my WP8.1 project

Here I met a new strange issue, it reported the error from Boo.Lang.DLL, but I’ve never used any *.boo. The code is about HashTable, so I guess it didn’t find any hashtable classes, so use the existing one from Boo.Lang??

Exception: System.Boolean System.Type::IsInstanceOfType(System.Object) called in c:\buildslave\mono-runtime-and-classlibs\build\external\boo\src\Boo.Lang\Runtime\RuntimeServices.cs (243, 4).
Type: System.MissingMemberException
Module: Boo.Lang
InnerException:
AdditionalInfo:
at UnsupportedMember_Boolean(Type self, Object o, String signature)

I’ve import WinRTLegacy, but why it didn’t use it?

Hi, it looks like it hit a path in Boo.Lang.dll that we anticipated that it would never hit. The exception looks confusing though - do you have a stack trace? From a quick look at it, it looks like you tried inserting an object of non-matching type to a collection.

This is expected - you probably used UnityScript. UnityScript both compiler and runtime is written in Boo, so it heavily relies on its services.

Either way, a bug report with a repro would be nice so we could fix it.

UnityScript is built on top of Boo, so if you use UnityScript, it’ll pull Boo in as well.
It looks like a bug, can you report it?
Thanks.

Even I changed the declaration type from HashTable into System.Collections.HashTable, when I debug it in VS2013, it still showed the variable is Boo.Lang.Hash.
I am trying to make a small size project to repo it, since the original project is too huge to send.
It blocked me 3 days to move on, nearly crazy.

What’s the stacktrace? Did you try using System.Collections.Generic.Dictionary? That should definitely not pull any Boo dependencies.

Boo.Lang.DLL!.UnsupportedMember_Boolean(System.Type self, object o, string signature) 未知
Boo.Lang.DLL!Boo.Lang.Runtime.RuntimeServices.CreateCoerceDispatcher(object value, System.Type toType) 未知
Boo.Lang.DLL!Boo.Lang.Runtime.RuntimeServices.Coerce.AnonymousMethod__16() 未知
Boo.Lang.DLL!Boo.Lang.Runtime.DynamicDispatching.DispatcherCache.Get(Boo.Lang.Runtime.DynamicDispatching.DispatcherKey key, Boo.Lang.Runtime.DynamicDispatching.DispatcherCache.DispatcherFactory factory) 未知
Boo.Lang.DLL!Boo.Lang.Runtime.RuntimeServices.GetDispatcher(object target, string cacheKeyName, System.Type[ ] cacheKeyTypes, Boo.Lang.Runtime.DynamicDispatching.DispatcherCache.DispatcherFactory factory) 未知
Boo.Lang.DLL!Boo.Lang.Runtime.RuntimeServices.Coerce(object value, System.Type toType) 未知
> Assembly-UnityScript.DLL!FTEBaseVO.getList(string key) 行 71 未知
Assembly-UnityScript.DLL!StepVO.mergeDataFrom(object src) 行 57 未知
Assembly-UnityScript.DLL!FTEDialog.loadStep(int step) 行 51 未知
Assembly-UnityScript.DLL!FTEMgrImpl.loadStep(int step) 行 440 未知
Assembly-UnityScript.DLL!FTEMgrImpl.startFTE() 行 139 未知
Assembly-UnityScript.DLL!GameMain.fte_startFTE() 行 1006 未知
Assembly-UnityScript.DLL!GameMain.$onLevelLoaded$4499.$.MoveNext() 行 483 未知
UnityEngine.DLL!UnityEngine.Internal.$MethodUtility.$Invoke66(long instance, long* args) 未知
UnityEngine.DLL!UnityEngine.Internal.$MethodUtility.InvokeMethod(long instance, long* args, System.IntPtr method) 未知

Above are the call stacks.
Does the System.Collections.Generic.Dictionary can be fully replaced the HashTable?

Almost. There are minor differences, but they should mostly be compatible. Dictionary should work a little bit faster, since it is not thread safe. It will also offer type safety, as it is a generic class.

The original project used toooo many HashTables, is there a quick way to modify them?

I found it’s a huge project to replace the hashtable…
Do I have a chance to make the unityscript using the hashtable from WinRTLegacy but not boo.lang???

It’s not using hash table from Boo.Lang.dll - the stack trace tells a different story. UnityScript compiler generates a call to Boo.Lang.Runtime.RuntimeServices.Coerce. Unfortunately, it’s pretty hard to know what it is doing without seeing the source code. The offending call seems to be at FTEBaseVO.getList(string key) line 71. What is it doing on that line?

Below is the getList(string key)'s body, and error was on the statement in red.
public function getList(key:String):Array
{
var srcList:Array = rawData[key];
var destList:Array=null;
if(srcList)
{
var itemVO:FTEBaseVO;
destList = [ ];
for(var i:int = 0; i<srcList.length; i++)
{
itemVO = itemVOCreater(key);
if(!itemVO)
continue;
itemVO.mergeDataFrom(srcList*);*
destList.push(itemVO);
}
}
return destList;
}

note: rawData is the HashTable.

So it looks like the accessor is “[ ]” not supported?

Ok, that was helpful.

When the compiled UnityScript is translated to C#, it looks like this:

Array srcList;
object tempArg = this.rawData.get_Item(key);
if (!(tempArg is Array))
{
    srcList = (Array)Boo.Lang.Runtime.RuntimeServices.Coerce(tempArg, typeof(Array));
}
else
{
    srcList = (Array)tempArg;
}

// ... rest of the code

Basically, it takes that path when the thing you store in rawData with the specified key is not an array. This should help you narrow down the issue.

An additional note: there is a distinction between System.Array and UnityScript.Lang.Array. If you add items to the hashtable from C#, items in the array will be of type System.Array, and thus would cause this issue as well.

If this is the case, you could declare srcList as System.Array, rather than Array.

And I’ve been able to reproduce it locally. Thanks! I’ll make sure to file a bug report.

C#:

using UnityEngine;
using System.Collections;

public class ArrayProvider
{
   public static int[] GetArray()
   {
     return new int[] { 1, 2, 3 };
   }
}

UnityScript:

#pragma strict

var rawData:System.Collections.Hashtable;

function getList(key:String):Array
{
   return rawData[key];
}

function Start()
{
   rawData = new System.Collections.Hashtable();
   rawData.Add("a", ArrayProvider.GetArray());
   UnityEngine.Debug.Log(getList("a"));
}

Thanks, so what I have to do is convert the js Array to C# Array? I remember there is a way on
http://docs.unity3d.com/ScriptReference/Array.html
is it?

There’s method “ToBuiltin” on UnityScript.Lang.Array.

The “System.MissingMemberException” happened again, but this time the value is indeed Array type.

Exception: System.Boolean System.Type::IsInstanceOfType(System.Object) called in c:\buildslave\mono-runtime-and-classlibs\build\external\boo\src\Boo.Lang\Runtime\RuntimeServices.cs (243, 4).
Type: System.MissingMemberException
Module: Boo.Lang
InnerException:
AdditionalInfo:
at UnsupportedMember_Boolean(Type self, Object o, String signature)
at Boo.Lang.Runtime.RuntimeServices.CreateCoerceDispatcher(Object value, Type toType)
at Boo.Lang.Runtime.RuntimeServices.<>c__DisplayClass17.b__16()
at Boo.Lang.Runtime.DynamicDispatching.DispatcherCache.Get(DispatcherKey key, DispatcherFactory factory)
at Boo.Lang.Runtime.RuntimeServices.GetDispatcher(Object target, String cacheKeyName, Type[ ] cacheKeyTypes, DispatcherFactory factory)
at Boo.Lang.Runtime.RuntimeServices.Coerce(Object value, Type toType)
at Building.getCreatBuildingList(Int32 cityId, Int32 slotId)
at CreatBuilding.UpdateData(Object param)
at CreatBuilding.OnPush(Object param)
at MenuMgr.$PushMenu$4576.$.MoveNext()
at UnityEngine.Internal.$MethodUtility.$Invoke66(Int64 instance, Int64* args)
at UnityEngine.Internal.$MethodUtility.InvokeMethod(Int64 instance, Int64* args, IntPtr method)

and the related source are:
var cityBuildListOrder:Array = [[5,13,11,7,9,12,8,15,16,14,17,18,20],[5,13,11,7,9,12,8,15,16,14,17,18],[5,13,11,7,9,12,8,15,16,14,17,18],[5,13,11,7,9,12,8,15,16,14,17,18]];
var curList:Array;
curList = cityBuildListOrder[0];

Don’t know what did the Boo.Lang.Runtime.RuntimeServices.Coerce do this time.

The missing member exception will be fixed in the tomorrow’s patch release.

What happens if you change the type of curList to int[ ]?

Solved, after change to int[ ], so what I understand is the Boo.Lang.XXX cannot exactly parse the real type?