Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
202 commits
Select commit Hold shift + click to select a range
43f18c1
fix: preserve numeric conversion signedness and overflow checks
jogibear9988 Oct 18, 2026
4f62b8b
fix: emit nullable Boolean operators with three-valued logic
jogibear9988 Oct 18, 2026
5094310
fix: reject extension reductions that make no progress
jogibear9988 Oct 18, 2026
7d9dc02
fix: box value operands before emitting type tests
jogibear9988 Oct 18, 2026
7c6c022
test: run compatibility regressions on .NET Framework
jogibear9988 Oct 18, 2026
d71e945
fix: box constants declared as reference base types and interfaces
jogibear9988 Oct 18, 2026
d66f0ff
fix: unbox values converted from ValueType and nullable interfaces
jogibear9988 Oct 18, 2026
6670906
fix: load nullable arithmetic locals as values
jogibear9988 Oct 18, 2026
3f1f151
fix: preserve null when boxing nullable values to reference types
jogibear9988 Oct 18, 2026
33d02f6
fix: normalize nullable and wide array bounds before allocation
jogibear9988 Oct 18, 2026
9841ae4
fix: resolve lifted arithmetic operators on underlying operand types
jogibear9988 Oct 18, 2026
8f463e3
fix: emit unsigned division for unsigned arithmetic results
jogibear9988 Oct 18, 2026
83d24af
fix: emit lifted and method-based ones complement safely
jogibear9988 Oct 18, 2026
f3d08d8
fix: dereference by-ref operands when emitting conversions
jogibear9988 Oct 18, 2026
e3b5897
fix: emit typed and lifted increment and decrement operations
jogibear9988 Oct 18, 2026
0e4d224
fix: honor explicit methods for increment and decrement assignments
jogibear9988 Oct 18, 2026
a399994
fix: emit valid instance calls and index access on struct receivers
jogibear9988 Oct 18, 2026
2857b90
fix: preserve nullable and unsigned numeric comparison semantics
jogibear9988 Oct 18, 2026
2fb3a20
fix: convert both nullable coalesce branches to the result type
jogibear9988 Oct 18, 2026
c7d8e8a
fix: discard values and preserve control flow for void label targets
jogibear9988 Oct 18, 2026
fbd2e6c
test: use a portable explicit conversion oracle for coalesce
jogibear9988 Oct 18, 2026
2b4e054
fix: reuse lifted operator emission for unary increment and decrement
jogibear9988 Oct 18, 2026
b1970a1
fix: route typed jumps through their actual label targets
jogibear9988 Oct 18, 2026
b0a3678
fix: preserve reference identity in equality expressions
jogibear9988 Oct 18, 2026
eb008d4
fix: emit user-defined conditional logical operators
jogibear9988 Oct 18, 2026
0b6e1e1
fix: invoke coalesce conversion callbacks on non-null operands
jogibear9988 Oct 18, 2026
9c1d044
fix: honor custom Not methods in conditionals and interpretation
jogibear9988 Oct 18, 2026
50daf8b
fix: lift method-based Not and OnesComplement operands
jogibear9988 Oct 18, 2026
11f1b7a
fix: preserve original boxed constant identity in reference contexts
jogibear9988 Oct 18, 2026
338c4c4
fix: honor explicit binary methods in arithmetic and compound assignment
jogibear9988 Oct 18, 2026
476a3c4
feat: compile exact runtime TypeEqual tests in the existing emitter
jogibear9988 Oct 18, 2026
7d855d4
fix: apply compound assignment conversions before nullable writeback
jogibear9988 Oct 18, 2026
ce6ba47
refactor: reuse comparison operand emission for reference identity
jogibear9988 Oct 18, 2026
29862c2
test: skip compiler-layout assertions only after strict behavior vali…
jogibear9988 Oct 18, 2026
368a270
fix: spill compound assignment targets around complex right operands
jogibear9988 Oct 18, 2026
88b8878
fix: preserve checked overflow and nullable negation semantics
jogibear9988 Oct 18, 2026
4b9e317
fix: evaluate nullable arithmetic right operands before null propagation
jogibear9988 Oct 18, 2026
bc31076
fix: preserve pending arithmetic values around nested exception blocks
jogibear9988 Oct 18, 2026
74b95d1
fix: honor truth operator methods and nullable IsFalse semantics
jogibear9988 Oct 18, 2026
47a4909
fix: narrow checked short arithmetic results with overflow detection
jogibear9988 Oct 18, 2026
1fcafbc
fix: constrain integer switch tables to valid unique 32-bit indices
jogibear9988 Oct 18, 2026
80b5c9b
fix: preserve comparison methods and identity through conditional red…
jogibear9988 Oct 18, 2026
4ba7a28
fix: lift shifts with nullable counts and nonnullable left operands
jogibear9988 Oct 18, 2026
5224211
fix: resolve nonpublic delegate Invoke methods
jogibear9988 Oct 18, 2026
d453cdd
fix: check null reference receivers for nonvirtual instance calls
jogibear9988 Oct 18, 2026
9eaa4cf
fix: copy readonly value fields before calling mutating members
jogibear9988 Oct 18, 2026
075a19f
fix: address multidimensional array elements for value member access
jogibear9988 Oct 18, 2026
8f946f4
fix: invoke custom unary-plus methods instead of returning the operand
jogibear9988 Oct 18, 2026
f664afa
fix: pass addresses to explicit ref-parameter conversion methods
jogibear9988 Oct 18, 2026
411c217
fix: make invocation results addressable for ref arguments
jogibear9988 Oct 18, 2026
c3fc865
fix: preserve direct value-type calls through ref receivers
jogibear9988 Oct 18, 2026
32bee09
fix: preserve decimal constant sign and scale
jogibear9988 Oct 18, 2026
1690477
fix: lift user-defined conditional logical operators
jogibear9988 Oct 18, 2026
77c6fc1
feat: emit guarded exception filters in the existing try emitter
jogibear9988 Oct 18, 2026
03b168d
fix: spill delegate targets and arguments around exception regions
jogibear9988 Oct 18, 2026
80dd80c
fix: spill index receivers and arguments around exception regions
jogibear9988 Oct 18, 2026
8243674
fix: discard unused list initializer Add results
jogibear9988 Oct 18, 2026
cfffb6a
fix: preserve strict filter rejection on .NET Framework
jogibear9988 Oct 18, 2026
e0fc886
test: make regression oracles portable to .NET Framework
jogibear9988 Oct 18, 2026
febef69
fix: load writable boxed capture addresses for ref arguments
jogibear9988 Oct 18, 2026
a3ee56c
fix: initialize static members without instance operands
jogibear9988 Oct 18, 2026
c2bc56e
fix: spill array bounds and initializer values around exception regions
jogibear9988 Oct 18, 2026
4f62e15
fix: spill list initializer operands around exception regions
jogibear9988 Oct 18, 2026
1ae2221
fix: spill member initializer receivers and binding values around exc…
jogibear9988 Oct 18, 2026
9f2038f
fix: share constructor argument spilling for intrinsic expression nodes
jogibear9988 Oct 18, 2026
67e9557
test: exclude proven system compiler layout assertions with reasons
jogibear9988 Oct 18, 2026
efe9a2b
fix: emit actual array accessors for rank-one non-vector arrays
jogibear9988 Oct 18, 2026
445542b
feat: emit capture-free quotes and empty runtime-variable views
jogibear9988 Oct 18, 2026
d138b46
fix: compile direct quoted lambda invocations through existing emitters
jogibear9988 Oct 18, 2026
3744234
feat: emit nested member and list initializer bindings
jogibear9988 Oct 18, 2026
a10b092
fix: preserve typed ref arguments and property copyback across calls
jogibear9988 Oct 18, 2026
999bee5
fix: preserve readonly copies and typed static field addresses
jogibear9988 Oct 18, 2026
1c14285
fix: preserve non-runtime Type constant identities
jogibear9988 Oct 18, 2026
fb073b5
fix: reduce custom expression node types through the standard contract
jogibear9988 Oct 18, 2026
a5d3120
test: cover quoted lambda indexer arguments
jogibear9988 Oct 18, 2026
c50f3cb
fix: preserve runtime switch test evaluation and void results
jogibear9988 Oct 18, 2026
c7718d7
test: temporarily defer the known deep-expression stack crash
jogibear9988 Oct 18, 2026
e5f960b
test: exclude the now-verified inline-ref IL layout oracle
jogibear9988 Oct 18, 2026
c41f135
fix: reject abstract constructor calls before returning a delegate
jogibear9988 Oct 18, 2026
23515ee
fix: preserve quotation identity across nested Light compilation
jogibear9988 Oct 18, 2026
1b2e9b4
test: retain Framework FEC behavior checks when its system oracle is …
jogibear9988 Oct 18, 2026
e73b433
test: verify Framework ref-call semantics without invalid system oracles
jogibear9988 Oct 18, 2026
10dd9c4
test: verify nested initializer behavior before excluding system IL o…
jogibear9988 Oct 18, 2026
1a6c2da
fix: preserve writable Unbox and runtime array receiver storage
jogibear9988 Oct 18, 2026
65f979e
fix: prepare ref arguments using their formal storage types
jogibear9988 Oct 18, 2026
8a3b8d2
fix: reject lambda signatures that exceed the method parameter limit
jogibear9988 Oct 18, 2026
eb47858
Report duplicate label definitions with InvalidOperationException
jogibear9988 Oct 18, 2026
5cbeff5
test: separate verified FEC behavior from System representation asser…
jogibear9988 Oct 18, 2026
42212ba
fix: preserve the full character width through managed references
jogibear9988 Oct 18, 2026
9ef4999
Preserve value payloads on Light continue gotos
jogibear9988 Oct 18, 2026
a4122e8
fix: validate abstract constructors in nested Light lambdas
jogibear9988 Oct 18, 2026
623a512
test: verify behavior before excluding interpreter representation ass…
jogibear9988 Oct 18, 2026
b587c27
Validate rethrow and catch filter scopes during collection
jogibear9988 Oct 18, 2026
87c96ce
Validate jumps across exception region boundaries
jogibear9988 Oct 18, 2026
6f07aa6
Support invoking runtime expression-tree values
jogibear9988 Oct 18, 2026
afa7116
Load invocation receivers by value before calling them
jogibear9988 Oct 18, 2026
b46acc1
test: register remaining compatibility regressions in both runners
jogibear9988 Oct 18, 2026
ee485bc
fix: spill invocation operands across argument jumps
jogibear9988 Oct 18, 2026
cc0a649
Bind reused label targets within sibling block scopes
jogibear9988 Oct 18, 2026
a026282
Reject label redefinition inside an active default expression
jogibear9988 Oct 18, 2026
7bce53d
test: register scoped labels and exercise both invocation modes
jogibear9988 Oct 18, 2026
5c35381
Compile dynamic expressions through per-occurrence DLR call sites
jogibear9988 Oct 18, 2026
96e7b99
Keep rethrow validation inside inlined lambda boundaries
jogibear9988 Oct 18, 2026
79662b6
Propagate argument jumps through enclosing calls and constructors
jogibear9988 Oct 18, 2026
5602638
Defer runtime expression compilation for structural argument spills
jogibear9988 Oct 18, 2026
81c9d6e
Keep argument-local returns inside inlined invocation wrappers
jogibear9988 Oct 18, 2026
87db9c9
Keep stateful dynamic sites distinct across nested lambda occurrences
jogibear9988 Oct 18, 2026
f964559
Preserve argument-local returns in computed delegate invocations
jogibear9988 Oct 18, 2026
abd760c
test: register final dynamic and invocation compatibility regressions
jogibear9988 Oct 18, 2026
1dd9eaa
fix: propagate the trimming contract to argument spill metadata
jogibear9988 Oct 18, 2026
5698585
Preserve physical method tail returns across scoped label definitions
jogibear9988 Oct 18, 2026
072dd9d
test: run method-tail return regressions in every native runner
jogibear9988 Oct 18, 2026
89d649f
test: keep by-ref spill behavior checks on Framework
jogibear9988 Oct 18, 2026
9b8eadb
Make exception validation test oracles portable to Framework
jogibear9988 Oct 18, 2026
6b26169
fix: restore the declaring variable scope when leaving nested blocks
jogibear9988 Oct 18, 2026
82694e8
fix: duplicate only the final assignment field address
jogibear9988 Oct 18, 2026
416df4e
feat: bind captured quotes and runtime variables to shared typed cells
jogibear9988 Oct 18, 2026
b58ab0c
test: verify shared struct-cell IL after executing its behavior
jogibear9988 Oct 18, 2026
e48563f
test: retain Framework filter rejection while checking catch quote cells
jogibear9988 Oct 18, 2026
b28dd57
fix: keep struct operator operands separate from receiver addresses
jogibear9988 Oct 18, 2026
93aae6b
test: account for Framework System quote block typing
jogibear9988 Oct 18, 2026
1407d63
fix: validate lexical scope of label jumps
jogibear9988 Oct 18, 2026
87dc022
Verify runtime-variable spill behavior before excluding IL snapshots
jogibear9988 Oct 18, 2026
4d407c6
Keep unary and conversion operands in value contexts
jogibear9988 Oct 18, 2026
2f139b2
Test FEC rejection contracts for irreducible expression nodes
jogibear9988 Oct 18, 2026
4b823a6
Classify interpreter-specific runtime assertions with compiled behavi…
jogibear9988 Oct 18, 2026
d42ac98
Fix non-Exception catch policy for generated methods
jogibear9988 Oct 18, 2026
3218de4
Preserve original string constant reference identity
jogibear9988 Oct 18, 2026
07da616
Keep Framework boxed receivers verifiable during argument spills
jogibear9988 Oct 18, 2026
f66ab50
Reuse collected delegate invocation parameters
jogibear9988 Oct 19, 2026
358d262
Avoid eager scope and exception metadata allocations on label-free paths
jogibear9988 Oct 19, 2026
3f3f936
Reuse collected reductions for dynamic and quoted extension nodes
jogibear9988 Oct 19, 2026
17468e7
Reuse hoisted capture reflection metadata within each compilation
jogibear9988 Oct 19, 2026
b7e206e
Keep lazy JIT with anonymous catch policy on modern runtimes
jogibear9988 Oct 19, 2026
f22b52a
Keep provably readonly captures in existing value closure slots
jogibear9988 Oct 19, 2026
c5f2709
Fold immutable constant string lengths without capturing string storage
jogibear9988 Oct 19, 2026
b12741c
Reuse transient scope buffers and skip terminal-node scope tracking
jogibear9988 Oct 19, 2026
8f8a96d
Analyze capture storage mutations once per compilation root
jogibear9988 Oct 19, 2026
92cc495
Reuse capture call signatures and avoid cells for value arguments
jogibear9988 Oct 19, 2026
7bf6b3d
Collect switch test values without enumerator allocations
jogibear9988 Oct 19, 2026
267707c
Allocate hoisted type cache only for actual shared cells
jogibear9988 Oct 19, 2026
fcacccb
Identify vector arrays directly on modern runtimes
jogibear9988 Oct 19, 2026
d3680f1
Keep lexical and exception ancestry in inline indexed metadata
jogibear9988 Oct 19, 2026
f785b15
Collect terminal expression nodes before tracking lexical scopes
jogibear9988 Oct 19, 2026
6348d05
Keep quote and dynamic emission maps off ordinary compiler contexts
jogibear9988 Oct 19, 2026
9817968
Allocate invocation spill metadata only for arguments with jumps
jogibear9988 Oct 19, 2026
a1e2591
Preserve readonly capture layout through control flow and initializers
jogibear9988 Oct 19, 2026
76f5677
Keep primitive arithmetic emission outside lifted-operation handling
jogibear9988 Oct 19, 2026
9fbac74
Track capture slot writes precisely and scan simple initializers once
jogibear9988 Oct 19, 2026
bdbe35c
Reuse cleared capture metadata rentals and resolve constructor handles
jogibear9988 Oct 19, 2026
752d1d3
Cover captures alongside static indexed property access
jogibear9988 Oct 19, 2026
e848d1a
Skip scoped label helpers while emitting label-free blocks
jogibear9988 Oct 19, 2026
271c8c2
Share root capture analysis before propagating nested parameters
jogibear9988 Oct 19, 2026
9c3b069
Remove exception cleanup regions from internal collector recursion
jogibear9988 Oct 19, 2026
1551a28
Keep common scope compression and unchanged-depth returns inline
jogibear9988 Oct 19, 2026
64bce73
Avoid primitive arithmetic spills for atomic operands after EH
jogibear9988 Oct 19, 2026
1ed3e68
Inline the empty capture-parameter cache path
jogibear9988 Oct 19, 2026
ffcfafd
Reuse operand types in scalar arithmetic emission
jogibear9988 Oct 19, 2026
246e762
Keep private mutable reference captures in their sole child value slot
jogibear9988 Oct 19, 2026
713301f
Use native boxed storage for live nonnullable value captures
jogibear9988 Oct 19, 2026
2e402d6
Recognize only known intrinsic storage shapes before capture emission
jogibear9988 Oct 19, 2026
ee95767
Cover live boxed struct receivers with exception-block call arguments
jogibear9988 Oct 19, 2026
f6f82ee
Keep Framework mutable captures in verifiable typed cells
jogibear9988 Oct 19, 2026
60b5c8a
Exercise hoisted metadata overflow clearing with native boxed captures
jogibear9988 Oct 19, 2026
4272a67
Batch collection of consecutive single-expression block scopes
jogibear9988 Oct 19, 2026
aedb5d2
Reuse the initial node type during collection
jogibear9988 Oct 19, 2026
aa8860c
Avoid root capture scans when typed storage is already required
jogibear9988 Oct 19, 2026
937afc4
Reuse private reference slots through constructor and array containers
jogibear9988 Oct 19, 2026
bc32616
Establish the actual capture-analysis root before intrinsic collection
jogibear9988 Oct 19, 2026
bb70eb4
Avoid materializing Light array operands during private capture analysis
jogibear9988 Oct 19, 2026
2177b3b
Restore typed reference loads for verified Framework closure slots
jogibear9988 Oct 19, 2026
7d399c9
Defer quote and runtime-variable metadata on unrelated compilation paths
jogibear9988 Oct 19, 2026
7b821ae
Declare trimming requirement for lazy quote metadata holder
jogibear9988 Oct 19, 2026
529ae3f
Keep scope overflow arrays in compact geometric pool buckets
jogibear9988 Oct 19, 2026
e255ce1
Skip empty jump validators on jump-free expression trees
jogibear9988 Oct 19, 2026
0caf756
Reduce Framework capture constructor metadata allocations
jogibear9988 Oct 19, 2026
9f128dd
Type Framework capture parameters in existing rented signatures
jogibear9988 Oct 19, 2026
b1bad48
Avoid the full collector for terminal binary roots
jogibear9988 Oct 19, 2026
7cebdbe
Use boxed Framework value cells in proven owned roots
jogibear9988 Oct 19, 2026
56635f6
Avoid redundant Framework delegate casts in proven owned roots
jogibear9988 Oct 19, 2026
9e04dbb
Restore owned Framework capture slot loads without extra casts
jogibear9988 Oct 19, 2026
26cf73a
Avoid arithmetic operand spills when the right side cannot enter EH
jogibear9988 Oct 19, 2026
0e3a630
Materialize try results before using struct receiver addresses
jogibear9988 Oct 19, 2026
aec2324
test: cover upstream SmallMap promotion with colliding keys
jogibear9988 Oct 19, 2026
e75e6a4
Use the supported anonymous DynamicMethod constructor for exception-a…
jogibear9988 Oct 19, 2026
cd25301
Explain scope pool buckets and outlined frame growth
jogibear9988 Oct 19, 2026
170389b
Cover opaque quotes and pruned invocation spill ordering
jogibear9988 Oct 19, 2026
79197e8
fix: recognize converted simple arithmetic operands without bypassing…
jogibear9988 Oct 24, 2026
dd98968
docs: consolidate compatibility and performance validation records
jogibear9988 Oct 25, 2026
e496d42
bench: establish frozen compilation and invocation performance baseline
jogibear9988 Oct 18, 2026
dc5033a
perf: avoid enumerating fields for named LightExpression lookup
jogibear9988 Oct 18, 2026
77d51ba
bench: baseline conditional comparison branches before optimization
jogibear9988 Oct 18, 2026
c004af6
test: record repeated performance evidence and compatibility validation
jogibear9988 Oct 18, 2026
efc51ff
docs: update performance measurement publication status
jogibear9988 Oct 18, 2026
baa0f5a
bench: compare master, compatibility fixes and rebased performance layer
jogibear9988 Oct 24, 2026
be513de
docs: distinguish measured stack from subsequent upstream changes
jogibear9988 Oct 24, 2026
2bed9d8
test: cover upstream constructor signature pool reuse
jogibear9988 Oct 24, 2026
51305fa
perf: collect terminal binary operands without recursive dispatch
jogibear9988 Oct 24, 2026
00af81b
bench: compare master and both PR stages through first invocation
jogibear9988 Oct 24, 2026
93af41d
docs: validate performance stack on rewritten PR 558
jogibear9988 Oct 25, 2026
7be7c4b
docs: remove obsolete branch performance measurements
jogibear9988 Oct 25, 2026
7133ad8
docs: report only current master and PR 558/559 performance
jogibear9988 Oct 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 23 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ Moreover the compiled delegate may be slower than the manually created delegate
_TL;DR;_
> Expression.Compile creates a DynamicMethod and associates it with an anonymous assembly to run it in a sand-boxed environment. This makes it safe for a dynamic method to be emitted and executed by partially trusted code but adds some run-time overhead.

