Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions src/Compiler/AbstractIL/ilwrite.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1151,8 +1151,11 @@ let canGenMethodDef (tdef: ILTypeDef) cenv (mdef: ILMethodDef) =
match mdef.Access with
| ILMemberAccess.Public -> true
// When emitting a reference assembly, do not emit methods that are private/protected/internal unless they are virtual/abstract or provide an explicit interface implementation.
// REVIEW: Addded(vlza, fixes #14937):
// We also emit methods that are marked as HideBySig and static,
// since they're not virtual or abstract, but we want (?) the same behaviour as normal instance implementations.
| ILMemberAccess.Private | ILMemberAccess.Family | ILMemberAccess.Assembly | ILMemberAccess.FamilyOrAssembly
when mdef.IsVirtual || mdef.IsAbstract || mdef.IsNewSlot || mdef.IsFinal || mdef.IsEntryPoint -> true
when (mdef.IsHideBySig && mdef.IsStatic) || mdef.IsVirtual || mdef.IsAbstract || mdef.IsNewSlot || mdef.IsFinal || mdef.IsEntryPoint -> true
// When emitting a reference assembly, only generate internal methods if the assembly contains a System.Runtime.CompilerServices.InternalsVisibleToAttribute.
| ILMemberAccess.FamilyOrAssembly | ILMemberAccess.Assembly
when cenv.hasInternalsVisibleToAttrib -> true
Expand Down Expand Up @@ -2678,7 +2681,7 @@ let GenMethodImplPass3 cenv env _tgparams tidx mimpl =
let midx2Tag, midx2Row = GetOverridesSpecAsMethodDefOrRef cenv env mimpl.Overrides
AddUnsharedRow cenv TableNames.MethodImpl
(UnsharedRow
[| SimpleIndex (TableNames.TypeDef, tidx)
[| SimpleIndex (TableNames.TypeDef, tidx)
MethodDefOrRef (midxTag, midxRow)
MethodDefOrRef (midx2Tag, midx2Row) |]) |> ignore

Expand Down
136 changes: 136 additions & 0 deletions tests/fsharp/Compiler/CodeGen/EmittedIL/ReferenceAssemblyTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1404,5 +1404,141 @@ Console.WriteLine("Hello World!")"""
"""
]
|> ignore
#if NETCOREAPP
[<Test>]
#endif
let ``Refassembly_emits_static_abstracts_implementations_the_same_way_it_does_for_instance_with_empty_signature`` () =

let signature = """namespace Foobar
type IHasStaticAbstractBase<'a> =
static abstract BoomStatic: unit -> 'a
abstract BoomInstance: unit -> 'a

type CompilerGoesBoom<'a> =
interface IHasStaticAbstractBase<'a>
new: unit -> CompilerGoesBoom<'a>"""

let implementation = """namespace Foobar
type IHasStaticAbstractBase<'a> =
abstract BoomInstance: unit -> 'a
static abstract BoomStatic: unit -> 'a

type CompilerGoesBoom<'a>() =
interface IHasStaticAbstractBase<'a> with
member (*virtual*) this.BoomInstance() = Unchecked.defaultof<'a>
static member (*non-virtual*) BoomStatic() = Unchecked.defaultof<'a>
"""

Fsi signature
|> withAdditionalSourceFile (FsSource implementation)
|> withOptions [ "--refonly" ]
|> ignoreWarnings
|> compile
|> shouldSucceed
|> verifyIL
[
referenceAssemblyAttributeExpectedIL
""".class interface public abstract auto ansi serializable beforefieldinit Foobar.IHasStaticAbstractBase`1<a>
{
.custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 03 00 00 00 00 00 )
.method public hidebysig abstract virtual
instance !a BoomInstance() cil managed
{
}

.method public hidebysig static abstract virtual
!a BoomStatic() cil managed
{
}

}"""
""".method private hidebysig newslot virtual
instance !a 'Foobar.IHasStaticAbstractBase<\'a>.BoomInstance'() cil managed
{
.override method instance !0 class Foobar.IHasStaticAbstractBase`1<!a>::BoomInstance()

.maxstack 8
IL_0000: ldnull
IL_0001: throw
}

.method assembly hidebysig static !a 'Foobar.IHasStaticAbstractBase<\'a>.BoomStatic'() cil managed
{
.override method !0 class Foobar.IHasStaticAbstractBase`1<!a>::BoomStatic()

.maxstack 8
IL_0000: ldnull
IL_0001: throw
}"""
]


#if NETCOREAPP
[<Test>]
#endif
let ``Refassembly_emits_static_abstracts_implementations_the_same_way_it_does_for_instance_with_signature`` () =
let signature = """namespace Foobar
type IHasStaticAbstractBase<'a> =
static abstract BoomStatic: unit -> 'a
abstract BoomInstance: unit -> 'a

type CompilerGoesBoom<'a> =
interface IHasStaticAbstractBase<'a>
new: unit -> CompilerGoesBoom<'a>"""

let implementation = """namespace Foobar
type IHasStaticAbstractBase<'a> =
abstract BoomInstance: unit -> 'a
static abstract BoomStatic: unit -> 'a

type CompilerGoesBoom<'a>() =
interface IHasStaticAbstractBase<'a> with
member (*virtual*) this.BoomInstance() = Unchecked.defaultof<'a>
static member (*non-virtual*) BoomStatic() = Unchecked.defaultof<'a>
"""

Fsi signature
|> withAdditionalSourceFile (FsSource implementation)
|> withOptions ["--refonly"]
|> ignoreWarnings
|> compile
|> shouldSucceed
|> verifyIL
[
referenceAssemblyAttributeExpectedIL
""".class interface public abstract auto ansi serializable beforefieldinit Foobar.IHasStaticAbstractBase`1<a>
{
.custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 03 00 00 00 00 00 )
.method public hidebysig abstract virtual
instance !a BoomInstance() cil managed
{
}

.method public hidebysig static abstract virtual
!a BoomStatic() cil managed
{
}

}"""
""".method private hidebysig newslot virtual
instance !a 'Foobar.IHasStaticAbstractBase<\'a>.BoomInstance'() cil managed
{
.override method instance !0 class Foobar.IHasStaticAbstractBase`1<!a>::BoomInstance()

.maxstack 8
IL_0000: ldnull
IL_0001: throw
}

.method assembly hidebysig static !a 'Foobar.IHasStaticAbstractBase<\'a>.BoomStatic'() cil managed
{
.override method !0 class Foobar.IHasStaticAbstractBase`1<!a>::BoomStatic()

.maxstack 8
IL_0000: ldnull
IL_0001: throw
}"""
]


// TODO: Add tests for internal functions, types, interfaces, abstract types (with and without IVTs), (private, internal, public) fields, properties (+ different visibility for getters and setters), events.