Breaking Changes in Query Expression Fixes
AnonymousObject Structural Equality 🔴
AnonymousObject<T> types now implement Equals/GetHashCode with structural equality.
Impact: Code using these as Dictionary keys with identity semantics will see different behavior.
let a = AnonymousObject(1, 2)
let b = AnonymousObject(1, 2)
a.Equals(b) // Was: false, Now: true
Why: Fixes #7885, #47 - join/groupBy with tuple keys now work correctly.
Expression Tree Structure Changes 🟡
Let-bindings use Block instead of Lambda.Invoke
<@ let x = 1 in x + 1 @>
// Was: Lambda(x => x+1).Invoke(1)
// Now: Block({ x = 1; x + 1 })
Migration: If you detected let-bindings via Lambda.Invoke:
|
Array access uses ArrayIndex
<@ arr.[0] @>
// Was: Call(GetArray, arr, 0)
// Now: ArrayIndex(arr, 0)
Migration:
|
IQueryable Type Preservation 🟡
Tuple projections now preserve the provider's IQueryable type.
query { for p in db.Products do select (p.Id, p.Name) }
// Was: EnumerableQuery<_>
// Now: Provider's IQueryable<_>
Impact: Code checking is EnumerableQuery<_> may need adjustment.
FCS API: Query Variables 🟢
Query variables now report IsCompilerGenerated = true. Fixes #422 (FS1182 false positives).
val a: obj
val b: obj
System.Object.Equals(obj: obj) : bool
val x: int
val query: Linq.QueryBuilder
val p: obj
custom operation: select ('Result)
Calls Linq.QueryBuilder.Select
F# Compiler Guide