cypher-codegen: fix scalar math & numeric arithmetic type inference#95
Merged
Conversation
Adds unit coverage for log/log10/exp/sqrt/trig/ceil/floor/round/e/pi/rand (→ Double), sign (→ Long), and abs (input-preserving). These currently throw "Unrecognized function" — the type checker has no entries for scalar math. Generated with AI Co-Authored-By: AI <ai@example.com>
Adds Neo4j scalar math functions to the type checker. log/log10/exp/sqrt, trig, ceil/floor/round, e/pi/rand and friends return Double; sign returns Long; abs is special-cased to preserve its argument's numeric type. Previously any of these threw "Unrecognized function", failing codegen for queries that project bare math calls. Generated with AI Co-Authored-By: AI <ai@example.com>
Adds unit coverage for numeric arithmetic unification (Long ⊔ Double = Double across operands and operator levels, power → Double) and float-literal typing (1.5 → Double). These currently infer Long because arithmetic types only the first operand and all numeric literals are typed Long. String and list concatenation cases included as regression guards. Generated with AI Co-Authored-By: AI <ai@example.com>
Arithmetic previously typed only the first operand, so Long * Double inferred Long (codegenning Neo4jInt and risking a runtime decode failure on floats). Refactors the addSub/multDiv/power/unary levels into recursive helpers that infer every operand and unify them by the numeric join (Long ⊔ Double = Double); ^ yields Double. Also types numeric literals by their text (1.5/1e3 → Double), so priceLong * 1.5 now infers Double. Non-numeric, String, and list operands are unchanged. Generated with AI Co-Authored-By: AI <ai@example.com>
Generated with AI Co-Authored-By: AI <ai@example.com>
Merged
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
Fixes two numeric type-inference gaps in the
cypher-codegentype checker (src/frontend/InferType.ts):log,log10,exp,sqrt, the trigonometricfunctions,
ceil,floor,round,e(),pi(),rand()and friends were absent from thefunction registry and not special-cased, so the checker threw
CypherTypeError: Unrecognized function '<name>'— a hard codegen failure for any queryprojecting a bare math call (e.g.
RETURN log(x) AS weight).a * b/a ^ bonly inspected the first operand,and numeric
a + breturned the first operand's type. SoLong * Double(orpriceLong * 1.5)inferred
Long, emittingNeo4jIntand risking a runtime decode failure when Neo4j returns afloat. Compounded by all numeric literals typing as
Long(the lexer'sDIGITtoken doesn'tdistinguish ints from floats).
Changes
AGGREGATE_RETURN_TYPES—log/log10/exp/sqrt/ceil/floor/round/sin/cos/tan/cot/asin/acos/atan/atan2/degrees/radians/haversine/e/pi/rand→Double,sign→Long.absis special-cased topreserve its argument's numeric type (
abs(Long)=Long,abs(Double)=Double).inferExpressionTypeintorecursive helpers (
inferAddSubType/inferMultDivType/inferPowerType/inferUnaryType) thatinfer every operand and unify them with a
numericJoin(Long ⊔ Double = Double). ADoubleanywhere widens the result;
^yieldsDouble. Non-numeric (date/duration), String-concatenation,and list-concatenation cases are preserved.
numLitnow types literals by their text —1.5,1e3, and float-suffixedliterals infer
Double; plain integers inferLong. SopriceLong * 1.5correctly infersDouble.src/frontend/CLAUDE.md(function table + a numeric-arithmetic typing rule).Tests
Reproduce-then-fix per gap (RED → GREEN → RED → GREEN):
scalar math functionsdescribe block (log/trig →Double,sign→Long,absinput-preserving) — failed with "Unrecognized function" before the fix.
arithmetic operand typingdescribe block (Long ⊔ Double = Double,^→Double,float literals →
Double, with String/list concatenation as regression guards) — failed inferringLongbefore the fix.Full package unit suite passes (215 tests), including
CypherCodegen.typecheckwhich compilesthe generated output under Effect v4 (confirms the
Double→Schema.Numbercodegen path isunaffected).
eslintandtscare clean.A changeset (
patchfor@evryg/effect-cypher-codegen) is included.