Skip to content

BE-615: HashQL: Introduce the concept of synthetic closures in the MIR#8894

Open
indietyp wants to merge 8 commits into
bm/be-607-hashql-remove-smallvec-from-the-standardlibrary-for-modulefrom
bm/be-615-hashql-introduce-synthetic-closures-and-trivial-closure
Open

BE-615: HashQL: Introduce the concept of synthetic closures in the MIR#8894
indietyp wants to merge 8 commits into
bm/be-607-hashql-remove-smallvec-from-the-standardlibrary-for-modulefrom
bm/be-615-hashql-introduce-synthetic-closures-and-trivial-closure

Conversation

@indietyp

Copy link
Copy Markdown
Member

🌟 What is the purpose of this PR?

Introduces Source::Synthetic for compiler-generated wrapper bodies and extends administrative reduction to handle single-operation function bodies (TrivialClosure).

This is groundwork for making intrinsics usable in value position (e.g. passing + as an argument to a higher-order function). The Synthetic source variant will identify wrapper bodies that bridge non-first-class operations into callable closures, and TrivialClosure ensures they are always inlined away.

🔍 What does this change?

  • Adds Source::Synthetic(Symbol) to the MIR Source enum for compiler-synthesized operation wrappers
  • Adds ReductionKind::TrivialClosure to administrative reduction, recognizing single-basic-block bodies where a trivial prelude leads to a single non-call operation (Binary, Unary, Aggregate, Input, Load) whose result is returned
  • Synthetic bodies get InlineDirective::Always (same as Ctor)
  • All downstream Source matches updated: execution pipeline, statement placement, eval context, pretty printer
  • Adds [synthetic sym::path] source to the body! test macro

The TrivialClosure classification is intentionally broader than just synthetic bodies. Any function matching the shape is reducible, which unlocks optimization cascades: single-operation closures get inlined, exposing constant-foldable expressions, enabling branch elimination downstream.

Pre-Merge Checklist 🚀

🚢 Has this modified a publishable library?

This PR:

  • does not modify any publishable blocks or libraries, or modifications do not need publishing

📜 Does this require a change to the docs?

The changes in this PR:

  • are internal and do not require a docs change

🕸️ Does this require a change to the Turbo Graph?

The changes in this PR:

  • do not affect the execution graph

🐾 Next steps

  • Implement qualified_path in reification to generate synthetic wrapper bodies for intrinsics in value position
  • Intrinsic classification (first-classable vs syntactic forms)
  • Call handler optimization to recognize administrative thunk-force patterns and skip throwaway thunk body generation

🛡 What tests cover this?

  • Classification unit tests: classify_trivial_closure_binary, classify_trivial_closure_unary, classify_non_reducible_non_trivial_prelude
  • Inlining snapshot tests: inline_trivial_closure_binary, inline_trivial_closure_transitive
  • Existing compiletest suite (e.g. nested-branch-elimination now demonstrates the full optimization cascade)

❓ How to test this?

cargo test --package hashql-mir --lib -- administrative_reduction::tests

📹 Demo

The nested-branch-elimination compiletest shows the cascade effect: closures containing single comparisons (> 100, < 0) are now inlined by AR, exposing constant-foldable comparisons (50 > 100, 50 < 0), which enables the entire branch structure to collapse to return "in range".

Copilot AI review requested due to automatic review settings June 22, 2026 13:47
@vercel

vercel Bot commented Jun 22, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
hash Ready Ready Preview, Comment Jun 23, 2026 10:13am
petrinaut Ready Ready Preview Jun 23, 2026 10:13am
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
hashdotdesign-tokens Ignored Ignored Preview Jun 23, 2026 10:13am

@vercel vercel Bot temporarily deployed to Preview – petrinaut June 22, 2026 13:47 Inactive
@cursor

cursor Bot commented Jun 22, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Touches MIR optimization semantics, intrinsic representation, and Postgres SQL shape for entity edition joins; behavior changes are mostly internal but affect compiled graph-read filters and SQL plans.

Overview
Adds Source::Synthetic for compiler-generated operation wrappers (path-identified, always inlined like ctors) and ReductionKind::TrivialClosure so administrative reduction inlines single-block bodies whose last statement is a primitive op (Binary, Unary, Load, etc.), not only forwarding calls. That enables deeper constant-folding and branch-collapse in compiletests (e.g. filters simplifying to direct comparisons or return true).

