Skip to content

Commit 586af7a

Browse files
author
maximv
committed
fixing block stack collecting again; added the test for #287
1 parent 159eccb commit 586af7a

File tree

2 files changed

+119
-68
lines changed

2 files changed

+119
-68
lines changed

src/FastExpressionCompiler/FastExpressionCompiler.cs

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1299,35 +1299,29 @@ private static bool TryCollectBoundConstants(ref ClosureInfo closure, Expression
12991299

13001300
case ExpressionType.Block:
13011301
var blockExpr = (BlockExpression)expr;
1302-
var blockVarExprs = blockExpr.Variables;
13031302
var blockExprs = blockExpr.Expressions;
13041303
var blockExprCount = blockExprs.Count;
13051304
if (blockExprCount == 0)
13061305
return true; // yeah, this is the real case
13071306

1308-
if (blockExprCount == 0)
1309-
{
1310-
for (var i = 0; i < blockExprCount - 1; i++)
1311-
if (!TryCollectBoundConstants(ref closure, blockExprs[i], paramExprs, isNestedLambda, ref rootClosure, flags))
1312-
return false;
1313-
expr = blockExprs[blockExprCount - 1];
1314-
continue;
1315-
}
1316-
else
1317-
{
1318-
if (blockVarExprs.Count == 1)
1319-
closure.PushBlockWithVars(blockVarExprs[0]);
1320-
else if (blockVarExprs.Count != 0)
1321-
closure.PushBlockWithVars(blockVarExprs);
1307+
var varExprs = blockExpr.Variables;
1308+
var varExprCount = varExprs.Count;
1309+
if (varExprCount == 1)
1310+
closure.PushBlockWithVars(varExprs[0]);
1311+
else if (varExprCount != 0)
1312+
closure.PushBlockWithVars(varExprs);
13221313

1323-
for (var i = 0; i < blockExprCount; i++)
1324-
if (!TryCollectBoundConstants(ref closure, blockExprs[i], paramExprs, isNestedLambda, ref rootClosure, flags))
1325-
return false;
1314+
for (var i = 0; i < blockExprCount - 1; i++)
1315+
if (!TryCollectBoundConstants(ref closure, blockExprs[i], paramExprs, isNestedLambda, ref rootClosure, flags))
1316+
return false;
13261317

1327-
if (blockVarExprs.Count != 0)
1328-
closure.PopBlock();
1329-
}
1318+
expr = blockExprs[blockExprCount - 1];
1319+
if (varExprCount == 0) // in case of no variables we can collect the last exp without recursion
1320+
continue;
13301321

1322+
if (!TryCollectBoundConstants(ref closure, expr, paramExprs, isNestedLambda, ref rootClosure, flags))
1323+
return false;
1324+
closure.PopBlock();
13311325
return true;
13321326

13331327
case ExpressionType.Loop:

test/FastExpressionCompiler.IssueTests/Issue274_Failing_Expressions_in_Linq2DB.cs

Lines changed: 104 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -468,7 +468,7 @@ public void Test_case_4_simplified_InvalidCastException()
468468
Assert.IsNull(f());
469469
}
470470

471-
public static void SimpleStringHandler(string s) {}
471+
public static void SimpleStringHandler(string s) { }
472472

473473
[Test]
474474
public void Test_case_4_Full_InvalidCastException()
@@ -539,17 +539,61 @@ public void Test_case_4_Full_InvalidCastException()
539539
Assert.IsInstanceOf<SampleClass>(s2);
540540
}
541541

