F # System.TypeLoadException: generic type 'System.Tuple`3' was used with an invalid instance in an assembly
I have a very strange error in mode Debug
in F # assembly and this error disappears in mode Release
. I've tried .NET 4.0, 4.5, 4.6, I've also tried on a machine that doesn't have VS2015 and .NET 4.6. I also tried F # 3.1 and 4.0.
System.TypeLoadException: Generic type 'System.Tuple`3' was used with invalid instance in assembly 'mscorlib, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089'.
or (the only difference is Tuple'2 or '3)
System.TypeLoadException: Generic type 'System.Tuple`2' was used with invalid instance in assembly 'mscorlib, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089'.
I am developing in release mode a special flag Prerelease
for conditional compilation - to be able to run meaningful benchmarks Release
on every change (the flag is set in both Debug and Release). So my place is not where used #if DEBUG...
and I double checked this.
What does this error mean? Do you have an idea where to look for a fix? I have no idea and still cannot pursue the place where he is actually abandoned. The stack trace is not useful as it shows the top calling method.
In my build release, I have a warning that I've never seen before, but it appears both in Debug
and out Release
and probably doesn't matter.
FSC: Warning FS3186: An error occurred while reading the metadata F # node at position 3223 in the collectors table of assembly 'Spreads.Collections, Version = 0.0.31.0, Culture = neutral, PublicKeyToken = null. node has no corresponding declaration. please report this warning. You may need to recompile the F # assembly you are in using.
source to share
Here is a minimal example that reproduces the problem.
open System
open System.Collections.Generic
open System.Runtime.InteropServices
module Test =
type MyType<'A,'B,'C>() =
let mutable counter = 0
member this.Counter with get() = counter and set(v) = counter <- v
member inline this.TryDoWorkChecked(next:KeyValuePair<'A,'B>, [<Out>] value: byref<'C>) : bool =
let before = this.Counter
let res = this.TryDoWork(next, &value)
if before <> this.Counter then raise (InvalidOperationException("Must not change counter during work"))
else res
abstract TryDoWork: next:KeyValuePair<'A,'B> * [<Out>] value: byref<'C> -> bool
override this.TryDoWork(next:KeyValuePair<'A,'B>, [<Out>] value: byref<'C>) : bool =
value <- Unchecked.defaultof<'C>
if counter > 10 then true else false
member this.DoWork(next:KeyValuePair<'A,'B>) =
let mutable value = Unchecked.defaultof<'C>
while not (this.TryDoWorkChecked(next, &value)) do
counter <- counter + 1
open Test
[<EntryPoint>]
let main argv =
let myType = MyType<int,int,int>()
let next = Unchecked.defaultof<KeyValuePair<int,int>>
myType.DoWork(next)
Console.ReadLine() |> ignore
0
In debug mode, ILSpy shows this:
// Program.Test.MyType<A, B, C>
public unsafe void DoWork(KeyValuePair<A, B> next)
{
C value = default(C);
while (true)
{
Tuple<KeyValuePair<A, B>, C*> tuple = new Tuple<KeyValuePair<A, B>, C*>(next, ref value);
KeyValuePair<A, B> item = tuple.Item1;
C* item2 = tuple.Item2;
int num = this.Counter;
bool flag = this.TryDoWork(item, item2);
if ((num == this.Counter) ? flag : Operators.Raise<bool>(new InvalidOperationException("Must not change counter during work")))
{
break;
}
this.counter++;
}
}
And this is the output of ILSpy in Release mode:
// Program.Test.MyType<A, B, C>
public void DoWork(KeyValuePair<A, B> next)
{
C value = default(C);
while (true)
{
int num = this.counter;
bool flag = this.TryDoWork(next, out value);
if (num != this.counter)
{
break;
}
if (flag)
{
return;
}
this.counter++;
}
throw new InvalidOperationException("Must not change counter during work");
}
I believe this is a bug in the F # compiler.
source to share