diff --git a/src/InlineIL.Tests.Common/ReferencedAssemblyType.cs b/src/InlineIL.Tests.Common/ReferencedAssemblyType.cs index b58d8e7..4555c96 100644 --- a/src/InlineIL.Tests.Common/ReferencedAssemblyType.cs +++ b/src/InlineIL.Tests.Common/ReferencedAssemblyType.cs @@ -4,6 +4,7 @@ public unsafe class TypeFromReferencedAssembly { public readonly StructFromReferencedAssembly FieldWithTypeFromThisAssembly = default; public readonly StructFromReferencedAssembly* PointerField = default; + public readonly TypeFromReferencedAssembly GenericTypeField = new(); } public unsafe class TypeFromReferencedAssembly diff --git a/src/InlineIL.Tests.UnverifiableAssemblyToProcess/FieldRefTestCases.cs b/src/InlineIL.Tests.UnverifiableAssemblyToProcess/FieldRefTestCases.cs index 84ae7ba..63b74e6 100644 --- a/src/InlineIL.Tests.UnverifiableAssemblyToProcess/FieldRefTestCases.cs +++ b/src/InlineIL.Tests.UnverifiableAssemblyToProcess/FieldRefTestCases.cs @@ -1,5 +1,6 @@ using System; using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; using InlineIL.Tests.Common; using static InlineIL.IL.Emit; @@ -9,7 +10,7 @@ namespace InlineIL.Tests.UnverifiableAssemblyToProcess; [SuppressMessage("ReSharper", "UnusedMember.Global")] [SuppressMessage("ReSharper", "UnassignedField.Global")] [SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] -public class FieldRefTestCases +public unsafe class FieldRefTestCases { public void ReadFieldFromReferencedAssemblyType() { @@ -24,22 +25,38 @@ public void ReadPointerFieldFromReferencedAssemblyType() { IL.Push(new TypeFromReferencedAssembly()); Ldfld(FieldRef.Field(typeof(TypeFromReferencedAssembly), nameof(TypeFromReferencedAssembly.PointerField))); - Pop(); + Call(MethodRef.Method(typeof(FieldRefTestCases), nameof(ConsumePointer))); } public void ReadGenericPointerFieldFromReferencedAssemblyType() { IL.Push(new TypeFromReferencedAssembly()); Ldfld(FieldRef.Field(typeof(TypeFromReferencedAssembly), nameof(TypeFromReferencedAssembly.PointerField))); - Pop(); + Call(MethodRef.Method(typeof(FieldRefTestCases), nameof(ConsumePointer))); IL.Push(new TypeFromReferencedAssembly()); Ldfld(FieldRef.Field(typeof(TypeFromReferencedAssembly), nameof(TypeFromReferencedAssembly.PointerField))); - Pop(); + Call(MethodRef.Method(typeof(FieldRefTestCases), nameof(ConsumePointer))); IL.Push(new TypeFromReferencedAssembly()); Ldfld(FieldRef.Field(typeof(TypeFromReferencedAssembly), nameof(TypeFromReferencedAssembly.PointerField))); - Pop(); + Call(MethodRef.Method(typeof(FieldRefTestCases), nameof(ConsumePointer))); + } + + public void ReadGenericTypeFieldFromReferencedAssemblyType() + { + IL.Push(new TypeFromReferencedAssembly()); + Ldfld(FieldRef.Field(typeof(TypeFromReferencedAssembly), nameof(TypeFromReferencedAssembly.GenericTypeField))); + Ldfld(FieldRef.Field(typeof(TypeFromReferencedAssembly), nameof(TypeFromReferencedAssembly.PointerField))); + Call(MethodRef.Method(typeof(FieldRefTestCases), nameof(ConsumePointer))); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + [SuppressMessage("ReSharper", "UnusedParameter.Local")] + private static void ConsumePointer(void* value) + { + // This could probably have been replaced by a pop, but having a noinline method + // makes sure the JIT won't be able to optimize away reading the unused field value } } diff --git a/src/InlineIL.Tests/Weaving/FieldRefTests.cs b/src/InlineIL.Tests/Weaving/FieldRefTests.cs index 59ea7ec..2534a73 100644 --- a/src/InlineIL.Tests/Weaving/FieldRefTests.cs +++ b/src/InlineIL.Tests/Weaving/FieldRefTests.cs @@ -38,6 +38,13 @@ public void should_handle_generic_fields_with_types_from_referenced_assemblies() instance.ReadGenericPointerFieldFromReferencedAssemblyType(); } + [Fact] + public void should_handle_generic_type_fields_from_referenced_assemblies() + { + var instance = GetUnverifiableInstance(); + instance.ReadGenericTypeFieldFromReferencedAssemblyType(); + } + [Fact] public void should_reference_field_in_different_ways() {