Conversation
…b API Adds the new Hyperbee.ExpressionCompiler class library (net8.0;net9.0;net10.0) with HyperbeeCompiler static API (Compile, TryCompile, CompileWithFallback) and HyperbeeCompilerExtensions. All methods are stubs; TryCompile returns null so CompileWithFallback falls back to Expression.Compile(). Updates solution file.
…/constant/conditional tests
Add the foundational IR types for the Hyperbee expression compiler: - IROp enum with all opcodes for Phase 1+ compilation - IRInstruction readonly struct for cache-friendly instruction storage - IRBuilder with instruction stream, operand table, locals, and labels - LocalInfo and LabelInfo readonly record structs for metadata
Single-pass expression tree visitor that lowers to flat IR instructions. Supports constants, parameters, binary/unary ops, method calls, conditionals (ternary + IfThen), member access, new objects, blocks, assignment, default, type conversions, short-circuit logic, and operator overloads. Unsupported types throw NotSupportedException.
1:1 mapping from IR opcodes to CIL via ILGenerator. Handles all Phase 1 operations including arithmetic, checked variants, comparisons, conversions, method calls, branching, fields, boxing/unboxing, and non-embeddable constants loaded from a closure object[] array. Uses short-form opcodes for locals 0-3 and args 0-3.
…ests Complete the compiler pipeline: expression tree pre-scan for non-embeddable constants, lowering to IR, IL emission via DynamicMethod, and delegate creation. TryCompile now returns a working delegate for all Phase 1 patterns. All 81 compiler tests and 6 issue regression tests pass across net8.0, net9.0, and net10.0.
…/throw/goto/label - Add Leave IROp for exiting try/catch blocks - Implement TryCatch/Throw/Rethrow/Goto/Label lowering in ExpressionLowerer - Add StackSpillPass to convert Branch to Leave at exception boundaries - Update ILEmissionPass with BeginTry/BeginCatch/BeginFinally/EndTryCatch/Throw/Rethrow/Leave emission - Wire StackSpillPass into HyperbeeCompiler pipeline between lowering and emission - Extend NeedsConstantsArray scanner for TryExpression/GotoExpression/LabelExpression - Add 62 exception handling tests (basic try/catch, typed catch, catch variable, try/catch/finally, throw/rethrow, goto/label, void try, nested try, value results) - Add 4 HyperbeeCompiler.Compile native tests for Pattern 1 and Pattern 2 in IssueTests - All 143 Compiler.Tests + 10 IssueTests pass on net8.0/net9.0/net10.0
LowerToIR, RunPasses, EmitDelegate each own a single responsibility. Removes stale rationale comments and dead NeedsConstantsArray wrapper.
…nd nested lambdas Implement support for Expression.Lambda and Expression.Invoke with captured variables using the StrongBox<T> pattern: - Add CaptureScanner to detect variables captured by nested lambdas - Extend ExpressionLowerer with Lambda/Invoke handling and StrongBox access for captured variables (load via LoadField, store via StoreField) - Rewrite inner lambdas to accept StrongBox<T> parameters and compile with System compiler, enabling shared mutable state between outer and inner delegates - Update HyperbeeCompiler to integrate capture scanning before lowering - Add ScanForNonEmbeddableConstants support for Lambda/Invoke nodes - Add ClosureTests with 12 test cases covering no-capture, single capture, multiple captures, mutable captures, and mixed scenarios - Add native HyperbeeCompiler.Compile tests for Pattern 3 in FecKnownIssues (no longer needs CompileWithFallback) All 167 compiler tests + 12 issue tests pass across net8.0/net9.0/net10.0.
…ction init, coalesce, quote Add support for all remaining expression types to make HyperbeeCompiler a drop-in replacement for Expression.Compile(): Lowering (ExpressionLowerer): - Loop expressions with break/continue labels - Switch expressions with int/string cases, multiple test values, custom comparison - NewArrayInit and NewArrayBounds (single and multi-dimensional) - ArrayIndex (binary), ArrayLength (unary), Index (indexer property or array) - ListInit (List, Dictionary collection initializers) - MemberInit (property and field assignment bindings) - Coalesce (null coalescing for reference types and nullable value types) - TypeEqual (exact type match via GetType() == typeof(T)) - Quote (expression tree as data) - Power (Math.Pow) - Unbox (unbox.any) - DebugInfo (no-op) IL emission (ILEmissionPass): - NewArray (newarr), LoadElement/StoreElement (typed ldelem/stelem variants) - LoadArrayLength (ldlen + conv.i4), LoadAddress (ldloca) Also fixes void conditional handling in full ternary path to pop non-void results when the conditional type is void. 60 new tests across 6 test files, all passing on net8.0/net9.0/net10.0.
…eduction, benchmark updates Add PeepholePass with 7 peephole patterns: StoreLocal/LoadLocal to Dup/StoreLocal, dead load elimination (LoadConst/Pop, LoadNull/Pop, LoadLocal/Pop), identity Box/UnboxAny removal, Dup/Pop elimination, and branch-to-fallthrough removal. Reduce allocations: pre-size IRBuilder lists and ExpressionLowerer dictionaries, optimize BuildConstantsMapping from O(operands*instructions) to O(operands+instructions) using a HashSet pre-scan. Update benchmarks to use HyperbeeCompiler.Compile directly (no fallback needed) and add Loop and Switch tier benchmarks. Results show Hyperbee within 1.3-1.8x of FEC compilation speed and 8-30x faster than System compiler.
… bugs CompilerType.Hyperbee was using CompileWithFallback which silently fell back to the System compiler on any failure, masking all bugs. Changed to use HyperbeeCompiler.Compile directly. Fixed lowering bugs exposed by removing fallback: - LowerDefault: removed broken InitObj+StoreLocal pattern, use zero-initialized local - LowerConditional: non-void ternary stores branch results to temp local - LowerAndAlso/OrElse: replaced Dup across labels with result-local pattern - LowerCoalesce: rewrote both nullable and reference paths with temp locals - Added ExpressionType.Increment/Decrement to unary handler - NewExpression without constructor now handles value-type default - LowerAssign now supports IndexExpression (array/indexer assignment) - IRValidator: moved LoadArrayLength from push to neutral category Also includes allocation reduction (lazy dictionaries, reduced capacities, StackSpillPass fast-exit), nullable warning fixes, new Phase 9 tests (559 total), and FEC IssueTests patterns 4-10.
…ment tests - Pattern 8 (box/unbox in conditional) now uses HyperbeeCompiler.Compile natively after LowerConditional fix - LowerSwitch: non-void switch uses result-local pattern so stack is empty at labels, fixing string switch without explicit comparison - Added PostIncrementAssign, PreIncrementAssign, PostDecrementAssign tests - Added string switch without explicit comparison test
…timeVariables - Add lifted nullable binary operations (arithmetic + comparisons) via LowerLiftedBinary, LowerLiftedComparison, LowerLiftedArithmetic - Add lifted nullable unary operations via LowerLiftedUnary - Add Nullable<T> ↔ T conversions and enum underlying-type conversions in LowerConvert (fixes TypeConversionTests for Hyperbee compiler) - Add exception filter support: BeginFilter / BeginFilteredCatch IR ops, IL emission, DeadCodePass sentinel, IRValidator stack depth - Add RuntimeVariables support: RuntimeVariablesHelper, CaptureScanner FindRuntimeVariablesCaptures, LowerRuntimeVariables with StrongBox array - Fix TypeIs to use ldtoken + Type.GetTypeFromHandle (embeddable in CompileToMethod) - Add OnesComplement to supported unary ops - Improve closure binding: BuildClosureBinder for non-invoked captured lambdas - Remove obsolete IROp entries: LoadClosureVar, StoreClosureVar, CreateDelegate - Add README.md with architecture overview and benchmark comparison table - Add FecKnownIssues patterns 11-20 (AddAssign, TypeAs, closures, filter, etc.) - Add test files: BitwiseTests, CompileToMethodTests, DynamicExpressionTests, RuntimeVariablesTests (679 tests passing across net8/net9/net10)
FEC generates incorrect IL for Not(Nullable<bool>): calling the compiled delegate with any argument causes AccessViolationException (crashes the test host process). The bug exists because FEC does not null-guard the lifted Not operation — it attempts to dereference the nullable value without checking HasValue first. - NullableTests.Not_NullableBool(Fast): guard before delegate invocation with Assert.Fail, documenting the bug rather than crashing the host - FecKnownIssues.Pattern21: add native Hyperbee verification test with explanation of why the FEC variant cannot be safely tested Effect: 808 tests total, 807 pass, 1 documented FEC failure (no crash). Previously: 648 tests appeared to pass, then host crashed (160 tests never ran due to the fatal AccessViolationException mid-run).
…t, IR fixes Compiler fixes: - Add unsigned checked IR opcodes (AddCheckedUn, SubCheckedUn, MulCheckedUn, ConvertCheckedUn) to IROp, IRValidator, ILEmissionPass, and ExpressionLowerer - Fix float/double comparisons to use IsUnsignedOrFloat (clt.un/cgt.un for unordered NaN semantics) - Fix nullable Power lowering to emit null-propagation guard - Fix ~30 additional expression lowering correctness bugs Test infrastructure: - Remove FEC→System fallback from CompileFast — FEC failures now surface as test failures - FecKnownIssues.cs rewritten: only FEC-specific _FecBug and CompileWithFallback tests (no redundant _HyperbeeNative tests); added Pattern23 (ulong LessThan) and Pattern25 (ConvertChecked ulong→long) as verifiable _FecBug tests - Policy: System fails → remove test; FEC fails → suppress + FecKnownIssues link; Hyperbee fails → fix - Remove two invalid all-compiler-crash patterns (NewArrayInit_NullableIntArray, ConvertChecked_NullableIntToByte_Overflow) New test files (6): - BlockTests.cs, ControlFlowTests.cs, ConvertCheckedTests.cs - LambdaTests.cs, NullableArithmeticTests.cs, NullableBitwiseTests.cs Expanded test files (11): - ArrayTests, BinaryTests, CollectionInitTests, ComparisonTests, ConditionalTests - ExceptionHandlingTests, LoopTests, NullableTests, SwitchTests, TypeConversionTests, UnaryTests Result: 1,559 total test instances — 1,551 passed, 8 skipped (all FEC-only), 0 failed
…ompiler bugs Expand HyperbeeCompiler test suite from ~1,766 to 2,426 instances (0 failures): Compiler fixes: - Add RightShiftUn opcode (shr.un) for unsigned logical right shift; uint/ulong RightShift now correctly emits shr.un instead of sign-extending shr - Fix IRValidator false positive: track expected stack depth per label from branch sites so conditional sub-expressions inside arithmetic no longer fail stack-depth validation - Add lifted IsFalse/IsTrue support in LowerLiftedUnary for bool? operands New test coverage: - ComparisonTests: NaN comparisons (all 6 ops × float/double), infinity comparisons, float basic comparisons, decimal comparisons (+20 methods) - ArrayTests: 2D/3D array bounds creation, 2D read/write, zero-length arrays, nullable array, bool/long/string arrays, out-of-bounds throws (+11 methods) - BoundaryValueTests: float NaN propagation, infinity arithmetic, int boundary wrapping, float/double divide by zero (+10 methods) - UnaryTests: fix IsFalse/IsTrue nullable semantics (bool? → bool?), fix Negate_SByte (widening pattern), FEC suppress for PostIncrementAssign_Double (+fixes) - ExceptionHandlingTests: fix 3 tests with try/catch type mismatch (void vs value) - Multiple type-complete arithmetic/comparison tests across session
… and README - Fix AccessViolationException in LowerConstant: Constant(null, typeof(int?)) was emitting ldnull, but stelem for a value type expects a struct on the stack. CLR zeroes locals on declaration, so a fresh temp local already holds default(Nullable<T>) — emit LoadLocal directly instead of LoadNull. - Re-enable NewArrayInit_NullableIntArray_AccessElements test (3 DataRows). - Update README compilation benchmarks to latest run (9–34x vs System, 1.11–1.47x vs FEC); add execution benchmarks table; document CompileToMethod API.
…cStateMachineBuilder Reverts premature integration of HEC into hyperbee.expressions before the compiler was proven correct on state-machine patterns. MoveNextCompiler option removed from ExpressionRuntimeOptions; compiler project reference removed from expressions test project.
…ests - CompileToInstanceMethodTests: covers field read/write, non-embeddable constant rejection, and the StateMachineCompiler sentinel - StateMachinePatternTests: 12 tests proving HEC compiles every pattern produced by the async state machine lowerer — Switch dispatch tables, instance field read/write, IfThen+Return (suspend pattern), ref parameter calls, TryCatch wrapping, and multi-state MoveNext shapes — all verified against System compiler
Introduce ICoroutineDelegateBuilder and ICoroutineImplementationBuilder as the abstraction layer for async state machine compilation, replacing the previous IEntryPointGenerator / IStateMachineGenerator names. "Coroutine" is the CS term for the suspend/resume pattern underlying both async/await and yield-return — not tied to state machines and safe for future .NET runtime-native async (e.g. .NET 11+). Changes: - ICoroutineBuilder.cs: defines ICoroutineDelegateBuilder (public) and ICoroutineImplementationBuilder (internal, reserved for M3) - AsyncStateMachineBuilder.cs: DefaultCoroutineDelegateBuilder replaces SystemEntryPointGenerator; raw-lambda embedding preserved for default, Constant(delegate) used for custom builders - ExpressionRuntimeOptions.cs: EntryPointGenerator → DelegateBuilder - HyperbeeCoroutineDelegateBuilder.cs: HEC implementation (was HecEntryPointGenerator) - CompilerDiagnostics.cs + IRFormatter.cs: diagnostic infrastructure - nestedCompiler wired in ExpressionLowerer for recursive HEC compilation - BlockAsyncHecTests.cs: integration tests (3 pass, 8 known HEC bugs) All Hyperbee.Expressions.Tests pass (669/3). No regressions.
…thodBuilderBox Replaces the misleadingly named AsyncInterpreterTaskBuilder<TResult> with AsyncTaskMethodBuilderBox<TResult>, which clearly communicates its purpose: a typed heap box around the AsyncTaskMethodBuilder<TResult> struct, required because expression tree MemberExpression access copies struct fields, making direct struct mutation impossible without a class wrapper. Adds XML doc comments explaining the struct-copy problem, the box pattern, and why StrongBox<T> alone would not suffice.
…est suite 2547/21 Compiler fixes: - HyperbeeCompiler: ScanForNonEmbeddableConstants now returns true for extension nodes so AsyncBlockExpression reduction is handled correctly (SingleAwait, VoidResult) - ILEmissionPass: short branch auto-upgraded to long branch when offset exceeds ±127 bytes (fixes ConditionalAwait illegal one-byte branch) - ExpressionLowerer: struct field method calls emit Constrained prefix + LoadFieldAddress for TaskAwaiter<T> fields (fixes stack underflow in SequentialAwaits/TryCatch) Test reorganization: - BlockAsync*Tests moved from Expressions/ to Integration/ — these are pipeline integration tests, not HEC expression pattern tests - StateMachinePatternTests deleted; patterns redistributed: - Ref/out parameter tests added to MethodCallTests (AwaitOnCompleted pattern) - Switch dispatch-table tests added to SwitchTests (state-dispatch pattern) Test expansion: - MethodCallTests: +5 ref/out parameter tests - SwitchTests: +3 switch-as-dispatch-table tests (null default, Goto-bodied cases) - CompileToInstanceMethodTests: 7 → 17 tests - RuntimeVariablesTests: 5 → 13 tests Results: 2547 passed, 21 skipped, 0 failed (net9.0)
…ssionCompiler, remove DelegateBuilder from options - Add CoroutineBuilderContext (AsyncLocal per-compilation + static process-wide default) with Exchange(), SetScope(), SetDefault() — compiler choice never passes through BlockAsync options - Add IExpressionCompiler interface + SystemExpressionCompiler in Hyperbee.Expressions - Add HyperbeeExpressionCompiler (DI-injectable adapter) in Hyperbee.Expressions.Compiler - HyperbeeCompiler.Compile() sets ambient via Exchange() in try/finally; adds UseAsDefault()/ClearDefault() - AsyncStateMachineBuilder reads CoroutineBuilderContext.Current directly; removes DefaultCoroutineDelegateBuilder - Remove ExpressionRuntimeOptions.DelegateBuilder — options describe behavior only, not compiler choice - Simplify AsyncBlockExpression.Reduce(); remove ResolvedOptions() - Integration tests: remove HecOptions() from all BlockAsync tests; IRCapture test uses SetScope() - Add BlockAsyncContextTests covering ambient and process-wide default paths
…-Inconclusive test - Add FecKnownIssues.Pattern28: Return(label, Assign(...)) inside async-lowered TryCatch generates invalid IL in FEC (incomplete error 1007 detection; FEC issue #495) - Update BlockAsyncTryCatchTests: standardize Fast suppress message to reference Pattern28 - Remove CompileFast_ShouldReturnNull_ForReturnGotoFromTryCatchWithAssign from CompilerCompatibilityTests — always-Inconclusive placeholder, now documented in FecKnownIssues - Solution skips: 23 total (2 Expressions.Tests + 21 Compiler.Tests), all FEC suppressions
…, fix void-assign and ldelema bugs Remove unnecessary merge-point result locals from conditional, logical, and coalesce lowering by leaving values on the evaluation stack at merge points (valid in CIL when stack depth is consistent across all paths). Saves 3–5 instructions and 1–2 locals per occurrence. Void-lambda with bare Assign body: set _discardResult=true to suppress the Dup that was incorrectly leaving a value on the stack before Ret. Void block ending in Assign: extend suppressAssign logic so the final Pop is not emitted after an Assign (the value was never pushed in the first place). ldelema fix: Assign to a field of a struct stored in an array element requires ldelema (managed pointer) not ldelem (value copy). Add IROp.LoadElementAddress, emit Ldelema in ILEmissionPass, handle in IRValidator/IRFormatter. New EmitInstanceForFieldAssign helper routes value-type instances through EmitLoadAddress, which now handles ArrayIndex-on-value-type via ldelema. Fix also covers mutating instance method calls on struct array elements. Add test coverage: void-lambda assign patterns (5 tests), struct-array-element field and property assignment patterns (5 tests) — all passing for System, FEC, and HEC.
…k delta columns - Remove IROp.Switch (never emitted), IRValidator.ValidateAlways (never called) - Remove scope subsystem: IROp.BeginScope/EndScope, IRBuilder.EnterScope/ExitScope, LocalInfo.ScopeDepth — entire subsystem was no-op (no IL emitted, no pass consumed it) - Remove CompilerDiagnostics.ILCapture (declared but never wired or invoked) - Gate CoroutineBuilderContext.Exchange on ScanForNonEmbeddableConstants to avoid unnecessary AsyncLocal writes for simple expressions; pass pre-computed result into LowerToIR to eliminate redundant traversal — restores 9-34x speedup vs SEC - Add BenchmarkExpressions (shared definitions), BenchmarkColumns (RatioToColumn for vs-SEC and vs-FEC delta columns), expand ExecutionBenchmarks to all 6 tiers - Update README with current benchmark numbers and expanded execution table
Add full documentation for Hyperbee.Expressions, Hyperbee.Expressions.Compiler, and Hyperbee.Expressions.Lab following the established just-the-docs pattern used across sibling projects (hyperbee.pipeline, hyperbee.json, hyperbee.xs). Structure (27 markdown files across 4 sections): - index.md — landing page with package table, quick start, expression type index - expressions/ — parent + 12 children (async-block, enumerable-block, await, yield, for, foreach, while, using, debug, string-format, inject, configuration-value) - configuration/ — parent + 3 children (runtime-options, module-providers, dependency-injection) - compiler/ — parent + 4 children (overview, api, diagnostics, performance) - lab/ — parent + 3 children (fetch, json, map-reduce) Infrastructure: - _config.yml — adds baseurl, url, footer_content, nav_external_links - _includes/nav_footer_custom.html — branded footer - docs.projitems — updated to include all 27 pages
Replace em/en dashes, arrows, box-drawing, micro sign, and other non-ASCII Unicode with ASCII-only substitutions so all docs .md files are plain ASCII.
…and redundant assignments
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
This PR introduces
Hyperbee.Expressions.Compiler(HEC) — a high-performance, IR-based compiler for .NETexpression trees — and wires it into the existing
Hyperbee.Expressionsasync/enumerable state machineinfrastructure via a pluggable interface.
Motivation
The System expression compiler (
Expression.Compile()) is a general-purpose interpreter. It is correctand portable, but it is slow. For applications that compile expression trees at runtime — rule engines,
query builders, dynamic pipelines, scripted workflows — compilation cost dominates.
FastExpressionCompiler(FEC) is a well-known improvement, but it has correctness gaps on complex patterns (nullable lifted ops,
certain try/catch shapes, RuntimeVariables, Dynamic expressions) and is a third-party dependency.
Hyperbee.Expressionsalready generates async and enumerable state machines as expression trees. Thosestate machines need to be compiled. Before this PR, the only options were SEC (slow) or FEC (fast but
incomplete). Neither integrates cleanly with the state machine generator — each compiled
MoveNextbodyhad to be compiled by whichever compiler happened to receive the outer lambda, which broke encapsulation.
Goals:
AsyncBlockExpressionshould not be coupled to any specific compiler.The outer compiler (SEC, FEC, or HEC) should be able to compile inner state machine bodies automatically.
IExpressionCompilerfor injectable compiler selection.ExpressionTypethe System compiler handles, plus the patterns FECdoes not.
What's New
Hyperbee.Expressions.Compiler(new package)A four-stage IR-based compiler:
LambdaExpression
→ ExpressionLowerer (expression tree → flat IROp instruction stream)
→ StackSpillPass (eliminate merge-point locals at branch phi-points)
→ PeepholePass (constant folding, branch simplification, load/store elimination)
→ DeadCodePass (remove unreachable instructions after unconditional branches)
→ ILEmissionPass (IR → CIL → DynamicMethod)
Public API surface:
HyperbeeCompilerCompile,TryCompile,CompileWithFallback,CompileToMethod,CompileToInstanceMethod,UseAsDefaultHyperbeeExpressionCompilerIExpressionCompilersingleton wrapper for DIHyperbeeCompilerExtensionslambda.CompileHyperbee()extension methodCompilerDiagnosticsIRCapturecallback for IR listing inspectionHyperbee.Expressions— pluggable coroutine builder (M1–M3)Three milestones refactored the state machine generator to support compiler plug-in without changing
expression construction semantics:
ICoroutineDelegateBuilderinterface;HyperbeeCoroutineDelegateBuilder;CoroutineBuilderContext(AsyncLocal ambient + static default)BlockAsyncpatterns correctly; fixes for short-branch overflow, struct field method calls, and extension-node constant scanningExpressionRuntimeOptions.DelegateBuilderremoved;IExpressionCompiler+SystemExpressionCompileradded;CoroutineBuilderContext.SetScope;HyperbeeExpressionCompiler; ambient set automatically duringHyperbeeCompiler.Compile()The net effect:
BlockAsyncoptions describe behavior only (Optimize, ModuleBuilderProvider, ExpressionCapture).Compiler choice flows through ambient context — no options need to change when switching compilers.
Performance
Benchmarks run on
.NET 9, BenchmarkDotNet, 3 iterations + 3 warmup,Intel Core i9-9980HK.Compilation Speed
HEC compiles 9–34× faster than the System compiler and within 1.16–1.54× of FEC.
Memory Allocations (per compile call)
HEC allocates up to 50% less than the System compiler.
Execution Speed
Delegates produced by HEC execute at the same speed as SEC and FEC. At sub-nanosecond scale, differences
are within measurement noise. For CPU-bound workloads (Complex tier, ~25 ns), all three compilers are
within 10% of each other.
Performance Implementation Notes
constants (object refs, delegates, nested lambdas) in a
object[]closure and indexes into it atruntime. FEC inlines constants directly via ldobj/stobj.
AsyncLocalwrites are expensive (~1 µs each).CoroutineBuilderContext.Exchange()is gated onScanForNonEmbeddableConstants— for simple expressions (no extension nodes), the ambient write isskipped entirely, recovering ~2 µs per compile call for the common case.
eliminate unnecessary locals, bringing HEC within striking distance of FEC's tight output.
Expression Coverage
HEC handles every
ExpressionTypethe System compiler handles, plus patterns FEC does not:Ceq,Clt,Cgt, un-variantsConvert,ConvertChecked,ConvertCheckedUn,Box,UnboxAny,CastClass,IsInstNewArray,LoadElement,StoreElement,LoadArrayLength,LoadElementAddressIfThen,IfThenElse,Switch,Loop,Goto,Label,ReturnTryCatch,TryCatchFinally,TryFinally,TryFault,ExceptionFilterStrongBox<T>hoisting; nested lambdasIRuntimeVariablesviaRuntimeVariablesHelperDynamicExpressionviaCallSiteExpression.Quotefor nested expression treesMethodBuildertarget (no closure support — all constants must be embeddable)MethodBuildertarget (forIAsyncStateMachine.MoveNext)Test Suite
2,610 test instances across 32 expression test files, 7
BlockAsyncintegration suites, and aFEC issue regression suite. All tests pass (2,589 passed, 21 skipped).
Test policy:
Assert.Inconclusive+ documented inFecKnownIssues.csBugs Fixed in
Hyperbee.ExpressionsSeveral bugs were discovered during M2 integration testing and fixed in the core library:
ILEmissionPassnow auto-upgrades short (br.s) branches to long (br) when the offset exceeds ±127 bytes. Required for theConditionalAwaitmulti-state pattern.ExpressionLowereremitsConstrainedprefix +LoadFieldAddressfor value-type field method calls (e.g.,TaskAwaiter<T>.GetResult()). Fixes stack underflow in multi-stateSequentialAwaitsandTryCatchMoveNext patterns.ScanForNonEmbeddableConstantsreturnstrueforExpressionType.ExtensionsoAsyncBlockExpressionreduction is handled correctly during HEC compilation.ExpressionLowerer.LowerBlockcorrectly suppresses theDupemitted byLowerAssignwhen the assignment result is immediately discarded.ldelemafor struct-element field assignmentLoadElementAddress(ldelema) is now emitted instead ofLoadElement+StoreElementwhen the target is a struct field element address.StackSpillPasseliminates the temporaryStoreLocal/LoadLocalpair inserted at branch merge-points when the value is immediately consumed, reducing unnecessary locals inif/elseandswitchpatterns.Documentation
Full just-the-docs documentation added under
docs/matching the structure of sibling projects(
hyperbee.pipeline,hyperbee.json,hyperbee.xs):docs/
├── index.md Landing page
├── expressions/ 12 expression type pages
├── configuration/ Runtime options, module providers, DI
├── compiler/ Overview, API reference, diagnostics, performance
└── lab/ Fetch, JSON, Map/Reduce
Files Changed
src/Hyperbee.Expressions.Compiler/— new package (19 source files)src/Hyperbee.Expressions/— 8 files modified (interfaces, ambient context, options)test/Hyperbee.Expressions.Compiler.Tests/— new project (32 test files, ~2,340 test instances)test/Hyperbee.Expressions.Compiler.IssueTests/— new project (FEC regression suite)test/Hyperbee.Expressions.Compiler.Benchmarks/— new project (compilation + execution benchmarks)docs/— 27 markdown pages + configChecklist
Hyperbee.Expressions.Testspass (no regressions)Hyperbee.Expressions.Compiler.Testspass (21 skipped — documented FEC limitations)Hyperbee.Expressions.Compiler.IssueTestspass