FEC keeps owned DynamicMethods for ordinary lambdas. Methods containing exception regions use anonymous hosting to match System's non-Exception throw and catch policy. The APIs that skip collection also use anonymous hosting, because their exception regions are unknown before emission. Anonymous hosting adds eager JIT work when creating the delegate. `CompileFastToIL` inherits the host policy of the caller's method.

See also [a deep dive to Delegate internals](https://mattwarren.org/2017/01/25/How-do-.NET-delegates-work/#different-types-of-delegates).


Expand Down Expand Up @@ -263,17 +265,34 @@ var x = f(new B());
The idea is to provide the fast compilation for the supported expression types
and fallback to the system `Expression.Compile()` for the not supported types:

Invoking a runtime `System.Linq.Expressions.Expression<TDelegate>` value compiles that value
with its `Compile()` method before invoking the resulting delegate, as the system compiler does.
This runtime operation is distinct from compilation fallback: with
`CompileFast(ifFastFailedReturnNull: true)`, FEC still compiles the surrounding lambda directly.
Errors from compiling or executing the runtime expression propagate to its caller.
Ref-property arguments retain FEC's normal setter copyback after successful invocation.
The system compiler can lose this copyback when another argument contains an exception
block; FEC preserves the property mutation instead of reproducing that behavior.

Dynamic expressions use ordinary DLR call sites: each emitted occurrence has its own site,
reuses binding rules, and reads the current mutable `Target` for every invocation.
Runtime binder rule compilation is intrinsic DLR behavior; the outer lambda still compiles directly with FEC.

Quoted lambdas and `RuntimeVariables` share live typed cells with compiled outer and sibling lambdas.
Mutations remain visible after the creating method returns; independent activations keep separate storage.
Capture-free quoted trees retain their original identity. The closure arrays and direct IL emitter remain in use.

### What's not supported yet

**FEC does not support yet:**

- `Quote`
- `Dynamic`
- `RuntimeVariables`
- Captures of by-ref parameters, pointer types, or byref-like values that cannot be stored in a heap cell
- Reused physical method-tail labels reached with pending operand values or from protected exception regions (strict null / `NotSupported_MethodReturn_Context`)
- `DebugInfo`
- `MemberInit` with the `MemberMemberBinding` and the `ListMemberBinding` binding types
- `NewArrayInit` multi-dimensional array initializer is not supported yet

Nested `MemberInit` member and list bindings are supported. Very deep expression trees still have a known recursive traversal limit; see the [runtime compatibility results](test/FastExpressionCompiler.DotNetRuntimeTests/results/fixes/README.md).

To find what nodes are not supported in your expression you may use the technic described below in the [Diagnostics](#diagnostics) section.

The compilation is done by traversing the expression nodes and emitting the IL.
Expand Down
74 changes: 49 additions & 25 deletions src/FastExpressionCompiler.LightExpression/Expression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1248,21 +1248,22 @@ public static ElementInit ElementInit(MethodInfo addMethod, params Expression[]
public static ElementInit ElementInit(MethodInfo addMethod, IEnumerable<Expression> arguments) =>
ElementInit(addMethod, arguments.AsReadOnlyList());

[RequiresUnreferencedCode(Trimming.Message)]
// The outer tree still consists of LightExpression nodes. A parameter or constant
// may hold a System Expression<TDelegate> as runtime data; Invoke compiles that
// value and invokes its delegate. This does not mix System nodes into the tree.
private static Type GetInvocationReturnType(Expression expression) =>
expression is LambdaExpression directLambda ? directLambda.ReturnType :
expression is UnaryExpression quote && quote.NodeType == ExpressionType.Quote && quote.Operand is LambdaExpression lambda
? lambda.ReturnType
: (expression.Type.FindExpressionCompileMethod()?.ReturnType ?? expression.Type).FindDelegateInvokeMethod().ReturnType;

public static InvocationExpression Invoke(LambdaExpression expression) =>
new NotNullExpressionInvocationExpression(expression);

public static InvocationExpression Invoke(LambdaExpression expression, Expression a0) =>
new OneArgumentInvocationExpression(expression, a0);

[MethodImpl((MethodImplOptions)256)]
[RequiresUnreferencedCode(Trimming.Message)]
private static Type GetInvocationReturnType(Expression expression) =>
expression is LambdaExpression lambda
? lambda.ReturnType
: expression is UnaryExpression unExpr && unExpr.NodeType == ExpressionType.Quote && unExpr.Operand is LambdaExpression quotedLambda
? quotedLambda.ReturnType
: expression.Type.FindDelegateInvokeMethod().ReturnType;

[RequiresUnreferencedCode(Trimming.Message)]
public static InvocationExpression Invoke(Expression expression, Expression a0) =>
expression is LambdaExpression
Expand Down Expand Up @@ -1475,12 +1476,13 @@ public static BinaryExpression Modulo(Expression left, Expression right, MethodI
GetArithmeticBinary(ExpressionType.Modulo, left, right, method);

/// <summary>Creates a BinaryExpression that represents a bitwise right-shift operation.</summary>
[RequiresUnreferencedCode(Trimming.Message)]
public static BinaryExpression RightShift(Expression left, Expression right) =>
new LeftTypedBinaryExpression(ExpressionType.RightShift, left, right);
GetShiftBinary(ExpressionType.RightShift, left, right);

/// <summary>Creates a BinaryExpression that represents a bitwise right-shift operation.</summary>
[RequiresUnreferencedCode(Trimming.Message)]
public static BinaryExpression RightShift(Expression left, Expression right, MethodInfo method) => GetLeftTypedBinary(ExpressionType.RightShift, left, right, method);
public static BinaryExpression RightShift(Expression left, Expression right, MethodInfo method) => GetShiftBinary(ExpressionType.RightShift, left, right, method);

/// <summary>Creates a BinaryExpression that represents an arithmetic subtraction operation that does not have overflow checking.</summary>
[RequiresUnreferencedCode(Trimming.Message)]
Expand Down Expand Up @@ -1552,9 +1554,9 @@ public static BinaryExpression And(Expression left, Expression right) =>

/// <summary>Creates a BinaryExpression that represents a conditional AND operation that evaluates the second operand only if the first operand evaluates to true.</summary>
public static BinaryExpression AndAlso(Expression left, Expression right) =>
left.Type == typeof(bool?)
? new LeftTypedBinaryExpression(ExpressionType.AndAlso, left, right)
: new LogicalBinaryExpression(ExpressionType.AndAlso, left, right);
left.Type == typeof(bool)
? new LogicalBinaryExpression(ExpressionType.AndAlso, left, right)
: new LeftTypedBinaryExpression(ExpressionType.AndAlso, left, right);

/// <summary>Creates a BinaryExpression that represents a conditional AND operation that evaluates the second operand only if the first operand evaluates to true.</summary>
[RequiresUnreferencedCode(Trimming.Message)]
Expand All @@ -1578,9 +1580,9 @@ public static BinaryExpression GetLogicalBinary(ExpressionType nodeType, Express

/// <summary>Creates a BinaryExpression that represents a conditional OR operation that evaluates the second operand only if the first operand evaluates to false.</summary>
public static BinaryExpression OrElse(Expression left, Expression right) =>
left.Type == typeof(bool?)
? new LeftTypedBinaryExpression(ExpressionType.OrElse, left, right)
: new LogicalBinaryExpression(ExpressionType.OrElse, left, right);
left.Type == typeof(bool)
? new LogicalBinaryExpression(ExpressionType.OrElse, left, right)
: new LeftTypedBinaryExpression(ExpressionType.OrElse, left, right);

/// <summary>Creates a BinaryExpression that represents a conditional OR operation that evaluates the second operand only if the first operand evaluates to false.</summary>
[RequiresUnreferencedCode(Trimming.Message)]
Expand Down Expand Up @@ -2909,6 +2911,13 @@ internal static Expression ConvertToLightExpression(SysExpr sysExpr, ref SmallLi
vars[i] = (ParameterExpression)sysVars[i].ToLightExpression(ref exprsConverted);
return new RuntimeVariablesExpression(vars);
}
case ExpressionType.TypeIs:
case ExpressionType.TypeEqual:
var typeTest = (System.Linq.Expressions.TypeBinaryExpression)sysExpr;
var tested = typeTest.Expression.ToLightExpression(ref exprsConverted);
return nodeType == ExpressionType.TypeIs
? Expression.TypeIs(tested, typeTest.TypeOperand)
: Expression.TypeEqual(tested, typeTest.TypeOperand);
case ExpressionType.DebugInfo:
{
var die = (System.Linq.Expressions.DebugInfoExpression)sysExpr;
Expand Down Expand Up @@ -3035,12 +3044,25 @@ internal static PropertyInfo FindProperty(this Type type, string propertyName)
[RequiresUnreferencedCode(Trimming.Message)]
internal static FieldInfo FindField(this Type type, string fieldName)
{
var fields = type.GetTypeInfo().DeclaredFields.AsArray();
for (var i = 0; i < fields.Length; i++)
if (fields[i].Name == fieldName)
return fields[i];
var info = type.GetTypeInfo();
if (fieldName == null)
return null;
try
{
var field = info.GetDeclaredField(fieldName);
if (field != null)
return field;
}
catch (AmbiguousMatchException)
{
// CLR metadata can contain same-name fields with different types. Preserve
// the existing first-declared-match behavior for such non-C# types.
foreach (var field in info.DeclaredFields)
if (field.Name == fieldName)
return field;
}

return type.GetTypeInfo().BaseType?.FindField(fieldName);
return info.BaseType?.FindField(fieldName);
}

internal const BindingFlags InstanceMethods = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
Expand Down Expand Up @@ -3515,7 +3537,8 @@ public bool IsLifted
[RequiresUnreferencedCode(Trimming.Message)]
get =>
NodeType != ExpressionType.Coalesce & NodeType != ExpressionType.Assign &&
Left.Type.IsNullable() &&
(Left.Type.IsNullable() ||
(NodeType == ExpressionType.LeftShift || NodeType == ExpressionType.RightShift) && Right.Type.IsNullable()) &&
(Method == null || !Method.GetParameters()[0].ParameterType.GetNonRef().IsEquivalentTo(Left.Type));
}

Expand Down Expand Up @@ -5956,18 +5979,19 @@ internal TypedReturnManyParametersExpression(Expression body, IReadOnlyList<Para
: base(body, parameters) => ReturnType = returnType;
}

// todo: @feature is not supported yet
public sealed class DynamicExpression : Expression
{
public override ExpressionType NodeType => ExpressionType.Dynamic;
public override Type Type => typeof(object);
public override Type Type { get; }
public Type DelegateType { get; }
public CallSiteBinder Binder { get; }
public IReadOnlyList<Expression> Arguments { get; }

[RequiresUnreferencedCode(Trimming.Message)]
public DynamicExpression(Type delegateType, CallSiteBinder binder, IReadOnlyList<Expression> arguments)
{
DelegateType = delegateType;
Type = delegateType.FindDelegateInvokeMethod().ReturnType;
Binder = binder;
Arguments = arguments;
}
Expand Down
Loading
Loading