Repository navigation
The LINQ compiler gives a constant, a nullable operand and sgn(0) the value evaluation gives - #2242
Merged
Merged
Conversation
… value evaluation gives Three defects in the LINQ compiler, found by work/compilesweep. A constant over Complex (#2235). A constant is compiled as the narrowest type that holds it, -1 as a long, and a function widens a long only to double. So in an expression compiled over Complex, sqrt(-1), ln(-1) and arcsin(2) were Math's NaN, widened to (NaN, 0), and 1/0 was +oo, where evaluation has no value. FastExpression, whose constants are Complex, was right. Where any argument or the result is Complex, BuildTree now converts each constant to Complex. Over double, a value that is not real still has none. A nullable operand (#2237). An Iverson bracket compiles to an int?, and a provided integer constant to a long?. No function has a definition for either, and the widening table has neither. So tan(iverson(pi > 0)) threw KeyNotFoundException, and abs, floor and sgn of one threw AngouriBugException, which asks for a bug report. The unary and binary converters now take a nullable number as a double, NaN for none, before anything else. A statement's bool? stays as it is. sgn(0) over Complex (#2238). The definition was z / |z|, which is 0/0 at 0. It is the Signum extension FastExpression already used, which is 0 there. LinqCompilationValueTest compares LINQ over Complex and FastExpression with evaluation on 16 expressions, among them six constants whose values are not real, 1/0, five nullable operands and sgn at 0. It also checks the double compiler on both kinds. 17 of its 21 cases fail on master. sgn(-1 provided false) is left out: evaluation gives 1 there, which is wrong, and is #2241. Fixes #2235. Fixes #2237. Fixes #2238. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #2242 +/- ##
==========================================
+ Coverage 86.68% 86.70% +0.02%
==========================================
Files 310 310
Lines 67766 67775 +9
Branches 19660 19663 +3
==========================================
+ Hits 58744 58767 +23
+ Misses 4909 4896 -13
+ Partials 4113 4112 -1
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
Rafael-SOWNet
added a commit
that referenced
this pull request
Oct 30, 2026
Signumf's rule took a real number's sign from its EDecimal, and EDecimal's Sign of NaN is 1. So the signum of anything without a value was 1: sgn(NaN), sgn(0/0), sgn(-1 provided false), and 1 + sgn(-1 provided pi < 3) was 2. That is a value where there is none, on 2.6.0 as on master. Number.Signum already gave NaN for NaN; only this rule did not. A NaN real is now its own signum. abs, sin and the rest already passed a NaN through. Found by comparing the compiled sgn with evaluation for #2242. The compiled value was NaN there, and evaluation's was 1. SignumOfNaNTest: five spellings of a missing value, by Evaled and by Simplify, all failing on master; five signs that stay as they were; and the compiled value. canoncheck-baseline.tsv loses 52 findings, and gains none. Each was an InnerSimplified order disagreement on a sum with sgn(a / 0) in it. a / 0 has no value, and its signum was 1, so the two orders of the sum came out as different expressions. Now that the signum is NaN, the sum is NaN in either order. The baseline goes from 2091 to 2039. Fixes #2241. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Rafael-SOWNet
added a commit
that referenced
this pull request
Oct 30, 2026
#2242 widened an Iverson bracket, an int?, and a provided integer, a long?, to double before a function took it. A piecewise's cases did not pass through that widening, so a piecewise with such a case still threw KeyNotFoundException, alone, under a function or nested in another piecewise: MaxType, which picks the type the cases are taken in, has no int? or long?. sin(piecewise(iverson(x > 0) provided x > 0, sin(2))) was one. HandlePiecewise now widens each numeric case as a function's operand is widened. On 2.6.0 an Iverson bracket did not compile at all, and a provided integer in a piecewise over double threw KeyNotFoundException too: piecewise(piecewise(-1 provided x > 0, 3) provided x > 0, x) + x at 1. The #2237 line in BREAKING-CHANGES.md now says which of the two threw, and takes in the piecewise. PiecewiseOfNullableCompilationTest compares seven such expressions, under both compilers, with evaluation. All seven fail on master. Part of #2237. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Rafael-SOWNet
added a commit
that referenced
this pull request
Oct 30, 2026
#2246) #2242 widened an Iverson bracket, an int?, and a provided integer, a long?, to double before a function took it. A piecewise's cases did not pass through that widening, so a piecewise with such a case still threw KeyNotFoundException, alone, under a function or nested in another piecewise: MaxType, which picks the type the cases are taken in, has no int? or long?. sin(piecewise(iverson(x > 0) provided x > 0, sin(2))) was one. HandlePiecewise now widens each numeric case as a function's operand is widened. On 2.6.0 an Iverson bracket did not compile at all, and a provided integer in a piecewise over double threw KeyNotFoundException too: piecewise(piecewise(-1 provided x > 0, 3) provided x > 0, x) + x at 1. The #2237 line in BREAKING-CHANGES.md now says which of the two threw, and takes in the piecewise. PiecewiseOfNullableCompilationTest compares seven such expressions, under both compilers, with evaluation. All seven fail on master. Part of #2237. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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.
Fixes #2235. Fixes #2237. Fixes #2238. Three defects in the LINQ compiler, all found by
work/compilesweep.A constant over
Complex(#2235). A constant is compiled as the narrowest type that holds it,-1as along, and a function widens alongonly todouble. So in an expression compiled overComplex,sqrt(-1),ln(-1)andarcsin(2)came out asMath'sNaN, widened to(NaN, 0). And1/0was+oo, where evaluation has no value. FastExpression, whose constants areComplex, was right. Where any argument or the result isComplex,BuildTreenow converts each constant toComplex. Overdouble, a value that is not real still has none.A nullable operand (#2237). An Iverson bracket compiles to an
int?, and aprovidedinteger constant to along?. No function has a definition for either, and the widening table has neither. Sotan(iverson(pi > 0))threwKeyNotFoundException, andabs,floorandsgnof one threwAngouriBugException, which asks for a bug report. The unary and binary converters now take a nullable number as adouble,NaNfor none, before anything else. A statement'sbool?stays as it is.sgn(0)overComplex(#2238). The definition wasz / |z|, which is0/0at0. It now uses theSignumextension FastExpression already used, which is0there."x + sqrt(-1)".ToEntity().Compile<Complex, Complex>("x")(0)(NaN, 0)(6.1e-17, 1)"x + 1/0".ToEntity().Compile<Complex, Complex>("x")(0)(Infinity, 0)(NaN, NaN)"x + sgn(-1 provided pi > 3)".ToEntity().Compile<Complex, Complex>("x")(1)AngouriBugException(0, 0)"sgn(x)".ToEntity().Compile<Complex, Complex>("x")(0)(NaN, NaN)(0, 0)Tests.
LinqCompilationValueTestcompares LINQ overComplexand FastExpression with evaluation on 16 expressions:1/0;sgnat0.It also checks the
doublecompiler on both kinds. 17 of its 21 cases fail on master. Full suite 18134/0, interactive trio, AOT smoke 73/0, all frameworks build.sgn(-1 provided false)is left out of the test: evaluation gives1there, which is wrong. That is filed as #2241, with its fix to follow.🤖 Generated with Claude Code