This is an automated email from the ASF dual-hosted git repository.

slawrence pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/daffodil.git


The following commit(s) were added to refs/heads/main by this push:
     new 104cb6397 Ensure if-expressions converge to a primitive type
104cb6397 is described below

commit 104cb63977229540959d1a2412097890d6bf4b61
Author: Steve Lawrence <[email protected]>
AuthorDate: Mon Oct 20 08:11:46 2025 -0400

    Ensure if-expressions converge to a primitive type
    
    Commit 6650eb918e modified if-expressions to use typeLeastUpperBound
    instead of generalizeArgAndResultTypesForNumericOp to calculate the
    result type of the if-expression. The thinking was that if-expressions
    aren't really numeric operations and so shouldn't use the same logic.
    
    However, typeLeastUpperBound can return non-primitive types which can
    lead to issues. For example, if one branch of an if-expression returns
    xs:double and the other returns xs:int, then the least upper bound is
    SignedNumeric, which is not a primitive type and can lead to failures in
    cases where DPath operations require an actual type.
    
    We fix this by reverting back to using 
generalizeArgAndResultTypesForNumericOp.
    Although this function is intended for numeric operations, the same
    logic of promoting different numeric types to a single primitive type is
    needed for if-expressions. And it is not too far fetched to say that if
    the branches of an if-expression are numeric, then the if-expression is
    essentially a numeric operation.
    
    DAFFODIL-2574
---
 .../scala/org/apache/daffodil/core/dpath/Expression.scala    | 12 ++++++++++--
 .../daffodil/section23/dfdl_expressions/expressions.tdml     |  8 ++++++++
 .../section23/dfdl_expressions/TestDFDLExpressions.scala     |  2 ++
 3 files changed, 20 insertions(+), 2 deletions(-)

diff --git 
a/daffodil-core/src/main/scala/org/apache/daffodil/core/dpath/Expression.scala 
b/daffodil-core/src/main/scala/org/apache/daffodil/core/dpath/Expression.scala
index 0a50bde5b..a8634c116 100644
--- 
a/daffodil-core/src/main/scala/org/apache/daffodil/core/dpath/Expression.scala
+++ 
b/daffodil-core/src/main/scala/org/apache/daffodil/core/dpath/Expression.scala
@@ -516,8 +516,16 @@ case class IfExpression(ifthenelse: List[Expression]) 
extends ExpressionLists(if
 
   override lazy val inherentType = {
     (thenPart.inherentType, elsePart.inherentType) match {
-      case (left: NodeInfo.Numeric.Kind, right: NodeInfo.Numeric.Kind) =>
-        NodeInfoUtils.typeLeastUpperBound(left, right)
+      case (left: NodeInfo.Numeric.Kind, right: NodeInfo.Numeric.Kind) => {
+        // if-expressions aren't technically numeric operations, but we still 
need the same
+        // logic as numeric operations used to promote both the left and right 
branches to the
+        // same primitive numeric type. Note that if we instead use something 
like
+        // typeLeastUpperBound, we could end up with a non-primitive type 
(e.g. SignedNumeric),
+        // which can break other parts of DPath that require primitive types.
+        val (_, resultType) =
+          NodeInfoUtils.generalizeArgAndResultTypesForNumericOp(op, left, 
right)
+        resultType
+      }
       case (left, right) if left == right => left
       case (left, right) if right == NodeInfo.Nothing => left
       case (left, right) if left == NodeInfo.Nothing => right
diff --git 
a/daffodil-test/src/test/resources/org/apache/daffodil/section23/dfdl_expressions/expressions.tdml
 
b/daffodil-test/src/test/resources/org/apache/daffodil/section23/dfdl_expressions/expressions.tdml
index 9dc1ae1ed..14afc3722 100644
--- 
a/daffodil-test/src/test/resources/org/apache/daffodil/section23/dfdl_expressions/expressions.tdml
+++ 
b/daffodil-test/src/test/resources/org/apache/daffodil/section23/dfdl_expressions/expressions.tdml
@@ -7430,6 +7430,9 @@ blastoff
 
     <xs:element name="precision01" type="xs:double" dfdl:inputValueCalc="{ 
xs:int(3) + xs:double(xs:int(34) div xs:double(60.0)) }" />
     <xs:element name="precision02" type="xs:double" dfdl:inputValueCalc="{ 
xs:integer(3) + xs:double(xs:integer(34) div xs:double(60.0)) }" />
+
+    <xs:element name="if01" type="xs:int" dfdl:inputValueCalc="{ 
fn:round-half-to-even(if (fn:true()) then xs:double(10.5) else xs:int(1)) }" />
+
   </tdml:defineSchema>
 
   <tdml:parserTestCase name="div01" root="div01" model="XPathMath" 
description="Section 23 - DFDL Expressions - div">
@@ -7783,6 +7786,11 @@ blastoff
     
<tdml:infoset><tdml:dfdlInfoset><precision02>3.566666666666667</precision02></tdml:dfdlInfoset></tdml:infoset>
   </tdml:parserTestCase>
 
+  <tdml:parserTestCase name="if01" root="if01" model="XPathMath" 
description="Section 23 - DFDL Expressions - div">
+    <tdml:document></tdml:document>
+    
<tdml:infoset><tdml:dfdlInfoset><if01>10</if01></tdml:dfdlInfoset></tdml:infoset>
+  </tdml:parserTestCase>
+
   <tdml:defineSchema name="DFDLCheckRange">
     <xs:include 
schemaLocation="/org/apache/daffodil/xsd/DFDLGeneralFormat.dfdl.xsd"/>
     <dfdl:format ref="ex:GeneralFormat" />
diff --git 
a/daffodil-test/src/test/scala/org/apache/daffodil/section23/dfdl_expressions/TestDFDLExpressions.scala
 
b/daffodil-test/src/test/scala/org/apache/daffodil/section23/dfdl_expressions/TestDFDLExpressions.scala
index 47295ae7d..1f24cd24e 100644
--- 
a/daffodil-test/src/test/scala/org/apache/daffodil/section23/dfdl_expressions/TestDFDLExpressions.scala
+++ 
b/daffodil-test/src/test/scala/org/apache/daffodil/section23/dfdl_expressions/TestDFDLExpressions.scala
@@ -420,6 +420,8 @@ class TestDFDLExpressions extends TdmlTests {
   @Test def precision01 = test
   @Test def precision02 = test
 
+  @Test def if01 = test
+
   // DFDL-1617 - should detect errors due to query-style expressions
   @Test def query_style_01 = test
   @Test def query_style_02 = test

Reply via email to