提交 75befe7d 编写于 作者: V vsadov

Make expression trees involving enum literals to look like produced by native compiler

Native compiler exposes results of constant folding in the expression trees.
In particular, conversion from an enum literal to an underlying type is fairly consistently folded by the native compiler as it can be observed in the expression trees.

Roslyn, on the other hand, was not very consistent here.
Some cases like explicitly converted literals were folded - Ex:  IntTakingMethod((int)E1.a)
Other cases like implicit conversions to underlying type introduced in the processs of type promotion in binary expressions were not.

This fixes known differences in this behavior.

Fixes #4085
Fixes #3292
上级 5be08f2f
......@@ -391,8 +391,8 @@ private BoundExpression VisitBinaryOperator(BinaryOperatorKind opKind, MethodSym
promotedType = _nullableType.Construct(promotedType);
}
loweredLeft = Convert(loweredLeft, left.Type, promotedType, isChecked, false);
loweredRight = Convert(loweredRight, right.Type, promotedType, isChecked, false);
loweredLeft = PromoteEnumOperand(left, loweredLeft, promotedType, isChecked);
loweredRight = PromoteEnumOperand(right, loweredRight, promotedType, isChecked);
var result = MakeBinary(methodOpt, type, isLifted, requiresLifted, opName, loweredLeft, loweredRight);
return Demote(result, type, isChecked);
......@@ -402,6 +402,20 @@ private BoundExpression VisitBinaryOperator(BinaryOperatorKind opKind, MethodSym
}
}
private BoundExpression PromoteEnumOperand(BoundExpression operand, BoundExpression loweredOperand, TypeSymbol promotedType, bool isChecked)
{
var literal = operand as BoundLiteral;
if (literal != null)
{
// for compat reasons enum literals are directly promoted into underlying values
return Visit(literal.Update(literal.ConstantValue, promotedType));
}
else
{
return Convert(loweredOperand, operand.Type, promotedType, isChecked, false);
}
}
private BoundExpression MakeBinary(MethodSymbol methodOpt, TypeSymbol type, bool isLifted, bool requiresLifted, string opName, BoundExpression loweredLeft, BoundExpression loweredRight)
{
return
......
......@@ -117,7 +117,7 @@ public BoundExpression VisitBinaryOperator(BoundBinaryOperator node, BoundUnaryO
var stack = ArrayBuilder<BoundBinaryOperator>.GetInstance();
for (BoundBinaryOperator current = node; current != null; current = current.Left as BoundBinaryOperator)
for (BoundBinaryOperator current = node; current != null && current.ConstantValue == null; current = current.Left as BoundBinaryOperator)
{
stack.Push(current);
}
......
......@@ -5066,6 +5066,131 @@ public static void Main()
.VerifyDiagnostics();
}
[WorkItem(3292, "https://github.com/dotnet/roslyn/issues/3292")]
[Fact]
public void EnumConversions001()
{
const string source = @"
using System;
using System.Linq.Expressions;
struct S { }
class C //: TestBase
{
enum E1
{
a,
b
}
class Program
{
static void Main(string[] args)
{
var v = E1.b;
Expression<Func<bool>> e = () => E1.b == v;
System.Console.WriteLine(e);
}
}
}";
const string expectedOutput = @"() => (1 == Convert(value(C+Program+<>c__DisplayClass0_0).v))";
CompileAndVerify(
new[] {
source,
// ExpressionTestLibrary
},
new[] { ExpressionAssemblyRef },
expectedOutput: expectedOutput);
}
[WorkItem(3292, "https://github.com/dotnet/roslyn/issues/3292")]
[Fact]
public void EnumConversions002()
{
const string source = @"
using System;
using System.Linq.Expressions;
struct S { }
class C //: TestBase
{
enum E1
{
a,
b
}
class Program
{
static void Main(string[] args)
{
var v = E1.b;
Expression<Func<bool>> e = () => (43 - E1.b) == v;
System.Console.WriteLine(e);
}
}
}";
const string expectedOutput = @"() => (42 == Convert(value(C+Program+<>c__DisplayClass0_0).v))";
CompileAndVerify(
new[] {
source,
// ExpressionTestLibrary
},
new[] { ExpressionAssemblyRef },
expectedOutput: expectedOutput);
}
[WorkItem(3292, "https://github.com/dotnet/roslyn/issues/3292")]
[Fact]
public void EnumConversions003()
{
const string source = @"
using System;
using System.Linq.Expressions;
struct S { }
class C //: TestBase
{
enum E1
{
a,
b
}
class Program
{
static void Main(string[] args)
{
Expression<Func<int>> e = () => foo((int)E1.b);
System.Console.WriteLine(e);
}
static int foo(int x)
{
return x;
}
}
}";
const string expectedOutput = @"() => foo(1)";
CompileAndVerify(
new[] {
source,
// ExpressionTestLibrary
},
new[] { ExpressionAssemblyRef },
expectedOutput: expectedOutput);
}
#endregion Regression Tests
#region helpers
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册