From ff3248484df18f0765546bfa06f7b8a31bb17d61 Mon Sep 17 00:00:00 2001 From: Adriano Carlos Verona Date: Wed, 13 Mar 2024 17:39:48 -0400 Subject: [PATCH] adds test for accessing non zero index InlineArray element (#257) also fixes the reference to Unsafe.As() and Unsafe.Add(); the code was accessing the open generic methods, as opposed to the generic instance methods. --- .../Tests/Unit/InlineArrayTests.cs | 38 ++++++++++++++++++- .../PrivateImplementationDetails.Generator.cs | 31 ++++++++++++--- 2 files changed, 62 insertions(+), 7 deletions(-) diff --git a/Cecilifier.Core.Tests/Tests/Unit/InlineArrayTests.cs b/Cecilifier.Core.Tests/Tests/Unit/InlineArrayTests.cs index 471e0b51..981923de 100644 --- a/Cecilifier.Core.Tests/Tests/Unit/InlineArrayTests.cs +++ b/Cecilifier.Core.Tests/Tests/Unit/InlineArrayTests.cs @@ -137,7 +137,41 @@ public struct IntBuffer { private int _element0; } """)); } - // Access to not first element + [TestCase("field[42] = 1", @"Ldflda, fld_field_\d+", TestName = "Field")] + [TestCase("parameter[42] = 1", @"Ldarga, p_parameter_\d+", TestName = "Parameter")] + [TestCase("local[42] = 1", @"Ldloca, l_local_\d+", TestName = "Local")] + public void AccessToNonFirstElement_Of_StorageLocation(string statement, string expectedOpCode) + { + var result = RunCecilifier($$""" + class C + { + public IntBuffer field; + void M(IntBuffer parameter) + { + var local = new IntBuffer(); + {{statement}}; + } + } + + [System.Runtime.CompilerServices.InlineArray(100)] + public struct IntBuffer { private int _element0; } + """); + + var cecilified = result.GeneratedCode.ReadToEnd(); + + Assert.That(cecilified, Does.Match($""" + (\s+il_M_\d+\.Emit\(OpCodes\.){expectedOpCode}\); + \1Ldc_I4, 42\); + \s+//\ class. + """)); + + Assert.That(cecilified, Does.Match(""" + (\s+il_M_\d+\.Emit\(OpCodes\.)Call, gi_inlineArrayElementRef_\d+\); + \s+\1Ldc_I4, 1\); + \s+\1Stind_I4\); + """)); + } + + // Element type: reference type, value type, custom value type - //ADD-ISSUE: } diff --git a/Cecilifier.Core/CodeGeneration/PrivateImplementationDetails.Generator.cs b/Cecilifier.Core/CodeGeneration/PrivateImplementationDetails.Generator.cs index 55b914e5..625fcd0c 100644 --- a/Cecilifier.Core/CodeGeneration/PrivateImplementationDetails.Generator.cs +++ b/Cecilifier.Core/CodeGeneration/PrivateImplementationDetails.Generator.cs @@ -139,15 +139,23 @@ public static string GetOrEmmitInlineArrayFirstElementRefMethod(IVisitorContext return spanTypeParameter.MakeByReferenceType(); }); + var tbufferTypeParameter = ResolveOwnedGenericParameter(context, "TBuffer", methodTypeQualifiedName); + var telementTypeParameter = ResolveOwnedGenericParameter(context, "TElement", methodTypeQualifiedName); + + var unsafeAsVarName = context.Naming.SyntheticVariable("unsafeAs", ElementKind.GenericInstance); + var unsafeAsExps = GetUnsafeAsMethod(context) + .MethodResolverExpression(context) + .MakeGenericInstanceMethod(unsafeAsVarName, [tbufferTypeParameter, telementTypeParameter]); + var methodBodyExpressions = CecilDefinitionsFactory.MethodBody( methodVar, [ OpCodes.Ldarg_0, - OpCodes.Call.WithOperand(GetUnsafeAsMethod(context).MethodResolverExpression(context)), + OpCodes.Call.WithOperand(unsafeAsVarName), OpCodes.Ret ]); - foreach (var exp in methodExpressions.Concat(methodBodyExpressions)) + foreach (var exp in methodExpressions.Concat(unsafeAsExps).Concat(methodBodyExpressions)) { context.WriteCecilExpression(exp); context.WriteNewLine(); @@ -190,17 +198,30 @@ public static string GetOrEmmitInlineArrayElementRefMethod(IVisitorContext conte return spanTypeParameter.MakeByReferenceType(); }); + var tbufferTypeParameter = ResolveOwnedGenericParameter(context, "TBuffer", methodTypeQualifiedName); + var telementTypeParameter = ResolveOwnedGenericParameter(context, "TElement", methodTypeQualifiedName); + + var unsafeAsVarName = context.Naming.SyntheticVariable("unsafeAs", ElementKind.GenericInstance); + var unsafeAsExps = GetUnsafeAsMethod(context) + .MethodResolverExpression(context) + .MakeGenericInstanceMethod(unsafeAsVarName, [tbufferTypeParameter, telementTypeParameter]); + + var unsafeAddVarName = context.Naming.SyntheticVariable("unsafeAdd", ElementKind.GenericInstance); + var unsafeAddExps = GetUnsafeAddMethod(context) + .MethodResolverExpression(context) + .MakeGenericInstanceMethod(unsafeAddVarName, [telementTypeParameter]); + var methodBodyExpressions = CecilDefinitionsFactory.MethodBody( methodVar, [ OpCodes.Ldarg_0, - OpCodes.Call.WithOperand(GetUnsafeAsMethod(context).MethodResolverExpression(context)), + OpCodes.Call.WithOperand(unsafeAsVarName), OpCodes.Ldarg_1, - OpCodes.Call.WithOperand(GetUnsafeAddMethod(context).MethodResolverExpression(context)), + OpCodes.Call.WithOperand(unsafeAddVarName), OpCodes.Ret ]); - foreach (var exp in methodExpressions.Concat(methodBodyExpressions)) + foreach (var exp in methodExpressions.Concat(unsafeAsExps).Concat(unsafeAddExps).Concat(methodBodyExpressions)) { context.WriteCecilExpression(exp); context.WriteNewLine();