Skip to content

Commit 2b4127c

Browse files
committed
Conflicts: test/FastExpressionCompiler.TestsRunner.Net472/Program.cs test/FastExpressionCompiler.TestsRunner/Program.cs
2 parents a39eed7 + 797c2a9 commit 2b4127c

File tree

8 files changed

+146
-22
lines changed

8 files changed

+146
-22
lines changed

src/FastExpressionCompiler.LightExpression/Expression.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2389,7 +2389,14 @@ internal TypeBinaryExpression(ExpressionType nodeType, Expression expression, Ty
23892389
protected internal override Expression Accept(ExpressionVisitor visitor) => visitor.VisitTypeBinary(this);
23902390
#endif
23912391
internal override SysExpr CreateSysExpression(ref LiveCountArray<LightAndSysExpr> exprsConverted) =>
2392-
SysExpr.TypeIs(Expression.ToExpression(ref exprsConverted), TypeOperand);
2392+
NodeType switch {
2393+
ExpressionType.TypeIs =>
2394+
SysExpr.TypeIs(Expression.ToExpression(ref exprsConverted), TypeOperand),
2395+
ExpressionType.TypeEqual =>
2396+
SysExpr.TypeEqual(Expression.ToExpression(ref exprsConverted), TypeOperand),
2397+
_ => throw new NotSupportedException()
2398+
};
2399+
23932400
}
23942401

23952402
public class MemberInitExpression : Expression, IArgumentProvider<MemberBinding>
@@ -4221,4 +4228,4 @@ public interface IParameterProvider
42214228
}
42224229
}
42234230

4224-
//#endif
4231+
//#endif

src/FastExpressionCompiler/FastExpressionCompiler.cs

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,9 @@ public enum NotSupported
9696
/// <summary>Goto of the Return kind from the TryCatch is not supported</summary>
9797
Try_GotoReturnToTheFollowupLabel,
9898
/// <summary>Not supported assignment target</summary>
99-
Assign_Target
99+
Assign_Target,
100+
/// <summary> ExpressionType.TypeEqual is not supported </summary>
101+
TypeEqual
100102
}
101103

102104
/// <summary>FEC Not Supported exception</summary>
@@ -2693,15 +2695,20 @@ private static bool TryEmitTypeIsOrEqual(TypeBinaryExpression expr, IReadOnlyLis
26932695
return false;
26942696

26952697
if ((parent & ParentFlags.IgnoreResult) != 0)
2696-
il.Emit(OpCodes.Pop);
2697-
else
2698+
return true;
2699+
else if (expr.NodeType == ExpressionType.TypeIs)
26982700
{
26992701
il.Emit(OpCodes.Isinst, expr.TypeOperand);
27002702
il.Emit(OpCodes.Ldnull);
27012703
il.Emit(OpCodes.Cgt_Un);
2704+
return true;
2705+
}
2706+
else
2707+
{
2708+
if ((setup & CompilerFlags.ThrowOnNotSupportedExpression) != 0)
2709+
throw new NotSupportedExpressionException(NotSupported.TypeEqual);
2710+
return false;
27022711
}
2703-
2704-
return true;
27052712
}
27062713

