dotnet / dotnet/fsharp

Runtime MethodAccessException due to incorrect visibility propagation

Open
#11,604 1 comment 0 reactions 1 assignee Claimed by @dsyme View on GitHub
Area-Compiler-Checking Area-Compiler-Checking-Accessibility Area-Compiler-CodeGen Bug Impact-Medium
Dominant language
F#
Stars
4.3k
Forks
876
Avg merge
4d 11h
Merged PRs (30d)
131

Description

Runtime MethodAccessException due to incorrect visibility propagation

First assembly in C#, as this does not quite reproduce identically in F#.
```cs
namespace Repro
{
public interface IRequest { }

public class Sender
{
public TResponse Send() where TRequest : IRequest
{
return default;
}
}

internal class Private { }
public class Public { }

public class Request : IRequest, IRequest
{

}
}
```

Second assembly:
```fs
open Repro

let response = Sender().Send()
```

First off `TResponse` is `IRequest` and compiles without error while part of its instantiation is internal to another assembly. Secondly regardless of any explicit specified type argument for `TResponse` it won't be respected. The compiler always picks the first interface implementation matching the open constraint. This seems like an 'interface implemented at multiple instantiations' and type inference interaction bug, as specific instantiations should be selectable.

Something I've noticed when trying to reproduce this in F# entirely is that the order of interfaces seems reversed from C# so even though C# has Private first, to get a similar issue to surface in F# it has to be defined second, this points to an observable non-obvious codegen difference.

F# version
```fs
namespace Repro

type IRequest<'response> = interface end

type Sender() =
member _.Send<'a, 'b when 'a :> IRequest<'b>>() = Unchecked.defaultof<'b>

type internal Private = class end
type Public = class end

type Request() =
// Reversed order required to select Private
interface IRequest
interface IRequest
```

Testing this F# version gives a late compiler error that Private is less visible than the type it's used in. Though better, there is room for improvement as the interface implementation could have been eliminated as not viable much earlier in the constraint solving process. Never surfacing an error if another valid match exists.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.