Intrinsics move from Source::Intrinsic(DefId) to a dedicated Intrinsic / IntrinsicId model (EntityPropertyAccess, optional optimize); built-in DefId dict/list op constants are removed. Execution placement, eval live-out, and pretty-printing treat Synthetic like other non–graph-read bodies.

Supporting changes: Pool is allocator-parameterized; core::json types are shared via a public types module; graph::entity::property is typed to return unknown() until Option comparisons work (BE-62). Postgres codegen now joins entity_editions via a lateral subquery instead of a plain inner join; eval MIR fixtures reflect statement ordering and inlined filter shapes.

Reviewed by Cursor Bugbot for commit d051ddb. Bugbot is set up for automated code reviews on this repo. Configure here.

indietyp commented Jun 22, 2026

Copy link
Copy Markdown
Member Author

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more

This stack of pull requests is managed by Graphite. Learn more about stacking.

@codecov

codecov Bot commented Jun 22, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 26.83%. Comparing base (df8bde2) to head (d051ddb).

Additional details and impacted files
@@                                            Coverage Diff                                            @@
##           bm/be-607-hashql-remove-smallvec-from-the-standardlibrary-for-module    #8894       +/-   ##
=========================================================================================================
- Coverage                                                                 42.67%   26.83%   -15.85%     
=========================================================================================================
  Files                                                                       776      652      -124     
  Lines                                                                     68104    50479    -17625     
  Branches                                                                   3908     3324      -584     
=========================================================================================================
- Hits                                                                      29066    13547    -15519     
+ Misses                                                                    38682    36777     -1905     
+ Partials                                                                    356      155      -201     
Flag Coverage Δ
apps.hash-ai-worker-ts 1.39% <ø> (ø)
apps.hash-api 0.00% <ø> (ø)
local.hash-backend-utils 2.82% <ø> (ø)
local.hash-graph-sdk 9.63% <ø> (ø)
local.hash-isomorphic-utils 0.00% <ø> (ø)
rust.hash-graph-api 7.63% <ø> (ø)
rust.hashql-compiletest 28.39% <ø> (ø)
rust.hashql-eval 82.10% <100.00%> (ø)
rust.hashql-mir ?

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends the HashQL MIR infrastructure to support compiler-synthesized wrapper bodies (“synthetic closures”) and broadens administrative reduction so single-operation closures can be inlined away, enabling optimization cascades (e.g., constant folding after inlining). It also updates several downstream components (pretty-printing, execution/eval contexts, statement placement) and refreshes a large set of MIR/SQL golden outputs to reflect the new inlining/reduction behavior.

Changes:

  • Introduces Source::Synthetic(Symbol) and updates inlining/execution/pretty-printing logic to recognize the new source kind.
  • Adds ReductionKind::TrivialClosure to administrative reduction and adds unit/snapshot tests for trivial-closure classification + transitive inlining.
  • Refactors allocator usage in MixedBitSetPool/Pool and updates MIR reification to use allocator-aware pools; updates many UI golden files to new optimized MIR/SQL.

Reviewed changes