27072714
#if LIGHT_EXPRESSION
@@ -2763,6 +2770,12 @@ private static bool TryEmitConvert(UnaryExpression expr, IReadOnlyList<PE> param
27632770
var underlyingNullableSourceType = Nullable.GetUnderlyingType(sourceType);
27642771
var targetType = expr.Type;
27652772

2773+
if (targetType.IsAssignableFrom(sourceType) && (parent & ParentFlags.IgnoreResult) != 0)
2774+
{
2775+
// quick path for ignored result & conversion which can't cause exception: just do nothing
2776+
return TryEmit(opExpr, paramExprs, il, ref closure, setup, parent);
2777+
}
2778+
27662779
if (sourceTypeIsNullable && targetType == underlyingNullableSourceType)
27672780
{
27682781
if (!TryEmit(opExpr, paramExprs, il, ref closure, setup,
@@ -2813,9 +2826,7 @@ private static bool TryEmitConvert(UnaryExpression expr, IReadOnlyList<PE> param
28132826
if (method != null && method.DeclaringType == targetType && method.GetParameters()[0].ParameterType == sourceType)
28142827
{
28152828
il.Emit(OpCodes.Call, method);
2816-
if ((parent & ParentFlags.IgnoreResult) != 0)
2817-
il.Emit(OpCodes.Pop);
2818-
return true;
2829+
return il.EmitPopIfIgnoreResult(parent);
28192830
}
28202831

28212832
var actualSourceType = sourceTypeIsNullable ? underlyingNullableSourceType : sourceType;
@@ -2991,8 +3002,14 @@ private static bool TryEmitConstantOfNotNullValue(
29913002
il.Emit(OpCodes.Ldelem_Ref);
29923003
if (exprType.IsValueType)
29933004
il.Emit(OpCodes.Unbox_Any, exprType);
2994-
else // todo: @perf it is probably required only for Full CLR starting from NET45, e.g. `Test_283_Case6_MappingSchemaTests_CultureInfo_VerificationException`
3005+
else
3006+
{
3007+
// this is probably required only for Full CLR starting from NET45, e.g. `Test_283_Case6_MappingSchemaTests_CultureInfo_VerificationException`
3008+
// .NET Core does not seem to care about verifiability and it's faster without the explicit cast
3009+
#if NETFRAMEWORK
29953010
il.Emit(OpCodes.Castclass, exprType);
3011+
#endif
3012+
}
29963013
}
29973014
}
29983015
else
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
using NUnit.Framework;
2+
using System;
3+
using System.Linq.Expressions;
4+
#if LIGHT_EXPRESSION
5+
using static FastExpressionCompiler.LightExpression.Expression;
6+
namespace FastExpressionCompiler.LightExpression.IssueTests
7+
#else
8+
using static System.Linq.Expressions.Expression;
9+
namespace FastExpressionCompiler.IssueTests
10+
#endif
11+
{
12+
[TestFixture]
13+
public class Issue310_InvalidProgramException_ignored_nullable
14+
{
15+
public int Run()
16+
{
17+
Test1();
18+
Test2();
19+
return 2;
20+
}
21+
22+
[Test]
23+
public void Test1()
24+
{
25+
var p = Parameter(typeof(int), "tmp0");
26+
var expr =
27+
Lambda<Action<int>>(Block(
28+
Convert(p, typeof(int?)),
29+
Default(typeof(void))), p);
30+
31+
var f = expr.CompileFast();
32+
f(2);
33+
}
34+
35+
[Test]
36+
public void Test2()
37+
{
38+
var p = Parameter(typeof(int), "tmp0");
39+
var expr =
40+
Lambda<Action<int>>(Convert(p, typeof(int?)), new[] { p });
41+
var f = expr.CompileFast();
42+
f(2);
43+
}
44+
}
45+
}

test/FastExpressionCompiler.TestsRunner.Net472/Program.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,9 @@ void Run(Func<int> run, string name = null)
201201
Run(new Issue308_Wrong_delegate_type_returned_with_closure().Run);
202202
Run(new FastExpressionCompiler.LightExpression.IssueTests.Issue308_Wrong_delegate_type_returned_with_closure().Run);
203203

204+
Run(new Issue310_InvalidProgramException_ignored_nullable().Run);
205+
Run(new FastExpressionCompiler.LightExpression.IssueTests.Issue310_InvalidProgramException_ignored_nullable().Run);
206+
204207
Run(new Issue309_InvalidProgramException_with_MakeBinary_liftToNull_true().Run);
205208
Run(new FastExpressionCompiler.LightExpression.IssueTests.Issue309_InvalidProgramException_with_MakeBinary_liftToNull_true().Run);
206209

test/FastExpressionCompiler.TestsRunner/Program.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,9 @@ void Run(Func<int> run, string name = null)
228228
Run(new Issue308_Wrong_delegate_type_returned_with_closure().Run);
229229
Run(new FastExpressionCompiler.LightExpression.IssueTests.Issue308_Wrong_delegate_type_returned_with_closure().Run);
230230

231+
Run(new Issue310_InvalidProgramException_ignored_nullable().Run);
232+
Run(new FastExpressionCompiler.LightExpression.IssueTests.Issue310_InvalidProgramException_ignored_nullable().Run);
233+
231234
Run(new Issue309_InvalidProgramException_with_MakeBinary_liftToNull_true().Run);
232235
Run(new FastExpressionCompiler.LightExpression.IssueTests.Issue309_InvalidProgramException_with_MakeBinary_liftToNull_true().Run);
233236

test/FastExpressionCompiler.UnitTests/TestTools.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ public static void PrintIL(this MethodInfo method, string tag = null)
5151

5252
public static StringBuilder ToILString(this MethodInfo method, StringBuilder s = null)
5353
{
54+
if (method is null) throw new ArgumentNullException(nameof(method));
55+
5456
s = s ?? new StringBuilder();
5557

5658
var ilReader = ILReaderFactory.Create(method);
@@ -64,7 +66,6 @@ public static StringBuilder ToILString(this MethodInfo method, StringBuilder s =
6466
s.AppendLine();
6567
else
6668
secondLine = true;
67-
6869
s.Append(il.Offset.ToString().PadRight(4, ' ')).Append(' ').Append(il.OpCode);
6970
if (il is InlineFieldInstruction f)
7071
s.Append(' ').Append(f.Field.DeclaringType.Name).Append('.').Append(f.Field.Name);

test/FastExpressionCompiler.UnitTests/TypeBinaryExpressionTests.cs

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
using System;
22
using NUnit.Framework;
33

44
#if LIGHT_EXPRESSION
@@ -16,25 +16,30 @@ public int Run()
1616
{
1717
TypeEqual_should_work();
1818
TypeIs_should_work();
19+
TypeIs_more_advanced();
1920

20-
return 2;
21+
return 3;
2122
}
2223

2324
[Test]
2425
public void TypeEqual_should_work()
2526
{
2627
var sExpr = Parameter(typeof(object), "o");
2728
var expr = Lambda<Func<object, bool>>(
28-
TypeEqual(sExpr, typeof(string)),
29+
TypeEqual(sExpr, typeof(A)),
2930
sExpr);
3031

31-
var f = expr.CompileFast(true);
32+
var f = expr.CompileSys(); // TODO: CompileFast, but it does not work ATM
3233
Assert.IsNotNull(f);
33-
bool result = f("123");
34-
35-
Assert.IsTrue(result);
34+
bool result = f(new A());
35+
Assert.IsTrue(result, expr.ToString());
36+
bool result2 = f(new B());
37+
Assert.IsFalse(result2, expr.GetType().FullName);
3638
}
3739

40+
class A { }
41+
class B: A { }
42+
3843
[Test]
3944
public void TypeIs_should_work()
4045
{
@@ -48,5 +53,34 @@ public void TypeIs_should_work()
4853

4954
Assert.IsTrue(result);
5055
}
56+
57+
[Test]
58+
public void TypeIs_more_advanced()
59+
{
60+
var fromParam = Parameter(typeof(object));
61+
var exprInt = Lambda<Func<object, bool>>(TypeIs(fromParam, typeof(int)), fromParam).CompileFast(true);
62+
var exprX = Lambda<Func<object, bool>>(TypeIs(fromParam, typeof(S)), fromParam).CompileFast(true);
63+
var exprXEnum = Lambda<Func<object, bool>>(TypeIs(fromParam, typeof(E)), fromParam).CompileFast(true);
64+
var exprString = Lambda<Func<object, bool>>(TypeIs(fromParam, typeof(string)), fromParam).CompileFast(true);
65+
var exprIgnoredResult = Lambda<Action<object>>(TypeIs(fromParam, typeof(string)), fromParam).CompileFast(true);
66+
67+
Assert.AreEqual(true, exprInt(1));
68+
Assert.AreEqual(false, exprInt("A"));
69+
Assert.AreEqual(false, exprInt(1L));
70+
Assert.AreEqual(true, exprX(new S()));
71+
Assert.AreEqual(false, exprX("A"));
72+
Assert.AreEqual(false, exprX(null));
73+
Assert.AreEqual(true, exprXEnum(E.A));
74+
Assert.AreEqual(false, exprXEnum("A"));
75+
Assert.AreEqual(false, exprXEnum(null));
76+
Assert.AreEqual(true, exprString("A"));
77+
Assert.AreEqual(false, exprString(E.A));
78+
Assert.AreEqual(false, exprXEnum(null));
79+
exprIgnoredResult(1);
80+
exprIgnoredResult("A");
81+
}
82+
83+
struct S { }
84+
enum E { A }
5185
}
5286
}

test/FastExpressionCompiler.UnitTests/ValueTypeTests.cs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
using System;
22
using NUnit.Framework;
33

44
#if LIGHT_EXPRESSION
@@ -22,8 +22,9 @@ public int Run()
2222
Can_init_struct_member();
2323
Can_get_struct_member();
2424
Action_using_with_struct_closure_field();
25+
Struct_Convert_to_interface();
2526

26-
return 7;
27+
return 8;
2728
}
2829

2930
[Test]
@@ -122,14 +123,27 @@ public void Action_using_with_struct_closure_field()
122123
Assert.AreEqual("a", s.Value);
123124
}
124125

125-
public struct SS
126+
[Test]
127+
public void Struct_Convert_to_interface()
128+
{
129+
Expression<Func<int, IComparable>> expr = a => a;
130+
Expression<Func<DateTimeKind, IComparable>> expr2 = a => a;
131+
Expression<Func<SS, IDisposable>> expr3 = a => a;
132+
133+
Assert.AreEqual(12, expr.CompileFast(ifFastFailedReturnNull: true)(12));
134+
Assert.AreEqual(DateTimeKind.Local, expr2.CompileFast(ifFastFailedReturnNull: true)(DateTimeKind.Local));
135+
Assert.AreEqual(new SS { Value = "a" }, expr3.CompileFast(ifFastFailedReturnNull: true)(new SS { Value = "a" }));
136+
}
137+
138+
public struct SS: IDisposable
126139
{
127140
public string Value;
128141

129142
public void SetValue(string s)
130143
{
131144
Value = s;
132145
}
146+
public void Dispose() { }
133147
}
134148
}
135149
}

0 commit comments

Comments
 (0)