Skip to content

Commit b8fdca7

Browse files
author
Maksim Volkau
committed
added test for #495
1 parent b7b57f5 commit b8fdca7

File tree

3 files changed

+103
-13
lines changed

3 files changed

+103
-13
lines changed

src/FastExpressionCompiler/FastExpressionCompiler.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1217,9 +1217,7 @@ public enum Result
12171217
/// <summary>TypeEqual is not supported </summary>
12181218
NotSupported_TypeEqual = 1009,
12191219
/// <summary>`when` in catch is not supported yet</summary>
1220-
NotSupported_ExceptionCatchFilter = 1010,
1221-
/// <summary>Example: lambda return type requires bool, but body has an object type</summary>
1222-
NotSupported_NoCoalesceBetweenLambdaReturnTypeAndBodyType = 1011
1220+
NotSupported_ExceptionCatchFilter = 1010
12231221
}
12241222

12251223
/// <summary>Return value is ignored</summary>
@@ -2343,7 +2341,7 @@ public static bool TryEmit(Expression expr,
23432341
{
23442342
// But we cannot use the return pattern and eliminate the target label if we have more gotos referencing it, see #430
23452343
var (gotos, labels) = closure.TargetToGotosAndLabels.Map.TryGetValueRef(label.Target, out var found);
2346-
if (found && gotos <= labels)
2344+
if (found & gotos <= labels)
23472345
{
23482346
if ((parent & ParentFlags.TryCatch) != 0)
23492347
{
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
#if NET8_0_OR_GREATER
2+
using System;
3+
using System.Reflection.Emit;
4+
using System.Text.Json;
5+
6+
#if LIGHT_EXPRESSION
7+
using FastExpressionCompiler.LightExpression.ImTools;
8+
using static FastExpressionCompiler.LightExpression.Expression;
9+
namespace FastExpressionCompiler.LightExpression.IssueTests;
10+
#else
11+
using System.Linq.Expressions;
12+
using static System.Linq.Expressions.Expression;
13+
namespace FastExpressionCompiler.IssueTests;
14+
#endif
15+
16+
public struct Issue495_Incomplete_pattern_detection_for_NotSupported_1007_Return_goto_from_TryCatch_with_Assign_generates_invalid_IL : ITestX
17+
{
18+
public void Run(TestRun t)
19+
{
20+
ReturnGotoFromTryCatchWithAssign_ShouldBeDetectedAsError1007(t);
21+
}
22+
23+
public void ReturnGotoFromTryCatchWithAssign_ShouldBeDetectedAsError1007(TestContext t)
24+
{
25+
// Arrange: Build expression with Return(label, Assign(...)) inside TryCatch
26+
var variable = Variable(typeof(object), "var");
27+
var finalResult = Variable(typeof(object), "finalResult");
28+
var returnLabel = Label(typeof(object), "return");
29+
var exceptionParam = Parameter(typeof(Exception), "ex");
30+
31+
var block = Block(
32+
new[] { variable, finalResult },
33+
TryCatch(
34+
Block(
35+
typeof(void),
36+
Assign(variable, Constant("hello", typeof(object))),
37+
IfThen(
38+
NotEqual(variable, Constant(null, typeof(object))),
39+
// FEC should detect this as error 1007 and reject it
40+
Return(returnLabel, Assign(finalResult, variable), typeof(object))
41+
// @wip other patters:
42+
// - Return(label, Block(Assign(var, value), value))
43+
// - Return(label, Call(MethodThatAssigns, ref var, value))
44+
// - Return(label, Coalesce(value, Assign(var, default)))
45+
),
46+
Assign(finalResult, Constant("default", typeof(object))),
47+
Label(returnLabel, Constant("fallback", typeof(object)))
48+
),
49+
Catch(exceptionParam, Empty())
50+
),
51+
finalResult
52+
);
53+
54+
var expr = Lambda<Func<object>>(block);
55+
56+
expr.PrintCSharp();
57+
var @cs = (Func<object>)(() => //object
58+
{
59+
object var = null;
60+
object finalResult = null;
61+
try
62+
{
63+
var = (object)"hello";
64+
if (var != null)
65+
{
66+
return finalResult = var;
67+
}; // todo: @wip remove ;
68+
finalResult = (object)"default";
69+
// return:; // todo: @wip remove or comment or rename but make it a valid c#
70+
}
71+
catch (Exception ex) // no need for ex
72+
{
73+
; // todo: @wip remove ;
74+
}
75+
return finalResult;
76+
});
77+
78+
79+
var fs = expr.CompileSys();
80+
fs.PrintIL(format: ILDecoder.ILFormat.AssertOpCodes);
81+
fs();
82+
83+
// Act: CompileFast should throw NotSupportedExpressionException or return null
84+
// var ff = expr.CompileFast(ifFastFailedReturnNull: true);
85+
// ff.PrintIL(format: ILDecoder.ILFormat.AssertOpCodes);
86+
87+
// // Expected: compiled should be null (pattern detected as unsupported)
88+
// t.IsNull(ff);
89+
}
90+
}
91+
#endif

test/FastExpressionCompiler.TestsRunner/Program.cs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,16 @@ public static void Main()
3434
// new Issue441_Fails_to_pass_Constant_as_call_parameter_by_reference().Run();
3535
// new Issue461_InvalidProgramException_when_null_checking_type_by_ref().Run();
3636

37+
var st = new TestRun(TestFlags.RethrowException);
38+
39+
st.Run(new Issue495_Incomplete_pattern_detection_for_NotSupported_1007_Return_goto_from_TryCatch_with_Assign_generates_invalid_IL());
40+
st.Run(new Issue480_CLR_detected_an_invalid_program_exception());
41+
42+
#if NET8_0_OR_GREATER
43+
st.Run(new Issue487_Fix_ToCSharpString_output_for_boolean_equality_expressions());
44+
st.Run(new Issue475_Reuse_DynamicMethod_if_possible());
45+
#endif
46+
3747
var lt = new LightExpression.TestRun(LightExpression.TestFlags.RethrowException);
3848

3949
#if NET8_0_OR_GREATER
@@ -46,15 +56,6 @@ public static void Main()
4656
lt.Run(new LightExpression.IssueTests.Issue473_InvalidProgramException_when_using_Expression_Condition_with_converted_decimal_expression());
4757
lt.Run(new LightExpression.IssueTests.Issue476_System_ExecutionEngineException_with_nullables_on_repeated_calls_to_ConcurrentDictionary());
4858

49-
var st = new TestRun(TestFlags.RethrowException);
50-
51-
st.Run(new Issue480_CLR_detected_an_invalid_program_exception());
52-
53-
#if NET8_0_OR_GREATER
54-
st.Run(new Issue487_Fix_ToCSharpString_output_for_boolean_equality_expressions());
55-
st.Run(new Issue475_Reuse_DynamicMethod_if_possible());
56-
#endif
57-
5859
RunAllTests();
5960
}
6061

0 commit comments

Comments
 (0)