Skip to content

F# System.TypeLoadException : The generic type 'System.Tuple`2' was used with an invalid instantiation in assembly #558

Closed
@buybackoff

Description

@buybackoff

In this SO question the minimum example of a bug in Debug mode.

This code works perfectly in Release mode, but throws in Debug mode with:

System.TypeLoadException : The generic type 'System.Tuple`2' was used with an invalid instantiation in assembly 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.

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 ILSpy output 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");
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions