dotnet / fsharp

The F# compiler, F# core library, F# language service, and F# tooling integration for Visual Studio
https://dotnet.microsoft.com/languages/fsharp
MIT License
3.92k stars 785 forks source link

MethodAccessException on equality comparison of a record with private fields #17447

Closed iminashi closed 3 months ago

iminashi commented 3 months ago

Equality comparison of a record type with private fields no longer works in SDK 8.0.400 for a type that is in a different assembly.

Repro steps

Assembly A:

Record type with private fields.

module Types

type Value =
    private { value: uint32 }

    static member Zero = { value = 0u }
    static member Create(value: int) = { value = uint value }

Assembly B:

Anything that uses the = operator on the type.

module Test

open NUnit.Framework
open Types

[<Test>]
let Equality () =
    let zero = Value.Create 0

    Assert.That(Value.Zero = zero, "zero equals zero")

Expected behavior

Equality comparison works.

Actual behavior

Runtime exception:

System.MethodAccessException : Attempt by method 'Test.Equality()' to access method 'Types+Value.Equals(Value, System.Collections.IEqualityComparer)' failed.

Known workarounds

Related information

vzarytovskii commented 3 months ago

Likely caused by https://github.com/dotnet/fsharp/pull/16857 (or by realsig, or by mixture of both)

vzarytovskii commented 3 months ago

Method is generated as internal for some reason:

image
vzarytovskii commented 3 months ago

@iminashi I suppose itermediate workaroud would be to add IVT attribute to the first assembly (the one which test is using), until we implement a fix.

psfinaki commented 3 months ago

Yes, the above helps (putting InternalsVisibleTo).

iminashi commented 3 months ago

I was just trying out the VS preview version (to see if it had the fix for #17161) when I ran into this, so this does not really affect me that much for now.

psfinaki commented 3 months ago

Note, --realsig+ also seems to fix the issue.

OkkeHendriks commented 2 months ago

Hello (@KevinRansom), will this be released for .NET 8.0.x? We, automatically, installed 8.0.400 through windows update on our build servers.

Projects which did not pin the SDK (or allowed feature updates by using "rollForward": "latestFeature" in their global.json) crash, at runtime, on production, if they happen to have an equality comparison in a untested code path.

It seems to me that this should be a major issue for many users? Or are we doing something out of the ordinary here?