提交 3a2a0b0f 编写于 作者: J Julien Couvreur 提交者: GitHub

VB: Explicit casts to Double or Single should produce a conversion operation (#22552)

上级 86fd17e9
......@@ -37,7 +37,7 @@ public override BoundNode VisitConversion(BoundConversion node)
// If original conversion has become something else with unknown precision, add an explicit identity cast.
if (!_inExpressionLambda &&
node.ExplicitCastInCode &&
IsFloatPointExpressionOfUnknownPrecision(result))
IsFloatingPointExpressionOfUnknownPrecision(result))
{
result = MakeConversionNode(
node.Syntax,
......@@ -52,7 +52,7 @@ public override BoundNode VisitConversion(BoundConversion node)
return result;
}
private static bool IsFloatPointExpressionOfUnknownPrecision(BoundExpression rewrittenNode)
private static bool IsFloatingPointExpressionOfUnknownPrecision(BoundExpression rewrittenNode)
{
if (rewrittenNode == null)
{
......@@ -84,7 +84,7 @@ private static bool IsFloatPointExpressionOfUnknownPrecision(BoundExpression rew
case BoundKind.Sequence:
var sequence = (BoundSequence)rewrittenNode;
return IsFloatPointExpressionOfUnknownPrecision(sequence.Value);
return IsFloatingPointExpressionOfUnknownPrecision(sequence.Value);
case BoundKind.Conversion:
// lowered conversions have definite precision unless they are implicit identity casts
......@@ -144,7 +144,7 @@ private static bool IsFloatPointExpressionOfUnknownPrecision(BoundExpression rew
// 4.1.6 C# spec: To force a value of a floating point type to the exact precision of its type, an explicit cast can be used.
// If this is not an identity conversion of a float with unknown precision, strip away the identity conversion.
if (!IsFloatPointExpressionOfUnknownPrecision(rewrittenOperand))
if (!IsFloatingPointExpressionOfUnknownPrecision(rewrittenOperand))
{
return EnsureNotAssignableIfUsedAsMethodReceiver(rewrittenOperand);
}
......
......@@ -1095,5 +1095,91 @@ static void Main()
string expectedOutput = @"1";
CompileAndVerify(source, expectedOutput: expectedOutput);
}
[Fact, WorkItem(22533, "https://github.com/dotnet/roslyn/issues/22533")]
public void TestDoubleConversionEmitted()
{
var source = @"
class Program
{
static bool M()
{
double dValue = 600.1;
int iValue = 600;
byte mbytDeciWgt = 1;
bool value = (dValue > iValue + (10 ^ -mbytDeciWgt));
return value;
}
}
";
var comp = CompileAndVerify(source);
comp.VerifyIL("Program.M",
@"{
// Code size 28 (0x1c)
.maxstack 4
.locals init (int V_0, //iValue
byte V_1) //mbytDeciWgt
IL_0000: ldc.r8 600.1
IL_0009: ldc.i4 0x258
IL_000e: stloc.0
IL_000f: ldc.i4.1
IL_0010: stloc.1
IL_0011: ldloc.0
IL_0012: ldc.i4.s 10
IL_0014: ldloc.1
IL_0015: neg
IL_0016: xor
IL_0017: add
IL_0018: conv.r8
IL_0019: cgt
IL_001b: ret
}");
}
[Fact, WorkItem(22533, "https://github.com/dotnet/roslyn/issues/22533")]
public void TestExplicitDoubleConversionEmitted()
{
var source = @"
class Program
{
static bool M()
{
double dValue = 600.1;
int iValue = 600;
byte mbytDeciWgt = 1;
bool value = ((double)dValue > (double)((double)iValue + (double)System.Math.Pow(10, -mbytDeciWgt)));
return value;
}
}
";
var comp = CompileAndVerify(source);
comp.VerifyIL("Program.M",
@"{
// Code size 43 (0x2b)
.maxstack 4
.locals init (int V_0, //iValue
byte V_1) //mbytDeciWgt
IL_0000: ldc.r8 600.1
IL_0009: ldc.i4 0x258
IL_000e: stloc.0
IL_000f: ldc.i4.1
IL_0010: stloc.1
IL_0011: conv.r8
IL_0012: ldloc.0
IL_0013: conv.r8
IL_0014: ldc.r8 10
IL_001d: ldloc.1
IL_001e: neg
IL_001f: conv.r8
IL_0020: call ""double System.Math.Pow(double, double)""
IL_0025: conv.r8
IL_0026: add
IL_0027: conv.r8
IL_0028: cgt
IL_002a: ret
}");
}
}
}
' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
Imports System.Collections.Immutable
Imports System.Diagnostics
Imports System.Runtime.InteropServices
Imports Microsoft.CodeAnalysis.PooledObjects
Imports Microsoft.CodeAnalysis.Text
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Imports TypeKind = Microsoft.CodeAnalysis.TypeKind
Namespace Microsoft.CodeAnalysis.VisualBasic
Partial Friend NotInheritable Class LocalRewriter
Public Overrides Function VisitConversion(node As BoundConversion) As BoundNode
If Not _inExpressionLambda AndAlso Conversions.IsIdentityConversion(node.ConversionKind) Then
Return Visit(node.Operand)
Dim result = DirectCast(Visit(node.Operand), BoundExpression)
If node.ExplicitCastInCode AndAlso IsFloatingPointExpressionOfUnknownPrecision(result) Then
' To force a value of a floating point type to the exact precision of its type, an explicit cast can be used.
' It means that explicit casts to CDbl() or CSng() should be preserved on the node.
' If original conversion has become something else with unknown precision, add an explicit identity cast.
result = node.Update(
result,
ConversionKind.Identity,
checked:=False,
explicitCastInCode:=True,
constantValueOpt:=node.ConstantValueOpt,
extendedInfoOpt:=node.ExtendedInfoOpt,
type:=node.Type)
End If
Return result
End If
If node.Operand.Kind = BoundKind.UserDefinedConversion Then
......@@ -100,7 +112,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
ElseIf (node.ConversionKind And ConversionKind.InterpolatedString) = ConversionKind.InterpolatedString Then
returnValue = RewriteInterpolatedStringConversion(node)
ElseIf (node.ConversionKind And (ConversionKind.Tuple Or ConversionKind.Nullable)) = conversionKind.Tuple Then
ElseIf (node.ConversionKind And (ConversionKind.Tuple Or ConversionKind.Nullable)) = ConversionKind.Tuple Then
returnValue = RewriteTupleConversion(node)
Else
......@@ -114,6 +126,43 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return returnValue
End Function
Private Shared Function IsFloatingPointExpressionOfUnknownPrecision(rewrittenNode As BoundExpression) As Boolean
If rewrittenNode Is Nothing Then
Return False
End If
' Note: no special handling for node having a constant value because it cannot reach here
Dim specialType = rewrittenNode.Type.SpecialType
If specialType <> SpecialType.System_Double AndAlso specialType <> SpecialType.System_Single Then
Return False
End If
Select Case rewrittenNode.Kind
' ECMA-335 I.12.1.3 Handling of floating-point data types.
' ... the value might be retained in the internal representation
' for future use, if it is reloaded from the storage location without having been modified ...
'
' Unfortunately, the above means that precision is not guaranteed even when loading from storage.
'
' Case BoundKind.FieldAccess
' Case BoundKind.ArrayAccess
' Return True
Case BoundKind.Sequence
Dim sequence = DirectCast(rewrittenNode, BoundSequence)
Return IsFloatingPointExpressionOfUnknownPrecision(sequence.ValueOpt)
Case BoundKind.Conversion
' lowered conversions have definite precision unless they are implicit identity casts
Dim conversion = DirectCast(rewrittenNode, BoundConversion)
Return conversion.ConversionKind = ConversionKind.Identity AndAlso Not conversion.ExplicitCastInCode
End Select
' it is a float/double expression and we have no idea ...
Return True
End Function
Private Function RewriteTupleConversion(node As BoundConversion) As BoundExpression
Dim syntax = node.Syntax
Dim rewrittenOperand = VisitExpression(node.Operand)
......
......@@ -13665,5 +13665,172 @@ End Module
}
]]>)
End Sub
<Fact, WorkItem(22533, "https://github.com/dotnet/roslyn/issues/22533")>
Public Sub TestExplicitDoubleConversionEmitted()
CompileAndVerify(
<compilation>
<file name="a.vb">
Imports System
Module Program
Function M() As Boolean
Dim dValue As Double = 600.1
Dim mbytDeciWgt As Byte = 1
Return CDbl(dValue) > CDbl(dValue + CDbl(10 ^ -mbytDeciWgt))
End Function
End Module
</file>
</compilation>).
VerifyIL("Program.M",
<![CDATA[
{
// Code size 39 (0x27)
.maxstack 4
.locals init (Double V_0, //dValue
Byte V_1) //mbytDeciWgt
IL_0000: ldc.r8 600.1
IL_0009: stloc.0
IL_000a: ldc.i4.1
IL_000b: stloc.1
IL_000c: ldloc.0
IL_000d: conv.r8
IL_000e: ldloc.0
IL_000f: ldc.r8 10
IL_0018: ldloc.1
IL_0019: neg
IL_001a: conv.ovf.i2
IL_001b: conv.r8
IL_001c: call "Function System.Math.Pow(Double, Double) As Double"
IL_0021: conv.r8
IL_0022: add
IL_0023: conv.r8
IL_0024: cgt
IL_0026: ret
}
]]>)
End Sub
<Fact, WorkItem(22533, "https://github.com/dotnet/roslyn/issues/22533")>
Public Sub TestImplicitDoubleConversionEmitted()
CompileAndVerify(
<compilation>
<file name="a.vb">
Imports System
Module Program
Function M() As Boolean
Dim dValue As Double = 600.1
Dim mbytDeciWgt As Byte = 1
Return dValue > dValue + (10 ^ -mbytDeciWgt)
End Function
End Module
</file>
</compilation>).
VerifyIL("Program.M",
<![CDATA[
{
// Code size 34 (0x22)
.maxstack 4
.locals init (Byte V_0) //mbytDeciWgt
IL_0000: ldc.r8 600.1
IL_0009: ldc.i4.1
IL_000a: stloc.0
IL_000b: dup
IL_000c: ldc.r8 10
IL_0015: ldloc.0
IL_0016: neg
IL_0017: conv.ovf.i2
IL_0018: conv.r8
IL_0019: call "Function System.Math.Pow(Double, Double) As Double"
IL_001e: add
IL_001f: cgt
IL_0021: ret
}
]]>)
End Sub
<Fact, WorkItem(22533, "https://github.com/dotnet/roslyn/issues/22533")>
Public Sub TestExplicitSingleConversionEmitted()
CompileAndVerify(
<compilation>
<file name="a.vb">
Imports System
Module Program
Function M() As Boolean
Dim dValue As Single = 600.1
Dim mbytDeciWgt As Byte = 1
Return CSng(dValue) > CSng(dValue + CSng(10 ^ -mbytDeciWgt))
End Function
End Module
</file>
</compilation>).
VerifyIL("Program.M",
<![CDATA[
{
// Code size 35 (0x23)
.maxstack 4
.locals init (Single V_0, //dValue
Byte V_1) //mbytDeciWgt
IL_0000: ldc.r4 600.1
IL_0005: stloc.0
IL_0006: ldc.i4.1
IL_0007: stloc.1
IL_0008: ldloc.0
IL_0009: conv.r4
IL_000a: ldloc.0
IL_000b: ldc.r8 10
IL_0014: ldloc.1
IL_0015: neg
IL_0016: conv.ovf.i2
IL_0017: conv.r8
IL_0018: call "Function System.Math.Pow(Double, Double) As Double"
IL_001d: conv.r4
IL_001e: add
IL_001f: conv.r4
IL_0020: cgt
IL_0022: ret
}
]]>)
End Sub
<Fact, WorkItem(22533, "https://github.com/dotnet/roslyn/issues/22533")>
Public Sub TestExplicitSingleConversionNotEmittedOnConstantValue()
CompileAndVerify(
<compilation>
<file name="a.vb">
Imports System
Module Program
Function M() As Boolean
Dim dValue As Single = 600.1
Dim mbytDeciWgt As Byte = 1
Return CSng(dValue) > CSng(CSng(600) + CSng(0.1))
End Function
End Module
</file>
</compilation>).
VerifyIL("Program.M",
<![CDATA[
{
// Code size 14 (0xe)
.maxstack 2
IL_0000: ldc.r4 600.1
IL_0005: conv.r4
IL_0006: ldc.r4 600.1
IL_000b: cgt
IL_000d: ret
}
]]>)
End Sub
End Class
End Namespace
......@@ -1992,7 +1992,7 @@ End Class
diff1.VerifyIL("C.VB$StateMachine_1_F.MoveNext()", "
{
// Code size 162 (0xa2)
// Code size 163 (0xa3)
.maxstack 5
.locals init (Boolean V_0,
Integer V_1,
......@@ -2008,7 +2008,7 @@ End Class
IL_000e: beq.s IL_0014
IL_0010: br.s IL_0016
IL_0012: br.s IL_0018
IL_0014: br.s IL_0074
IL_0014: br.s IL_0075
IL_0016: ldc.i4.0
IL_0017: ret
IL_0018: ldarg.0
......@@ -2032,48 +2032,49 @@ End Class
IL_0046: ldarg.0
IL_0047: ldc.i4.0
IL_0048: stfld ""C.VB$StateMachine_1_F.$S1 As Integer""
IL_004d: br.s IL_008c
IL_004d: br.s IL_008d
IL_004f: ldarg.0
IL_0050: ldarg.0
IL_0051: ldfld ""C.VB$StateMachine_1_F.$S3 As Double()""
IL_0056: ldarg.0
IL_0057: ldfld ""C.VB$StateMachine_1_F.$S1 As Integer""
IL_005c: ldelem.r8
IL_005d: stfld ""C.VB$StateMachine_1_F.$VB$ResumableLocal_x$4 As Double""
IL_0062: ldarg.0
IL_0063: ldc.i4.1
IL_0064: stfld ""C.VB$StateMachine_1_F.$Current As Integer""
IL_0069: ldarg.0
IL_006a: ldc.i4.1
IL_006b: dup
IL_006c: stloc.1
IL_006d: stfld ""C.VB$StateMachine_1_F.$State As Integer""
IL_0072: ldc.i4.1
IL_0073: ret
IL_0074: ldarg.0
IL_0075: ldc.i4.m1
IL_0076: dup
IL_0077: stloc.1
IL_0078: stfld ""C.VB$StateMachine_1_F.$State As Integer""
IL_007d: nop
IL_007e: ldarg.0
IL_005d: conv.r8
IL_005e: stfld ""C.VB$StateMachine_1_F.$VB$ResumableLocal_x$4 As Double""
IL_0063: ldarg.0
IL_0064: ldc.i4.1
IL_0065: stfld ""C.VB$StateMachine_1_F.$Current As Integer""
IL_006a: ldarg.0
IL_006b: ldc.i4.1
IL_006c: dup
IL_006d: stloc.1
IL_006e: stfld ""C.VB$StateMachine_1_F.$State As Integer""
IL_0073: ldc.i4.1
IL_0074: ret
IL_0075: ldarg.0
IL_0076: ldc.i4.m1
IL_0077: dup
IL_0078: stloc.1
IL_0079: stfld ""C.VB$StateMachine_1_F.$State As Integer""
IL_007e: nop
IL_007f: ldarg.0
IL_0080: ldfld ""C.VB$StateMachine_1_F.$S1 As Integer""
IL_0085: ldc.i4.1
IL_0086: add.ovf
IL_0087: stfld ""C.VB$StateMachine_1_F.$S1 As Integer""
IL_008c: ldarg.0
IL_008d: ldfld ""C.VB$StateMachine_1_F.$S1 As Integer""
IL_0092: ldarg.0
IL_0093: ldfld ""C.VB$StateMachine_1_F.$S3 As Double()""
IL_0098: ldlen
IL_0099: conv.i4
IL_009a: clt
IL_009c: stloc.2
IL_009d: ldloc.2
IL_009e: brtrue.s IL_004f
IL_00a0: ldc.i4.0
IL_00a1: ret
IL_0080: ldarg.0
IL_0081: ldfld ""C.VB$StateMachine_1_F.$S1 As Integer""
IL_0086: ldc.i4.1
IL_0087: add.ovf
IL_0088: stfld ""C.VB$StateMachine_1_F.$S1 As Integer""
IL_008d: ldarg.0
IL_008e: ldfld ""C.VB$StateMachine_1_F.$S1 As Integer""
IL_0093: ldarg.0
IL_0094: ldfld ""C.VB$StateMachine_1_F.$S3 As Double()""
IL_0099: ldlen
IL_009a: conv.i4
IL_009b: clt
IL_009d: stloc.2
IL_009e: ldloc.2
IL_009f: brtrue.s IL_004f
IL_00a1: ldc.i4.0
IL_00a2: ret
}
")
End Using
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册