提交 af831242 编写于 作者: V vsadov

Fixing a compat issue with invoking properties on generic type parameters in expression trees.

While the casts are semantically incorrect, the conditions under which they are observable are extremely narrow:
We would have to deal with a generic T receiver which is actually a struct that implements a property form an interface and the implementation of the getter must make observable mutations to the instance.

At this point it seems more appropriate to continue adding these casts.

Fixes #4471
上级 1bd00171
......@@ -923,6 +923,23 @@ private BoundExpression VisitPropertyAccess(BoundPropertyAccess node)
{
var receiver = node.PropertySymbol.IsStatic ? _bound.Null(ExpressionType) : Visit(node.ReceiverOpt);
var getMethod = node.PropertySymbol.GetOwnOrInheritedGetMethod();
// COMPAT: see https://github.com/dotnet/roslyn/issues/4471
// old compiler used to insert casts like this and
// there are known dependencies on this kind of tree shape.
//
// While the casts are semantically incorrect, the conditions
// under which they are observable are extremely narrow:
// We would have to deal with a generic T receiver which is actually a struct
// that implements a property form an interface and
// the implementation of the getter must make observable mutations to the instance.
//
// At this point it seems more appropriate to continue adding these casts.
if (node.ReceiverOpt?.Type.IsTypeParameter() == true)
{
receiver = this.Convert(receiver, getMethod.ReceiverType, isChecked: false);
}
return ExprFactory("Property", receiver, _bound.MethodInfo(getMethod));
}
......
......@@ -4159,6 +4159,48 @@ class Test
var r1 = f(default(T));
Expression<Func<T, int>> e = x => x.M() + x.P + x.P;
var r2 = e.Compile()(default(T));
Console.WriteLine(r1!=r2 ? ""pass"" : ""fail"");
}
static void Main()
{
Test1<S>();
}
}";
string expectedOutput = @"pass";
CompileAndVerify(
new[] { source },
new[] { ExpressionAssemblyRef },
expectedOutput: expectedOutput);
}
[WorkItem(530529, "DevDiv")]
[Fact]
public void BoxTypeParameter1()
{
string source =
@"using System;
using System.Linq;
using System.Linq.Expressions;
using System.Collections.Generic;
interface I
{
int P();
}
struct S : I
{
int _p;
public int P() => _p++;
}
class Test
{
public static void Test1<T>() where T : I
{
Func<T, int> f = x => x.P() + x.P();
var r1 = f(default(T));
Expression<Func<T, int>> e = x => x.P() + x.P();
var r2 = e.Compile()(default(T));
Console.WriteLine(r1==r2 ? ""pass"" : ""fail"");
}
static void Main()
......@@ -4175,6 +4217,27 @@ static void Main()
expectedOutput: expectedOutput);
}
[Fact, WorkItem(531047, "DevDiv")]
public void NullIsRegression()
{
string source =
@"using System;
using System.Linq.Expressions;
class Test
{
public static void Main()
{
Expression<Func<bool>> expr = () => null is Test;
Console.WriteLine(expr.Dump());
}
}";
string expectedOutput = "TypeIs(Constant(null Type:System.Object) TypeOperand:Test Type:System.Boolean)";
CompileAndVerify(
new[] { source, ExpressionTestLibrary },
new[] { ExpressionAssemblyRef },
expectedOutput: expectedOutput);
}
[WorkItem(546601, "DevDiv")]
[Fact]
public void NewArrayInitInAsAndIs()
......@@ -4209,22 +4272,43 @@ public static void Main()
expectedOutput: expectedOutput);
}
[WorkItem(531047, "DevDiv")]
[Fact, WorkItem(531047, "DevDiv")]
public void NullIsRegression()
[Fact, WorkItem(4471, "https://github.com/dotnet/roslyn/issues/4471")]
public void GenericPropertyReceiverCast()
{
string source =
@"using System;
using System.Linq.Expressions;
class Test
{
public interface IDeletedID
{
int DeletedID { get; }
}
public class C1 : IDeletedID
{
int IDeletedID.DeletedID
{
get
{
return 1;
}
}
}
public static void Main()
{
Expression<Func<bool>> expr = () => null is Test;
Test1(new C1());
}
public static void Test1<T>(T x) where T: IDeletedID
{
Expression<Func<bool>> expr = () => x.DeletedID == 1;
Console.WriteLine(expr.Dump());
}
}";
string expectedOutput = "TypeIs(Constant(null Type:System.Object) TypeOperand:Test Type:System.Boolean)";
string expectedOutput = "Equal(MemberAccess(Convert(MemberAccess(Constant(Test+<>c__DisplayClass3_0`1[Test+C1] Type:Test+<>c__DisplayClass3_0`1[Test+C1]).x Type:Test+C1) Type:Test+IDeletedID).DeletedID Type:System.Int32) Constant(1 Type:System.Int32) Type:System.Boolean)";
CompileAndVerify(
new[] { source, ExpressionTestLibrary },
new[] { ExpressionAssemblyRef },
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册