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.

+3


source to share


1 answer


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.

+1


source







All Articles