You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
ValueOption equality on expression trees causes crash #13370
I'm trying to have an expression tree to compare a struct with the same item, and it fails?
openSystemopenSystem.Linq.Expressions//let tester = Some "a" //works//let tester = Guid.NewGuid() //workslettester= ValueSome "b"//crashletequalExpr= Expression.Equal(Expression.Constant(tester), Expression.Constant(tester))//System.InvalidOperationException: The binary operator Equal is not defined for the types // 'Microsoft.FSharp.Core.FSharpValueOption`1[System.String]' and // 'Microsoft.FSharp.Core.FSharpValueOption`1[System.String]'.// at System.Linq.Expressions.Expression.GetEqualityComparisonOperator(ExpressionType binaryType, String opName, Expression left, Expression right, Boolean liftToNull)// at System.Linq.Expressions.Expression.Equal(Expression left, Expression right, Boolean liftToNull, MethodInfo method)
Ok,
I found a workaround that is enough good for me: I lie the types to the expression tree:
openSystemopenSystem.Linq.Expressions//let tester = Some "a" //works//let tester = Guid.NewGuid() //workslettester= ValueSome "b"letty= typeof<obj>letequalExpr= Expression.Equal(Expression.Constant(tester, ty), Expression.Constant(tester, ty))
Edit: Not very good solution if your expressions are not Constant.
An example of full stack is here:
System.InvalidOperationException: The binary operator Equal is not defined for the types 'Microsoft.FSharp.Core.FSharpValueOption`1[System.String]' and 'Microsoft.FSharp.Core.FSharpValueOption`1[System.String]'.
at System.Linq.Expressions.Expression.GetEqualityComparisonOperator(ExpressionType binaryType, String opName, Expression left, Expression right, Boolean liftToNull)
at System.Linq.Expressions.Expression.Equal(Expression left, Expression right, Boolean liftToNull, MethodInfo method)
at Microsoft.FSharp.Linq.RuntimeHelpers.LeafExpressionConverter.ConvExprToLinqInContext@364.Invoke(Tuple`2 tupledArg)
at Microsoft.FSharp.Linq.RuntimeHelpers.LeafExpressionConverter.ConvExprToLinqInContext(ConvEnv env, FSharpExpr inp) in D:\a\_work\1\s\src\fsharp\FSharp.Core\Linq.fs:line 364
at Microsoft.FSharp.Linq.RuntimeHelpers.LeafExpressionConverter.ConvExprToLinqInContext(ConvEnv env, FSharpExpr inp) in D:\a\_work\1\s\src\fsharp\FSharp.Core\Linq.fs:line 599
at Microsoft.FSharp.Primitives.Basics.List.mapToFreshConsTail[a,b](FSharpList`1 cons, FSharpFunc`2 f, FSharpList`1 x) in D:\a\_work\1\s\src\fsharp\FSharp.Core\local.fs:line 237
at Microsoft.FSharp.Primitives.Basics.List.map[T,TResult](FSharpFunc`2 mapping, FSharpList`1 x) in D:\a\_work\1\s\src\fsharp\FSharp.Core\local.fs:line 248
at Microsoft.FSharp.Linq.RuntimeHelpers.LeafExpressionConverter.ConvExprsToLinq(ConvEnv env, FSharpList`1 es) in D:\a\_work\1\s\src\fsharp\FSharp.Core\Linq.fs:line 689
at Microsoft.FSharp.Linq.RuntimeHelpers.LeafExpressionConverter.ConvExprToLinqInContext(ConvEnv env, FSharpExpr inp) in D:\a\_work\1\s\src\fsharp\FSharp.Core\Linq.fs:line 507
at Microsoft.FSharp.Primitives.Basics.List.map[T,TResult](FSharpFunc`2 mapping, FSharpList`1 x) in D:\a\_work\1\s\src\fsharp\FSharp.Core\local.fs:line 246
at Microsoft.FSharp.Linq.RuntimeHelpers.LeafExpressionConverter.ConvExprsToLinq(ConvEnv env, FSharpList`1 es) in D:\a\_work\1\s\src\fsharp\FSharp.Core\Linq.fs:line 689
at Microsoft.FSharp.Linq.RuntimeHelpers.LeafExpressionConverter.ConvExprToLinqInContext(ConvEnv env, FSharpExpr inp) in D:\a\_work\1\s\src\fsharp\FSharp.Core\Linq.fs:line 507
at Microsoft.FSharp.Linq.RuntimeHelpers.LeafExpressionConverter.ConvExprToLinqInContext(ConvEnv env, FSharpExpr inp) in D:\a\_work\1\s\src\fsharp\FSharp.Core\Linq.fs:line 599
at Microsoft.FSharp.Linq.RuntimeHelpers.LeafExpressionConverter.EvaluateQuotation(FSharpExpr e) in D:\a\_work\1\s\src\fsharp\FSharp.Core\Linq.fs:line 713
at Microsoft.FSharp.Linq.QueryModule.EvalNonNestedInner(CanEliminate canElim, FSharpExpr queryProducingSequence) in D:\a\_work\1\s\src\fsharp\FSharp.Core\Query.fs:line 1823
at Microsoft.FSharp.Linq.QueryModule.clo@1926-18.Microsoft.FSharp.Linq.ForwardDeclarations.IQueryMethods.Execute[a,b](FSharpExpr`1 q) in D:\a\_work\1\s\src\fsharp\FSharp.Core\Query.fs:line 1928
openSystem.Linqletdatasource1=[1;2].AsQueryable()// primary keyletdatasource2=[ValueSome 1; ValueSome 2].AsQueryable()//foreign key
query {for d1 in datasource1 dofor d2 in datasource2 do
where (ValueSome(d1)= d2)
select (d1, d2)}|> Seq.toList;;// System.InvalidOperationException: The binary operator Equal is not defined for the types 'Microsoft.FSharp.Core.FSharpValueOption`1[System.Int32]' and 'Microsoft.FSharp.Core.FSharpValueOption`1[System.Int32]
For this you should provide the F# equality operator as a custom operator into the Expression.Equals constructor. F#'s equality is different from C#'s equality and System.Linq.Expressions uses C# equality by default.
@Happypig375 will the Microsoft.FSharp.Linq.RuntimeHelpers.LeafExpressionConverter be using this custom operator constructor when you do F# Linq query?
Activity
Thorium commentedon Jun 23, 2022
Ok,
I found a workaround that is enough good for me: I lie the types to the expression tree:
Edit: Not very good solution if your expressions are not Constant.
An example of full stack is here:
Thorium commentedon Jun 24, 2022
More practical example:
Thorium commentedon Jul 12, 2022
The original issue can be reproduced with custom types:
In the case of LINQ it's often maintainability over performance, so I'd prefer some extra-boxing or whatever just to make things work correctly.
Edit: I move the another issue to separate issue
Happypig375 commentedon Jul 12, 2022
For this you should provide the F# equality operator as a custom operator into the Expression.Equals constructor. F#'s equality is different from C#'s equality and System.Linq.Expressions uses C# equality by default.
Happypig375 commentedon Jul 12, 2022
Happypig375 commentedon Jul 12, 2022
This issue can be closed as by design
Thorium commentedon Jul 12, 2022
@Happypig375 will the Microsoft.FSharp.Linq.RuntimeHelpers.LeafExpressionConverter be using this custom operator constructor when you do F# Linq query?
Happypig375 commentedon Jul 12, 2022
@Thorium Only after merging #11681. Currently, no.
T-Gro commentedon Dec 29, 2022
#11681 is merged, this can be closed (by design, solution exists)