From 16acf3052d2652936df060bf86a9215991513c44 Mon Sep 17 00:00:00 2001 From: Adriano Carlos Verona Date: Sun, 29 Sep 2024 22:24:52 -0400 Subject: [PATCH] adds support for boxing elements in a collection expression (#256) --- .../OutputBased/CollectionExpressionTests.cs | 21 +++++++++++++++++-- .../AST/ArrayInitializationProcessor.cs | 12 +++++++++-- .../AST/CollectionExpressionProcessor.cs | 5 +++++ 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/Cecilifier.Core.Tests/Tests/OutputBased/CollectionExpressionTests.cs b/Cecilifier.Core.Tests/Tests/OutputBased/CollectionExpressionTests.cs index 9c3ae37d..0cb0cebb 100644 --- a/Cecilifier.Core.Tests/Tests/OutputBased/CollectionExpressionTests.cs +++ b/Cecilifier.Core.Tests/Tests/OutputBased/CollectionExpressionTests.cs @@ -81,7 +81,7 @@ public void ImplicitTypeConversions_Are_Applied([Values("List", "Foo[]", "S using System; {{targetType}} items = {{items}}; - // We can´t rely on a foreach (to simplify the code) due to issue #306 + // We can´t use a foreach (to simplify the code) due to issue #306 for(var i = 0; i < {{lengthExtractor}}; i++) System.Console.Write(items[i].Value); struct Foo @@ -94,7 +94,24 @@ struct Foo Regex.Replace(items, @"[\[\],\s+]", ""), expectedILError); } - "21", + + [Test] + public void BoxConversions_Are_Applied([Values("List", "object[]", "Span")] string targetType, [Values("[2, 1]", "[5, 4, 3, 2, 1]")] string items) + { + var (lengthExtractor, expectedILError) = targetType == "Span" ? ("items.Length", "[ReturnPtrToStack]") : ("((ICollection) items).Count", null); + AssertOutput( + $$""" + using System.Collections.Generic; + using System; + + {{targetType}} items = {{items}}; + // We can´t usa a foreach (to simplify the code) due to issue #306 + for(var i = 0; i < {{lengthExtractor}}; i++) + { + System.Console.Write(items[i]); + } + """, + Regex.Replace(items, @"[\[\],\s+]", ""), expectedILError); } } diff --git a/Cecilifier.Core/AST/ArrayInitializationProcessor.cs b/Cecilifier.Core/AST/ArrayInitializationProcessor.cs index 46bdca29..cd4762a2 100644 --- a/Cecilifier.Core/AST/ArrayInitializationProcessor.cs +++ b/Cecilifier.Core/AST/ArrayInitializationProcessor.cs @@ -1,4 +1,3 @@ -using System; using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; @@ -6,12 +5,21 @@ using Cecilifier.Core.CodeGeneration; using Cecilifier.Core.Extensions; +using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Operations; namespace Cecilifier.Core.AST; public class ArrayInitializationProcessor { + /// + /// Generates Cecil calls to initialize an array which reference is at the top of the stack. + /// + /// An used to visit each value to be stored in the array + /// + /// Values to be stored. + /// A operation conveying information on potential conversions. + /// The type of the ast node representing the elements. internal static void InitializeUnoptimized(ExpressionVisitor visitor, ITypeSymbol elementType, SeparatedSyntaxList? elements, IOperation parentOperation = null) where TElement : CSharpSyntaxNode { var context = visitor.Context; @@ -25,7 +33,7 @@ internal static void InitializeUnoptimized(ExpressionVisitor visitor, elements.Value[i].Accept(visitor); //TODO: Refactor to extract all this into some common method to apply conversions. - var itemType = context.SemanticModel.GetTypeInfo(elements.Value[i]); + var itemType = context.SemanticModel.GetTypeInfo(elements.Value[i] is ExpressionElementSyntax els ? els.Expression : elements.Value[i]); if (elementType.IsReferenceType && itemType.Type != null && itemType.Type.IsValueType) { context.EmitCilInstruction(visitor.ILVariable, OpCodes.Box, context.TypeResolver.Resolve(itemType.Type)); diff --git a/Cecilifier.Core/AST/CollectionExpressionProcessor.cs b/Cecilifier.Core/AST/CollectionExpressionProcessor.cs index d1433a2d..3e4e1c3b 100644 --- a/Cecilifier.Core/AST/CollectionExpressionProcessor.cs +++ b/Cecilifier.Core/AST/CollectionExpressionProcessor.cs @@ -10,6 +10,7 @@ using Cecilifier.Core.Naming; using Cecilifier.Core.Variables; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Operations; using Mono.Cecil.Cil; @@ -228,5 +229,9 @@ static void ApplyConversions(IVisitorContext context, string ilVar, IOperation o { context.AddCallToMethod(conversion.OperatorMethod, ilVar); } + else if (operation is IConversionOperation conversion2 && context.SemanticModel.Compilation.ClassifyConversion(conversion2.Operand.Type, operation.Type).IsBoxing) + { + context.EmitCilInstruction(ilVar, OpCodes.Box, context.TypeResolver.Resolve(conversion2.Operand.Type)); + } } }