diff --git a/CodeConverter/CSharp/TypeConversionAnalyzer.cs b/CodeConverter/CSharp/TypeConversionAnalyzer.cs index 385fd102..b43f7296 100644 --- a/CodeConverter/CSharp/TypeConversionAnalyzer.cs +++ b/CodeConverter/CSharp/TypeConversionAnalyzer.cs @@ -98,6 +98,11 @@ private ExpressionSyntax AddTypeConversion(VBSyntax.ExpressionSyntax vbNode, Exp var enumUnderlyingType = ((INamedTypeSymbol) vbType).EnumUnderlyingType; csNode = AddTypeConversion(vbNode, csNode, TypeConversionKind.NonDestructiveCast, addParenthesisIfNeeded, vbType, enumUnderlyingType); return AddTypeConversion(vbNode, csNode, TypeConversionKind.Conversion, addParenthesisIfNeeded, enumUnderlyingType, vbConvertedType); + case TypeConversionKind.LiteralSuffix: + if (csNode is CSSyntax.LiteralExpressionSyntax && vbNode is VBSyntax.LiteralExpressionSyntax { Token: { Value: { } val, Text: { } text } } && LiteralConversions.GetLiteralExpression(val, text, vbConvertedType) is { } csLiteral) { + return csLiteral; + } + return csNode; case TypeConversionKind.Unknown: case TypeConversionKind.Identity: return addParenthesisIfNeeded ? vbNode.ParenthesizeIfPrecedenceCouldChange(csNode) : csNode; @@ -327,7 +332,7 @@ private bool TryAnalyzeCsConversion(VBasic.VisualBasicCompilation vbCompilation, // e.g. When VB "&" changes to C# "+", there are lots more overloads available that implicit casts could match. // e.g. sbyte * ulong uses the decimal * operator in VB. In C# it's ambiguous - see ExpressionTests.vb "TestMul". typeConversionKind = - isConst && IsImplicitConstantConversion(vbNode) || csUnderlyingConversion.IsIdentity || !sourceForced && IsExactTypeNumericLiteral(vbNode, underlyingVbConvertedType) ? TypeConversionKind.Identity : + isConst && IsImplicitConstantConversion(vbNode) || csUnderlyingConversion.IsIdentity || !sourceForced && IsExactTypeNumericLiteral(vbNode, underlyingVbConvertedType) ? TypeConversionKind.LiteralSuffix : csUnderlyingConversion.IsImplicit || underlyingVbType.IsNumericType() ? TypeConversionKind.NonDestructiveCast : TypeConversionKind.Conversion; return true; @@ -502,7 +507,8 @@ public enum TypeConversionKind NullableBool, StringToCharArray, DelegateConstructor, - FractionalNumberRoundThenCast + FractionalNumberRoundThenCast, + LiteralSuffix } public static bool ConvertStringToCharLiteral(VBSyntax.ExpressionSyntax node, diff --git a/Tests/CSharp/TypeCastTests.cs b/Tests/CSharp/TypeCastTests.cs index 19b304e5..cace3a47 100644 --- a/Tests/CSharp/TypeCastTests.cs +++ b/Tests/CSharp/TypeCastTests.cs @@ -1559,6 +1559,84 @@ private static T GenericFunctionWithCastThatExistsInCsharp() where T : TestGe } [Fact] + public async Task TestInferringImplicitGenericTypesAsync() + { + await TestConversionVisualBasicToCSharpAsync(@" +Imports System +Imports System.Linq + +Public Class TestClass + Public Sub GenerateFromConstants + Dim floatArr = Enumerable.Repeat(1.0F, 5).ToArray() + Dim doubleArr = Enumerable.Repeat(2.0, 5).ToArray() + Dim decimalArr = Enumerable.Repeat(3.0D, 5).ToArray() + Dim boolArr = Enumerable.Repeat(true, 5).ToArray() + Dim intArr = Enumerable.Repeat(1, 5).ToArray() + Dim uintArr = Enumerable.Repeat(1ui, 5).ToArray() + Dim longArr = Enumerable.Repeat(1l, 5).ToArray() + Dim ulongArr = Enumerable.Repeat(1ul, 5).ToArray() + Dim charArr = Enumerable.Repeat(""a""c, 5).ToArray() + Dim strArr = Enumerable.Repeat(""a"", 5).ToArray() + Dim objArr = Enumerable.Repeat(new object(), 5).ToArray() + End Sub + + Public Sub GenerateFromCasts + Dim floatArr = Enumerable.Repeat(CSng(1), 5).ToArray() + Dim doubleArr = Enumerable.Repeat(CDbl(2), 5).ToArray() + Dim decimalArr = Enumerable.Repeat(CDec(3), 5).ToArray() + Dim boolArr = Enumerable.Repeat(CBool(1), 5).ToArray() + Dim intArr = Enumerable.Repeat(CInt(1.0), 5).ToArray() + Dim uintArr = Enumerable.Repeat(CUInt(1.0), 5).ToArray() + Dim longArr = Enumerable.Repeat(CLng(1.0), 5).ToArray() + Dim ulongArr = Enumerable.Repeat(CULng(1.0), 5).ToArray() + Dim charArr = Enumerable.Repeat(CChar(""a""), 5).ToArray() + Dim strArr = Enumerable.Repeat(CStr(""a""c), 5).ToArray() + Dim objArr1 = Enumerable.Repeat(CObj(""a""), 5).ToArray() + Dim objArr2 = Enumerable.Repeat(CType(""a"", object), 5).ToArray() + End Sub +End Class +", @" +using System; +using System.Linq; +using Microsoft.VisualBasic.CompilerServices; // Install-Package Microsoft.VisualBasic + +public partial class TestClass +{ + public void GenerateFromConstants() + { + float[] floatArr = Enumerable.Repeat(1.0f, 5).ToArray(); + double[] doubleArr = Enumerable.Repeat(2.0d, 5).ToArray(); + decimal[] decimalArr = Enumerable.Repeat(3.0m, 5).ToArray(); + bool[] boolArr = Enumerable.Repeat(true, 5).ToArray(); + int[] intArr = Enumerable.Repeat(1, 5).ToArray(); + uint[] uintArr = Enumerable.Repeat(1U, 5).ToArray(); + long[] longArr = Enumerable.Repeat(1L, 5).ToArray(); + ulong[] ulongArr = Enumerable.Repeat(1UL, 5).ToArray(); + char[] charArr = Enumerable.Repeat('a', 5).ToArray(); + string[] strArr = Enumerable.Repeat(""a"", 5).ToArray(); + object[] objArr = Enumerable.Repeat(new object(), 5).ToArray(); + } + + public void GenerateFromCasts() + { + float[] floatArr = Enumerable.Repeat(1f, 5).ToArray(); + double[] doubleArr = Enumerable.Repeat(2d, 5).ToArray(); + decimal[] decimalArr = Enumerable.Repeat(3m, 5).ToArray(); + bool[] boolArr = Enumerable.Repeat(Conversions.ToBoolean(1), 5).ToArray(); + int[] intArr = Enumerable.Repeat((int)Math.Round(1.0d), 5).ToArray(); + uint[] uintArr = Enumerable.Repeat((uint)Math.Round(1.0d), 5).ToArray(); + long[] longArr = Enumerable.Repeat((long)Math.Round(1.0d), 5).ToArray(); + ulong[] ulongArr = Enumerable.Repeat((ulong)Math.Round(1.0d), 5).ToArray(); + char[] charArr = Enumerable.Repeat('a', 5).ToArray(); + string[] strArr = Enumerable.Repeat(""a"", 5).ToArray(); + object[] objArr1 = Enumerable.Repeat((object)""a"", 5).ToArray(); + object[] objArr2 = Enumerable.Repeat((object)""a"", 5).ToArray(); + } +}"); + } + + + [Fact] public async Task TestCTypeStringToEnumAsync() { await TestConversionVisualBasicToCSharpAsync(