|
31 | 31 |
|
32 | 32 | import graphviz |
33 | 33 | from opentelemetry import trace |
34 | | -from typing_extensions import ParamSpec, Unpack |
| 34 | +from typing_extensions import ParamSpec, TypeForm, Unpack |
35 | 35 |
|
36 | 36 | from . import bindings |
37 | 37 | from ._tracing import call_with_current_trace |
@@ -1318,7 +1318,7 @@ def extract( |
1318 | 1318 | cost = cast("COST", extract_report.cost) |
1319 | 1319 | else: |
1320 | 1320 | if not isinstance(runtime_expr.__egg_typed_expr__.expr, (LetRefDecl, UnboundVarDecl)): |
1321 | | - self.register(expr) |
| 1321 | + self._register_extract_root(runtime_expr) |
1322 | 1322 | egg_cost_model = _CostModel(cost_model, self).to_bindings_cost_model() |
1323 | 1323 | egg_sort = self._state.type_ref_to_egg(tp) |
1324 | 1324 | extractor = call_with_current_trace(bindings.Extractor, [egg_sort], self._state.egraph, egg_cost_model) |
@@ -1554,6 +1554,20 @@ def _register_commands(self, cmds: list[Command]) -> None: |
1554 | 1554 | egg_cmds = [egg_cmd for cmd in cmds if (egg_cmd := self._command_to_egg(cmd)) is not None] |
1555 | 1555 | self._state.run_program(*egg_cmds) |
1556 | 1556 |
|
| 1557 | + def _register_extract_root(self, runtime_expr: RuntimeExpr) -> None: |
| 1558 | + """ |
| 1559 | + Register the exact extraction root without synthetic let factoring. |
| 1560 | +
|
| 1561 | + Synthetic lets are a command-size optimization for public registration, |
| 1562 | + but custom-cost extraction immediately evaluates the original root value. |
| 1563 | + Registering a let-factored presentation can leave the custom extractor |
| 1564 | + without a costed parent for that exact value in the direct command API. |
| 1565 | + """ |
| 1566 | + self._add_decls(runtime_expr) |
| 1567 | + action_egg = self._state.action_to_egg(ExprActionDecl(runtime_expr.__egg_typed_expr__), expr_to_let=False) |
| 1568 | + if action_egg is not None: |
| 1569 | + self._state.run_program(bindings.ActionCommand(action_egg)) |
| 1570 | + |
1557 | 1571 | def _command_to_egg(self, cmd: Command) -> bindings._Command | None: |
1558 | 1572 | ruleset_ident = Ident("") |
1559 | 1573 | cmd_decl: CommandDecl |
@@ -1835,7 +1849,7 @@ class Schedule(DelayedDeclarations): |
1835 | 1849 | A composition of some rulesets, either composing them sequentially, running them repeatedly, running them till saturation, or running until some facts are met |
1836 | 1850 | """ |
1837 | 1851 |
|
1838 | | - # Defer declerations so that we can have rule generators that used not yet defined yet |
| 1852 | + # Defer declarations so that we can have rule generators that used not yet defined yet |
1839 | 1853 | schedule: ScheduleDecl |
1840 | 1854 |
|
1841 | 1855 | def __str__(self) -> str: |
@@ -2138,7 +2152,7 @@ def rule(*facts: FactLike, ruleset: None = None, name: str | None = None) -> _Ru |
2138 | 2152 | return _RuleBuilder(facts=_fact_likes(facts), name=name, ruleset=ruleset) |
2139 | 2153 |
|
2140 | 2154 |
|
2141 | | -def var(name: str, bound: type[T], egg_name: str | None = None) -> T: |
| 2155 | +def var(name: str, bound: TypeForm[T], egg_name: str | None = None) -> T: |
2142 | 2156 | """Create a new variable with the given name and type.""" |
2143 | 2157 | return cast("T", _var(name, bound, egg_name=egg_name)) |
2144 | 2158 |
|
|
0 commit comments