Copilot reviewed 48 out of 49 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
libs/@local/hashql/mir/tests/ui/pass/post_inline/showcase.stdout Updated post-inline MIR output to reflect trivial-closure inlining/CFG simplification.
libs/@local/hashql/mir/tests/ui/pass/post_inline/nested-branch-elimination.stdout Updated golden output showing cascade to constant results after inlining.
libs/@local/hashql/mir/tests/ui/pass/post_inline/constant-propagation-after-inline.stdout Updated golden output showing constant propagation after inlining.
libs/@local/hashql/mir/tests/ui/pass/post_inline/closure-env-cleanup.stdout Updated golden output reflecting cleanup after inlining.
libs/@local/hashql/mir/tests/ui/pass/post_inline/cascading-simplification.stdout Updated golden output reflecting aggressive simplification after inlining.
libs/@local/hashql/mir/tests/ui/pass/lower/unreachable_only.snap New snapshot covering degenerate “unreachable-only” body through pipeline.
libs/@local/hashql/mir/tests/ui/pass/lower/goto_into_unreachable.snap New snapshot covering goto into unreachable and propagation/simplification.
libs/@local/hashql/mir/tests/ui/pass/inline/too-large-to-inline.stdout Updated inlining golden output (calls replaced by primitive ops/inputs where appropriate).
libs/@local/hashql/mir/tests/ui/pass/inline/heuristic-inline.stdout Updated heuristic-inlining golden output after new reductions.
libs/@local/hashql/mir/tests/ui/pass/inline/filter-with-ctor.stdout Updated golden output for filter + ctor interaction after new reductions.
libs/@local/hashql/mir/tests/ui/pass/inline/filter-aggressive.stdout Updated aggressive filter inlining golden output.
libs/@local/hashql/mir/tests/ui/pass/inline/closure-inline.stdout Updated closure-inlining golden output (e.g., direct input loads).
libs/@local/hashql/mir/tests/ui/pass/administrative_reduction/non-reducible-computation.stdout Updated AR golden output to reflect new “trivial closure” shape handling.
libs/@local/hashql/mir/tests/ui/pass/administrative_reduction/non-reducible-computation.jsonc Updated test description to reflect trivial-closure distinction.
libs/@local/hashql/mir/tests/ui/pass/administrative_reduction/inline_trivial_closure_transitive.snap New snapshot verifying transitive trivial-closure reduction results.
libs/@local/hashql/mir/tests/ui/pass/administrative_reduction/inline_trivial_closure_binary.snap New snapshot verifying binary-op trivial-closure reduction results.
libs/@local/hashql/mir/src/reify/mod.rs Updates reifier state to use allocator-aware MixedBitSetPool and recycler-in allocator construction.
libs/@local/hashql/mir/src/pretty/text.rs Adds Synthetic printing and adjusts intrinsic printing to use Intrinsic { id, .. }.
libs/@local/hashql/mir/src/pass/transform/inline/tests.rs Updates inline tests to accommodate new Source/intrinsic representation and adds required imports.
libs/@local/hashql/mir/src/pass/transform/inline/analysis.rs Treats Source::Synthetic as InlineDirective::Always.
libs/@local/hashql/mir/src/pass/transform/administrative_reduction/tests.rs Adds classification tests for trivial closures and inlining snapshot tests.
libs/@local/hashql/mir/src/pass/transform/administrative_reduction/mod.rs Updates module docs to include “trivial closures” as a reduction target.
libs/@local/hashql/mir/src/pass/transform/administrative_reduction/kind.rs Extends reduction classification to TrivialClosure for single-operation bodies.
libs/@local/hashql/mir/src/pass/tests.rs Extracts/expands pass-level pipeline tests and snapshot helpers.
libs/@local/hashql/mir/src/pass/mod.rs Moves inline tests module to pass/tests.rs and wires it in under #[cfg(test)].
libs/@local/hashql/mir/src/pass/execution/statement_placement/postgres/mod.rs Treats Synthetic like other non-filter sources for statement-placement behavior.
libs/@local/hashql/mir/src/pass/execution/statement_placement/interpret/mod.rs Treats Synthetic like other non-filter sources for statement-placement behavior.
libs/@local/hashql/mir/src/pass/execution/statement_placement/embedding/mod.rs Treats Synthetic like other non-filter sources for statement-placement behavior.
libs/@local/hashql/mir/src/pass/execution/mod.rs Skips execution analysis for Synthetic sources similarly to ctor/closure/thunk/intrinsic.
libs/@local/hashql/mir/src/lib.rs Introduces new intrinsic module.
libs/@local/hashql/mir/src/intrinsic.rs Adds IntrinsicId and Intrinsic metadata struct.
libs/@local/hashql/mir/src/def.rs Removes old DefId intrinsic constants, keeping placeholder.
libs/@local/hashql/mir/src/builder/body.rs Updates body-builder defaults/docs and adds body! macro support for [synthetic ...].
libs/@local/hashql/mir/src/body/mod.rs Changes Source::Intrinsic payload type and adds Source::Synthetic.
libs/@local/hashql/eval/tests/ui/postgres/tuple-construction.aux.mir Updated eval MIR golden output reflecting reordered temps after reductions.
libs/@local/hashql/eval/tests/ui/postgres/struct-construction.aux.mir Updated eval MIR golden output reflecting reordered temps after reductions.
libs/@local/hashql/eval/tests/ui/postgres/opaque-passthrough.aux.mir Updated eval MIR golden output reflecting simplified temp flow.
libs/@local/hashql/eval/tests/ui/postgres/mixed-sources-filter.stdout Updated SQL golden output (JOIN shape changed) after upstream MIR changes.
libs/@local/hashql/eval/tests/ui/postgres/list-construction.aux.mir Updated eval MIR golden output reflecting reordered inputs.
libs/@local/hashql/eval/tests/ui/postgres/entity-archived-check.stdout Updated SQL golden output (JOIN shape changed) after upstream MIR changes.
libs/@local/hashql/eval/tests/ui/postgres/dict-construction.aux.mir Updated eval MIR golden output reflecting reordered inputs.
libs/@local/hashql/eval/tests/ui/postgres/comparison-no-cast.aux.mir Updated eval MIR golden output reflecting reordered inputs.
libs/@local/hashql/eval/src/context.rs Skips eval codegen work for Synthetic sources similarly to other non-filter sources.
libs/@local/hashql/core/src/symbol/sym.rs Adds pointer symbol.
libs/@local/hashql/core/src/module/std_lib/graph/entity.rs Adjusts property signature (temporary) and updates imports/comments.
libs/@local/hashql/core/src/module/std_lib/core/mod.rs Makes core::json module publicly accessible.
libs/@local/hashql/core/src/module/std_lib/core/json.rs Refactors JSON-path types into reusable types submodule helpers.
libs/@local/hashql/core/src/collections/pool.rs Makes Pool allocator-aware and updates MixedBitSetPool alias accordingly.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread libs/@local/hashql/mir/src/lib.rs Outdated
Comment thread libs/@local/hashql/mir/src/builder/body.rs
Comment thread libs/@local/hashql/mir/src/body/mod.rs
Comment thread libs/@local/hashql/mir/src/intrinsic.rs
Comment thread libs/@local/hashql/mir/src/pass/transform/inline/tests.rs
@codspeed-hq

