TypeLoadException when accessing CustomAttributeData.ConstructorArguments in fsi
Repro steps
Simple reproduction, in dotnet fsi with multiemit on (as by default)
// run this in one prompt:
type MyCustomLogic() =
member this.DoSomething() = ()
type MyAnnotation(typ: System.Type) =
inherit System.Attribute()
// run this in another prompt:
[<MyAnnotation(typeof<MyCustomLogic>)>]
let getValue() = 42
match <@ getValue() @> with
| FSharp.Quotations.Patterns.Call(_, methodInfo, _) ->
methodInfo.GetCustomAttributesData()
|> Seq.iter (fun a -> a.ConstructorArguments |> Seq.iter (printfn "%A")) // fails with System.TypeLoadException
| _ -> ()
Expected behavior
If the referenced type and the attribute usage is in the same prompt, then there is no error. IL generation should correctly recognize which transient assembly a type referenced via typeof used for an attribute constructor is defined in.
Actual behavior
Error is like System.TypeLoadException: Could not resolve type 'FSI_0003+MyCustomLogic' in assembly 'FSI-ASSEMBLY, Version=0.0.0.32763, Culture=neutral, PublicKeyToken=null'.
This shows that the MyCustomLogic type is tried to be resolved from the transient assembly where the attribute is used, not where it is properly defined.
Known workarounds
Using --multiemit- argument for starting fsi.
Related information
Tested on dotnet SDKs 9.0.305 and 10.0.100-rc.1.25451.107 on Windows 11, both within and outside of Visual Studio.
I assume the issue is that each submission is a new assembly emitted (hence the version bump you see).
Not entirely sure what will the fix be.
Yes, the problem is the version mismatch between two transient assemblies. The type reference on the attribute is created pointing to the current one, even though it should be the earlier one where the referenced type is actually defined.