Skip to content

Commit 2fb1edc

Browse files
committed
TypeEqual expression is not supported
It was supported before, but the implementation is incorrect, so I changed it to fallback to System Compile (and I think this expression type is quite rare).
1 parent 682a90e commit 2fb1edc

File tree

5 files changed

+81
-18
lines changed

5 files changed

+81
-18
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: 12 additions & 5 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

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)