codspeed-hq Bot commented Jun 22, 2026

Copy link
Copy Markdown

Merging this PR will improve performance by 18.18%

⚡ 2 improved benchmarks
✅ 78 untouched benchmarks

Performance Changes

Benchmark BASE HEAD Efficiency
bit_matrix/dense/iter_row[64] 170 ns 140.8 ns +20.71%
bit_matrix/dense/iter_row[200] 215 ns 185.8 ns +15.7%

Tip

Curious why this is faster? Comment @codspeedbot explain why this is faster on this PR, or directly use the CodSpeed MCP with your agent.


Comparing bm/be-615-hashql-introduce-synthetic-closures-and-trivial-closure (d051ddb) with bm/be-607-hashql-remove-smallvec-from-the-standardlibrary-for-module (ceb05c9)1

Open in CodSpeed

Footnotes

  1. No successful run was found on bm/be-607-hashql-remove-smallvec-from-the-standardlibrary-for-module (df8bde2) during the generation of this report, so 3b47adc was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@github-actions

Copy link
Copy Markdown
Contributor

Benchmark results

@rust/hash-graph-benches – Integrations

policy_resolution_large

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 2002 $$27.4 \mathrm{ms} \pm 251 \mathrm{μs}\left({\color{gray}-0.928 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$3.38 \mathrm{ms} \pm 18.8 \mathrm{μs}\left({\color{gray}-0.897 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 1001 $$12.7 \mathrm{ms} \pm 93.5 \mathrm{μs}\left({\color{gray}-0.735 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 3314 $$42.7 \mathrm{ms} \pm 438 \mathrm{μs}\left({\color{gray}-2.524 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$14.1 \mathrm{ms} \pm 131 \mathrm{μs}\left({\color{gray}-0.712 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 1526 $$24.7 \mathrm{ms} \pm 179 \mathrm{μs}\left({\color{gray}2.28 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 2078 $$28.2 \mathrm{ms} \pm 204 \mathrm{μs}\left({\color{gray}-0.677 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$3.70 \mathrm{ms} \pm 21.0 \mathrm{μs}\left({\color{gray}-0.357 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 1033 $$13.4 \mathrm{ms} \pm 104 \mathrm{μs}\left({\color{gray}-1.643 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_medium

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 102 $$3.74 \mathrm{ms} \pm 22.9 \mathrm{μs}\left({\color{gray}-0.160 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$2.99 \mathrm{ms} \pm 19.3 \mathrm{μs}\left({\color{gray}0.830 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 51 $$3.35 \mathrm{ms} \pm 26.4 \mathrm{μs}\left({\color{gray}1.68 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 269 $$5.24 \mathrm{ms} \pm 40.4 \mathrm{μs}\left({\color{gray}0.624 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$3.53 \mathrm{ms} \pm 25.2 \mathrm{μs}\left({\color{gray}1.65 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 107 $$4.08 \mathrm{ms} \pm 26.8 \mathrm{μs}\left({\color{gray}0.907 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 133 $$4.40 \mathrm{ms} \pm 30.6 \mathrm{μs}\left({\color{gray}-0.629 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$3.44 \mathrm{ms} \pm 19.9 \mathrm{μs}\left({\color{gray}-0.191 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 63 $$4.14 \mathrm{ms} \pm 22.7 \mathrm{μs}\left({\color{gray}1.12 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_none

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 2 $$2.58 \mathrm{ms} \pm 13.4 \mathrm{μs}\left({\color{gray}-0.613 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$2.46 \mathrm{ms} \pm 13.2 \mathrm{μs}\left({\color{gray}-0.250 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 1 $$2.54 \mathrm{ms} \pm 14.8 \mathrm{μs}\left({\color{gray}-0.973 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 8 $$2.80 \mathrm{ms} \pm 14.1 \mathrm{μs}\left({\color{gray}-2.077 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$2.64 \mathrm{ms} \pm 18.3 \mathrm{μs}\left({\color{gray}0.295 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 3 $$2.80 \mathrm{ms} \pm 17.1 \mathrm{μs}\left({\color{gray}-0.186 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_small

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 52 $$3.06 \mathrm{ms} \pm 24.2 \mathrm{μs}\left({\color{gray}2.68 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$2.72 \mathrm{ms} \pm 15.2 \mathrm{μs}\left({\color{gray}0.175 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 25 $$2.97 \mathrm{ms} \pm 21.5 \mathrm{μs}\left({\color{gray}0.307 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 94 $$3.40 \mathrm{ms} \pm 21.1 \mathrm{μs}\left({\color{gray}0.236 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$2.89 \mathrm{ms} \pm 13.6 \mathrm{μs}\left({\color{gray}-0.358 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 26 $$3.26 \mathrm{ms} \pm 20.6 \mathrm{μs}\left({\color{gray}0.538 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 66 $$3.30 \mathrm{ms} \pm 20.9 \mathrm{μs}\left({\color{gray}-1.008 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$2.94 \mathrm{ms} \pm 24.0 \mathrm{μs}\left({\color{gray}0.588 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 29 $$3.30 \mathrm{ms} \pm 20.6 \mathrm{μs}\left({\color{lightgreen}-6.629 \mathrm{\%}}\right) $$ Flame Graph

read_scaling_complete

Function Value Mean Flame graphs
entity_by_id;one_depth 1 entities $$56.7 \mathrm{ms} \pm 326 \mathrm{μs}\left({\color{gray}-0.833 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 10 entities $$49.9 \mathrm{ms} \pm 246 \mathrm{μs}\left({\color{gray}3.86 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 25 entities $$54.1 \mathrm{ms} \pm 331 \mathrm{μs}\left({\color{red}5.28 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 5 entities $$47.1 \mathrm{ms} \pm 242 \mathrm{μs}\left({\color{lightgreen}-19.103 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 50 entities $$63.1 \mathrm{ms} \pm 368 \mathrm{μs}\left({\color{gray}1.91 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 1 entities $$65.1 \mathrm{ms} \pm 465 \mathrm{μs}\left({\color{gray}1.49 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 10 entities $$57.1 \mathrm{ms} \pm 388 \mathrm{μs}\left({\color{gray}1.25 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 25 entities $$109 \mathrm{ms} \pm 532 \mathrm{μs}\left({\color{gray}0.940 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 5 entities $$50.0 \mathrm{ms} \pm 367 \mathrm{μs}\left({\color{lightgreen}-21.352 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 50 entities $$303 \mathrm{ms} \pm 1.08 \mathrm{ms}\left({\color{red}9.58 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 1 entities $$22.7 \mathrm{ms} \pm 153 \mathrm{μs}\left({\color{gray}2.53 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 10 entities $$23.8 \mathrm{ms} \pm 119 \mathrm{μs}\left({\color{gray}-0.898 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 25 entities $$23.3 \mathrm{ms} \pm 165 \mathrm{μs}\left({\color{gray}4.15 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 5 entities $$22.5 \mathrm{ms} \pm 128 \mathrm{μs}\left({\color{gray}0.506 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 50 entities $$27.3 \mathrm{ms} \pm 156 \mathrm{μs}\left({\color{gray}2.53 \mathrm{\%}}\right) $$ Flame Graph

read_scaling_linkless

Function Value Mean Flame graphs
entity_by_id 1 entities $$22.4 \mathrm{ms} \pm 140 \mathrm{μs}\left({\color{gray}1.59 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 10 entities $$22.7 \mathrm{ms} \pm 132 \mathrm{μs}\left({\color{gray}3.15 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 100 entities $$23.0 \mathrm{ms} \pm 151 \mathrm{μs}\left({\color{gray}2.87 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 1000 entities $$21.6 \mathrm{ms} \pm 123 \mathrm{μs}\left({\color{gray}-4.752 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 10000 entities $$23.7 \mathrm{ms} \pm 160 \mathrm{μs}\left({\color{gray}0.842 \mathrm{\%}}\right) $$ Flame Graph

representative_read_entity

Function Value Mean Flame graphs
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/block/v/1 $$24.5 \mathrm{ms} \pm 195 \mathrm{μs}\left({\color{gray}-1.484 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/book/v/1 $$24.5 \mathrm{ms} \pm 130 \mathrm{μs}\left({\color{gray}-1.461 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/building/v/1 $$24.4 \mathrm{ms} \pm 153 \mathrm{μs}\left({\color{gray}-3.007 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/organization/v/1 $$24.4 \mathrm{ms} \pm 183 \mathrm{μs}\left({\color{gray}-1.317 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/page/v/2 $$26.6 \mathrm{ms} \pm 170 \mathrm{μs}\left({\color{gray}-0.898 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/person/v/1 $$26.7 \mathrm{ms} \pm 173 \mathrm{μs}\left({\color{gray}-0.567 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/playlist/v/1 $$24.5 \mathrm{ms} \pm 156 \mathrm{μs}\left({\color{gray}-0.992 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/song/v/1 $$24.2 \mathrm{ms} \pm 116 \mathrm{μs}\left({\color{gray}-2.557 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/uk-address/v/1 $$24.5 \mathrm{ms} \pm 161 \mathrm{μs}\left({\color{gray}-2.306 \mathrm{\%}}\right) $$ Flame Graph

representative_read_entity_type

Function Value Mean Flame graphs
get_entity_type_by_id Account ID: bf5a9ef5-dc3b-43cf-a291-6210c0321eba $$8.42 \mathrm{ms} \pm 47.4 \mathrm{μs}\left({\color{gray}-1.727 \mathrm{\%}}\right) $$ Flame Graph

representative_read_multiple_entities

Function Value Mean Flame graphs
entity_by_property traversal_paths=0 0 $$60.1 \mathrm{ms} \pm 358 \mathrm{μs}\left({\color{gray}0.102 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=255 1,resolve_depths=inherit:1;values:255;properties:255;links:127;link_dests:126;type:true $$111 \mathrm{ms} \pm 545 \mathrm{μs}\left({\color{gray}-2.145 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:0;link_dests:0;type:false $$66.8 \mathrm{ms} \pm 434 \mathrm{μs}\left({\color{gray}-0.315 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:1;link_dests:0;type:true $$75.2 \mathrm{ms} \pm 464 \mathrm{μs}\left({\color{gray}-0.522 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:2;links:1;link_dests:0;type:true $$85.8 \mathrm{ms} \pm 549 \mathrm{μs}\left({\color{gray}-1.092 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:2;properties:2;links:1;link_dests:0;type:true $$90.3 \mathrm{ms} \pm 589 \mathrm{μs}\left({\color{gray}-1.586 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=0 0 $$78.7 \mathrm{ms} \pm 419 \mathrm{μs}\left({\color{gray}-3.519 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=255 1,resolve_depths=inherit:1;values:255;properties:255;links:127;link_dests:126;type:true $$107 \mathrm{ms} \pm 602 \mathrm{μs}\left({\color{gray}-1.823 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:0;link_dests:0;type:false $$85.7 \mathrm{ms} \pm 489 \mathrm{μs}\left({\color{gray}-1.264 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:1;link_dests:0;type:true $$94.8 \mathrm{ms} \pm 480 \mathrm{μs}\left({\color{gray}-0.903 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:2;links:1;link_dests:0;type:true $$96.9 \mathrm{ms} \pm 474 \mathrm{μs}\left({\color{gray}-1.676 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:2;properties:2;links:1;link_dests:0;type:true $$96.9 \mathrm{ms} \pm 569 \mathrm{μs}\left({\color{gray}-2.079 \mathrm{\%}}\right) $$

scenarios

Function Value Mean Flame graphs
full_test query-limited $$139 \mathrm{ms} \pm 818 \mathrm{μs}\left({\color{lightgreen}-6.608 \mathrm{\%}}\right) $$ Flame Graph
full_test query-unlimited $$150 \mathrm{ms} \pm 661 \mathrm{μs}\left({\color{gray}-4.310 \mathrm{\%}}\right) $$ Flame Graph
linked_queries query-limited $$45.2 \mathrm{ms} \pm 284 \mathrm{μs}\left({\color{gray}-1.219 \mathrm{\%}}\right) $$ Flame Graph
linked_queries query-unlimited $$561 \mathrm{ms} \pm 1.16 \mathrm{ms}\left({\color{gray}-0.168 \mathrm{\%}}\right) $$ Flame Graph

@indietyp indietyp force-pushed the bm/be-615-hashql-introduce-synthetic-closures-and-trivial-closure branch from 8efe84c to a0c8ad1 Compare June 23, 2026 09:41
@indietyp indietyp force-pushed the bm/be-607-hashql-remove-smallvec-from-the-standardlibrary-for-module branch from 00cf591 to 85a5c9a Compare June 23, 2026 09:41
@indietyp indietyp force-pushed the bm/be-607-hashql-remove-smallvec-from-the-standardlibrary-for-module branch from 85a5c9a to ceb05c9 Compare June 23, 2026 09:52
Copilot AI review requested due to automatic review settings June 23, 2026 09:52
@indietyp indietyp force-pushed the bm/be-615-hashql-introduce-synthetic-closures-and-trivial-closure branch from a0c8ad1 to 0ddf199 Compare June 23, 2026 09:52

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 51 out of 52 changed files in this pull request and generated 1 comment.

Comment thread libs/@local/hashql/mir/src/def.rs
@indietyp indietyp force-pushed the bm/be-615-hashql-introduce-synthetic-closures-and-trivial-closure branch from 0ddf199 to d051ddb Compare June 23, 2026 10:02
@indietyp indietyp force-pushed the bm/be-607-hashql-remove-smallvec-from-the-standardlibrary-for-module branch from ceb05c9 to df8bde2 Compare June 23, 2026 10:02

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit d051ddb. Configure here.

})
{
return Some(Self::ForwardingClosure);
return Some(kind);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AR ignores intrinsic inline policy

Medium Severity

TrivialClosure classification applies to any single-block body with a primitive final assignment, with no check on Source::Intrinsic or Intrinsic::optimize. Intrinsic fallbacks that are one operation can be administratively inlined at Apply sites even though the inline pass treats intrinsics as never inline and the MIR docs say intrinsics are not inlined.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit d051ddb. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/libs Relates to first-party libraries/crates/packages (area) area/tests New or updated tests type/eng > backend Owned by the @backend team

Development

Successfully merging this pull request may close these issues.

2 participants