542+
[Test]
543+
public void Test_287_Case2_SimpleDelegate_as_nested_lambda_in_TesCollection_test()
544+
{
545+
var p = new ParameterExpression[3]; // the parameter expressions
546+
var e = new Expression[8]; // the unique expressions
547+
var l = new LabelTarget[0]; // the labels
548+
var expr = Lambda( // $
549+
typeof(Dynamic.SimpleDelegate),
550+
e[0] = Block(
551+
typeof(void),
552+
new[] {
553+
p[0]=Parameter(typeof(SimpleDelegate), "handler")
554+
},
555+
e[1] = MakeBinary(ExpressionType.Assign,
556+
p[0 // (SimpleDelegate handler)
557+
],
558+
e[2] = Field(
559+
p[1] = Parameter(typeof(SampleClass)),
560+
typeof(SampleClass).GetTypeInfo().GetDeclaredField("_SimpleDelegateEvent"))),
561+
e[3] = Condition(
562+
e[4] = MakeBinary(ExpressionType.NotEqual,
563+
p[0 // (SimpleDelegate handler)
564+
],
565+
e[5] = Constant(null, typeof(System.Delegate))),
566+
e[6] = Invoke(
567+
p[0 // (SimpleDelegate handler)
568+
],
569+
p[2] = Parameter(typeof(string))),
570+
e[7] = Empty(),
571+
typeof(void))),
572+
p[2 // (string string__41619574)
573+
]);
574+
575+
expr.PrintCSharp();
576+
577+
var fs = expr.CompileSys();
578+
fs.PrintIL();
579+
// Assert.AreEqual(new CustomMoneyType { Amount = 1.11m }, fs(1.11m));
580+
581+
var fx = expr.CompileFast(true);
582+
fx.PrintIL();
583+
// Assert.AreEqual(new CustomMoneyType { Amount = 1.11m }, fx(1.11m));
584+
}
585+
542586
[Test]
543587
public void Test_287_Case1_ConvertTests_NullableParameterInOperatorConvert_VerificationException()
544588
{
545589
var p = new ParameterExpression[1]; // the parameter expressions
546590
var e = new Expression[2]; // the unique expressions
547591
var l = new LabelTarget[0]; // the labels
548592
var expr = Lambda<Func<System.Decimal, CustomMoneyType>>(
549-
e[0]=Convert(
550-
e[1]=New(/*1 args*/
593+
e[0] = Convert(
594+
e[1] = New(/*1 args*/
551595
typeof(System.Nullable<System.Decimal>).GetTypeInfo().DeclaredConstructors.ToArray()[0],
552-
p[0]=Parameter(typeof(System.Decimal), "p")),
596+
p[0] = Parameter(typeof(System.Decimal), "p")),
553597
typeof(CustomMoneyType),
554598
typeof(CustomMoneyType).GetMethods().Single(x => !x.IsGenericMethod && x.Name == "op_Explicit" && x.GetParameters().Select(y => y.ParameterType).SequenceEqual(new[] { typeof(System.Nullable<System.Decimal>) }))),
555599
p[0 // ([struct] System.Decimal p)
@@ -562,15 +606,15 @@ public void Test_287_Case1_ConvertTests_NullableParameterInOperatorConvert_Verif
562606
Assert.AreEqual(new CustomMoneyType { Amount = 1.11m }, fs(1.11m));
563607

564608
var fx = expr.CompileFast(true);
565-
fx.PrintIL();
609+
fx.PrintIL();
566610
Assert.AreEqual(new CustomMoneyType { Amount = 1.11m }, fx(1.11m));
567611
}
568612

569613
private struct CustomMoneyType
570614
{
571-
public decimal? Amount;
572-
public static explicit operator CustomMoneyType(decimal? amount) =>
573-
new CustomMoneyType() { Amount = amount };
615+
public decimal? Amount;
616+
public static explicit operator CustomMoneyType(decimal? amount) =>
617+
new CustomMoneyType() { Amount = amount };
574618
}
575619

576620
[Test]
@@ -591,12 +635,12 @@ public void Test_283_Case6_MappingSchemaTests_CultureInfo_VerificationException(
591635
var e = new Expression[4]; // the unique expressions
592636
var l = new LabelTarget[0]; // the labels
593637
var expr = Lambda<Func<DateTime, string>>( // $
594-
e[0]=Call(
595-
p[0]=Parameter(typeof(System.DateTime), "v"),
638+
e[0] = Call(
639+
p[0] = Parameter(typeof(System.DateTime), "v"),
596640
typeof(System.DateTime).GetMethods().Single(x => !x.IsGenericMethod && x.Name == "ToString" && x.GetParameters().Select(y => y.ParameterType).SequenceEqual(new[] { typeof(System.IFormatProvider) })),
597-
e[1]=Property(
598-
e[2]=Field(
599-
e[3]=Constant(x, typeof(c__DisplayClass41_0)),
641+
e[1] = Property(
642+
e[2] = Field(
643+
e[3] = Constant(x, typeof(c__DisplayClass41_0)),
600644
typeof(c__DisplayClass41_0).GetTypeInfo().GetDeclaredField("info")),
601645
typeof(CultureInfo).GetTypeInfo().GetDeclaredProperty("DateTimeFormat"))),
602646
p[0 // ([struct] System.DateTime v)
@@ -609,13 +653,13 @@ public void Test_283_Case6_MappingSchemaTests_CultureInfo_VerificationException(
609653
Assert.AreEqual("20.01.2012 16:30:40", fs(new DateTime(2012, 1, 20, 16, 30, 40)));
610654

611655
var fx = expr.CompileFast(true);
612-
fx.PrintIL();
656+
fx.PrintIL();
613657
Assert.AreEqual("20.01.2012 16:30:40", fx(new DateTime(2012, 1, 20, 16, 30, 40)));
614658
}
615659

616660
class c__DisplayClass41_0
617661
{
618-
public System.Globalization.CultureInfo info;
662+
public System.Globalization.CultureInfo info;
619663
}
620664

621665
[Test]
@@ -625,17 +669,17 @@ public void Test_283_Case5_ConvertTests_NullableIntToNullableEnum_NullReferenceE
625669
var e = new Expression[5]; // the unique expressions
626670
var l = new LabelTarget[0]; // the labels
627671
var expr = Lambda<Func<System.Nullable<int>, System.Nullable<Enum1>>>( // $
628-
e[0]=Condition(
629-
e[1]=Property(
630-
p[0]=Parameter(typeof(System.Nullable<int>), "p"),
672+
e[0] = Condition(
673+
e[1] = Property(
674+
p[0] = Parameter(typeof(System.Nullable<int>), "p"),
631675
typeof(System.Nullable<int>).GetTypeInfo().GetDeclaredProperty("HasValue")),
632-
e[2]=Convert(
633-
e[3]=Property(
676+
e[2] = Convert(
677+
e[3] = Property(
634678
p[0 // ([struct] System.Nullable<int> p)
635679
],
636680
typeof(System.Nullable<int>).GetTypeInfo().GetDeclaredProperty("Value")),
637681
typeof(System.Nullable<Enum1>)),
638-
e[4]=Constant(null, typeof(System.Nullable<Enum1>)),
682+
e[4] = Constant(null, typeof(System.Nullable<Enum1>)),
639683
typeof(System.Nullable<Enum1>)),
640684
p[0 // ([struct] System.Nullable<int> p)
641685
]);
@@ -647,7 +691,7 @@ public void Test_283_Case5_ConvertTests_NullableIntToNullableEnum_NullReferenceE
647691
Assert.That(fs(null), Is.EqualTo(null));
648692

649693
var fx = expr.CompileFast(true);
650-
fx.PrintIL();
694+
fx.PrintIL();
651695
Assert.That(fx(null), Is.EqualTo(null));
652696
}
653697

@@ -660,19 +704,19 @@ public void Test_283_Case4_SecurityVerificationException()
660704
var e = new Expression[1]; // the unique expressions
661705
var l = new LabelTarget[0]; // the labels
662706
var expr = Lambda<System.Func<int, string>>( // $
663-
e[0]=Call(
664-
p[0]=Parameter(typeof(int), "p"),
707+
e[0] = Call(
708+
p[0] = Parameter(typeof(int), "p"),
665709
typeof(int).GetMethods().Single(x => !x.IsGenericMethod && x.Name == "ToString" && x.GetParameters().Length == 0)),
666710
p[0 // (int p)
667711
]);
668712

669-
var fs = expr.CompileSys();
670-
fs.PrintIL();
671-
Assert.That(fs(1), Is.EqualTo("1"));
713+
var fs = expr.CompileSys();
714+
fs.PrintIL();
715+
Assert.That(fs(1), Is.EqualTo("1"));
672716

673-
var fx = expr.CompileFast(true);
674-
fx.PrintIL();
675-
Assert.That(fx(1), Is.EqualTo("1"));
717+
var fx = expr.CompileFast(true);
718+
fx.PrintIL();
719+
Assert.That(fx(1), Is.EqualTo("1"));
676720
}
677721

678722
[Test]
@@ -682,14 +726,14 @@ public void Test_283_Case3_SecurityVerificationException()
682726
var e = new Expression[2]; // the unique expressions
683727
var l = new LabelTarget[0]; // the labels
684728
var expr = Lambda<Func<SampleClass, int, string>>(
685-
e[0]=Property(
686-
e[1]=Call(
687-
p[0]=Parameter(typeof(SampleClass), "s"),
729+
e[0] = Property(
730+
e[1] = Call(
731+
p[0] = Parameter(typeof(SampleClass), "s"),
688732
typeof(SampleClass).GetMethods().Single(x => !x.IsGenericMethod && x.Name == "GetOther" && x.GetParameters().Select(y => y.ParameterType).SequenceEqual(new[] { typeof(int) })),
689-
p[1]=Parameter(typeof(int), "i")),
733+
p[1] = Parameter(typeof(int), "i")),
690734
typeof(OtherClass).GetTypeInfo().GetDeclaredProperty("OtherStrProp")),
691735
p[0 // (SampleClass s)
692-
],
736+
],
693737
p[1 // (int i)
694738
]);
695739

@@ -790,7 +834,7 @@ public void Test_283_Case2_Minimal_NullRefException()
790834
Convert(
791835
Convert(
792836
Field(
793-
Convert(p, typeof(c__DisplayClass6_0)),
837+
Convert(p, typeof(c__DisplayClass6_0)),
794838
typeof(c__DisplayClass6_0).GetField(nameof(c__DisplayClass6_0.flag))),
795839
typeof(System.Enum)),
796840
typeof(object)),
@@ -810,46 +854,59 @@ public void Test_283_Case2_Minimal_NullRefException()
810854
[Flags]
811855
public enum FlagsEnum
812856
{
813-
None = 0,
857+
None = 0,
814858

815-
Flag1 = 0x1,
816-
Flag2 = 0x2,
817-
Flag3 = 0x4,
859+
Flag1 = 0x1,
860+
Flag2 = 0x2,
861+
Flag3 = 0x4,
818862

819-
All = Flag1 | Flag2 | Flag3
863+
All = Flag1 | Flag2 | Flag3
820864
}
821865

822-
class c__DisplayClass6_0
866+
class c__DisplayClass6_0
823867
{
824868
public FlagsEnum flag = FlagsEnum.All;
825869
}
826870

827871
public delegate void SimpleDelegate(string input);
828872

873+
public class Dynamic
874+
{
875+
public delegate void SimpleDelegate(string input);
876+
}
877+
829878
public static void HandleString(string s)
830879
{
831880

832881
}
833882

834883
class SampleClass
835884
{
836-
public int Id { get; set; }
837-
public int Value { get; set; }
885+
public int Id { get; set; }
886+
public int Value { get; set; }
838887
public object Instance;
839888
public Delegate[] Delegates;
840889

841-
public OtherClass GetOther (int idx) => new OtherClass { OtherStrProp = "OtherStrValue" + idx };
890+
public OtherClass GetOther(int idx) => new OtherClass { OtherStrProp = "OtherStrValue" + idx };
842891

843892
public OtherClass GetOtherAnother(int idx) => new OtherClass { OtherStrProp = "OtherAnotherStrValue" + idx };
844893

894+
private SimpleDelegate _SimpleDelegateEvent;
895+
public event SimpleDelegate SimpleDelegateEvent
896+
{
897+
add => _SimpleDelegateEvent = (SimpleDelegate)Delegate.Combine(_SimpleDelegateEvent, value);
898+
remove => _SimpleDelegateEvent = (SimpleDelegate)Delegate.Remove (_SimpleDelegateEvent, value);
899+
}
900+
901+
845902
public SampleClass(object instance = null, Delegate[] delegates = null)
846903
{
847904
Instance = instance;
848905
Delegates = delegates;
849906
}
850907
}
851-
class OtherClass
852-
{
908+
class OtherClass
909+
{
853910
public string OtherStrProp { get; set; }
854911
}
855912

0 commit comments

Comments
 (0)