Repository navigation
feat: type SQL macro calls everywhere, with optional returns, TYPE OF, ANY families and __cte - #1247
Merged
Merged
Conversation
…name Polyglot lowers __polyglot_typed(expr, 'TYPE') into a typed expression node. Authored SQL may not use that name, and the analysis cache format moves to v3 so entries typed by the old post-pass are dropped.
…ed query Expansion returns the byte range of every expression macro call, top-level and nested, through body substitution, declaration rendering, Python macro splicing and cursor canonicalisation. Calls inside Python macro arguments are not recorded.
The analysed text wraps each call to a macro with returns in the typed marker; the compiled SQL is unchanged. Binding diagnostics map back through the marker insertions.
Replace the declared-output post-pass with the typed marker: analysis types every recorded call from its SQL and falls back to the declared return type only when inference is unknown. Typed calls flow through compiled facts and rule rows, and the explicit-cast rule accepts whole macro calls with a return type by position.
An expression macro may omit returns; its calls are then typed by inference alone. When returns is declared, the body is typed once from stand-ins for its declared arguments, and a known type of another family is reported as P024 at the macro file. K003 and the explicit-cast rule suggest declaring returns when an output is one call to a macro without it.
A CTE-list macro call may pass __cte := name. The macro's last CTE then takes that name and its other CTEs become <name>__<cte>, renamed with their references by parsing; arguments are never renamed. Calls without __cte behave as before, and a repeated call now suggests __cte. The formatter also accepts comma-less CTE-list calls in a row.
returns TYPE OF <argument> types each call as its argument through the typed-like analysis marker, where the body's own type is unknown. An ANY argument may be narrowed to ANY NUMERIC, ANY TEXT or ANY TEMPORAL: calls are checked against the family at the argument, and the body is checked at the macro file with the family's widest member (P025). Bumps polyglot to the typed-like marker.
A marker asserted its type while an upstream star model's columns were still untyped, so a known column inside a call took the declared type. Such models are now enriched once their inputs are known, and the enrichment's types replace the earlier assertions.
…and shape-aware refinement
…ad the name they shadow
kvlonge
enabled auto-merge (squash)
October 24, 2026 14:23
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.
Why
A SQL macro's
returnstype was applied by a post-pass that only saw whole select items in a fewpositions,
returnswas mandatory but never checked against the body, and a CTE-list macro couldbe called only once per model.
Changes
returnsapplies wherever the expanded SQL's type is unknown, or partly unknown of the same shape. A known
type stands. Compiled SQL is unchanged. Post-pass removed. A marker never changes how a call's
position parses in the adapter's dialect; bare-word calls stay unmarked.
returnsis optional and validated per adapter dialect, with decimal ranges (P015). It ischecked against a body whose type is known, not guessed, at the macro file (
P024).returns TYPE OF <argument>;ANY NUMERIC,ANY TEXT,ANY TEMPORALarguments, checked at thecall (
P017) and in the body (P025).__cte := namenames the CTEs a CTE-list call inserts, renaming references by scope,including parenthesised joins.
K003andSQBRCONTRACT105suggestreturns;SQBRCONTRACT105judges a whole typed call by it.__polyglot_typedreserved.ORDER BY ALLand decimals wider than adialect holds keep their behaviour.
Verification
returnsforms, shapes, adapters;TYPE OF;families;
__ctescoping and builds; warm cache;--since.make test,make check-ci,make compiler-differential. Changed goldens:sql-macro-invalid-definition(missingreturnsis valid),sql-macro-cte-name-clash(helpsuggests
__cte); new:sql-macro-returns-disagrees-with-body,sql-macro-body-misuses-an-any-family. Generated-type golden: invalid nestedDECIMAL(0)is nowspelled generically.