Bug: Coalesce type inference returns Any instead of Integer in aggregate#1710
Open
JPercival wants to merge 1 commit into
Open
Bug: Coalesce type inference returns Any instead of Integer in aggregate#1710JPercival wants to merge 1 commit into
JPercival wants to merge 1 commit into
Conversation
Adds a failing-by-assertion test demonstrating that the translator infers `Coalesce(R, 1)` result type as `Any` instead of `Integer` when `R` is an aggregate accumulator starting from null. The downstream `Multiply` operator wraps the Coalesce result in an unnecessary `As(Integer)` cast. The correct behavior: Coalesce should compute its result type as the common type of concrete (non-Any) arguments, giving `Integer` directly without a cast. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Related IssuesThe following open issues may be related to this PR:
|
|
Formatting check succeeded! |
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #1710 +/- ##
============================================
- Coverage 65.68% 61.98% -3.71%
- Complexity 1645 3944 +2299
============================================
Files 481 210 -271
Lines 27890 20383 -7507
Branches 5553 3884 -1669
============================================
- Hits 18320 12634 -5686
+ Misses 7231 6139 -1092
+ Partials 2339 1610 -729 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
JPercival
added a commit
that referenced
this pull request
Mar 28, 2026
The Aggregate parity test skip is not a regression — our type inference is more correct. Document the pattern (Any-typed aggregate accumulators losing precision in Coalesce resolution) so future agents can recognize similar cases where the legacy inserts unnecessary casts that our pipeline correctly omits. References PR #1710. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
JPercival
added a commit
that referenced
this pull request
Mar 28, 2026
…ypeResolver and ElmEmitter Resolve model types (QUICK Element, Extension, etc.) through loaded models instead of only the system type namespace. This completes parity for the TupleAndClassConversions test, bringing results to 31/32 (1 intentional skip: Aggregate legacy bug #1710). TypeResolver: - Add resolveNamedType() and resolveModelType() for system+model lookup - Update resolveTypeSpecifier to handle qualified and unqualified model types - Update inferInstanceLiteralType to delegate to resolveTypeSpecifier EmissionContext: - Add resolveTypeQName() for name-to-QName with correct model namespace - Add dataTypeToQName() and dataTypeToTypeSpecifier() that bypass TypeBuilder's system-only ModelResolver for model types - Replace all operatorRegistry.typeBuilder.dataTypeToQName/TypeSpecifier calls across codegen package (EmissionContext, CollectionOperatorEmission, IntervalOperatorEmission) TypeOperatorEmission: - Update emitTypeSpecifier, emitImplicitCastExpression to use resolveTypeQName - Fix emitConversionExpression for class/tuple conversions: emit As with asType (QName) for named types, asTypeSpecifier for complex types, matching legacy buildAs behavior FullParityTest: - Register QuickModelInfoProvider in test model manager - Update results documentation
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.



Summary
Coalesce(R, 1)inside an aggregate with null starting value infers result typeAnyinstead ofIntegerMultiplyto insert an unnecessaryAs(Integer)cast around the Coalesce resultReproduction
define Sequence: { 1, 2, 3 } define Factorial: Sequence X aggregate R: Coalesce(R, 1) * XThe aggregate accumulator
Rstarts asnull(typeAny).Coalesce(R, 1)resolves through generic operator overload matching, which unifiesTtoAnybecause the first arg has typeAny. This gives the Coalesce a result type ofAny, forcing theMultiplyoperator to insert anAs(Integer)cast on its first operand.Expected ELM:
Multiply(Coalesce(QueryLetRef("R"), Literal(1)), AliasRef("X"))Actual ELM:
Multiply(As(Integer, Coalesce(QueryLetRef("R"), Literal(1))), AliasRef("X"))Test
The included test (
AggregateCoalesceTypeBugTest) demonstrates the bug by asserting that the firstMultiplyoperand is wrapped inAs— this assertion passes, confirming the unnecessary cast exists.Test plan
AggregateCoalesceTypeBugTestpasses (demonstrates the bug)assertIs<Coalesce>(firstOperand)🤖 Generated with Claude Code