override def targetTypeForSubexpression()

in daffodil-core/src/main/scala/org/apache/daffodil/core/dpath/Expression.scala [481:541]


  override def targetTypeForSubexpression(subExpr: Expression): NodeInfo.Kind = {
    //
    // Note: the subExpr might not be exactly our ifor child expression
    // because if ifor was a function call, then the resulting function
    // object will have been created and given this as its parent pointer.
    //
    Assert.invariant(subExpr == ifor || ifor.isInstanceOf[FunctionCallExpression])
    // The result of this function will be used to coerce the result of the
    // expression to the target type. However, we do not always want to allow
    // type coercion even when it might be possible. For example, if the
    // targetType is xs:string and the expression is { 5 }, we do not want to
    // coerce that to the string "5", but instead want to throw an SDE
    // signifying that we expected a string but the expression result was a
    // numeric. But we sometimes do want coercion for usability purposes. For
    // example, if the result of an expression is a int but the type is long,
    // then we should still allow that coercion. Below we allow coercion
    // between decimal-like types where precision would not be lost, and all
    // integer-like types (which check for precision loss when evaluated).
    val allowCoercion = (inherentType, targetType) match {
      case (_, _) if inherentType == targetType => true
      case (_, _)
          if (inherentType
            .isSubtypeOf(NodeInfo.String) && targetType.isSubtypeOf(NodeInfo.String)) =>
        true
      case (_, _)
          if (inherentType
            .isSubtypeOf(NodeInfo.Integer) && targetType.isSubtypeOf(NodeInfo.Integer)) =>
        true
      case (_, NodeInfo.Float) if (inherentType.isSubtypeOf(NodeInfo.Integer)) => true
      case (_, NodeInfo.Double) if (inherentType.isSubtypeOf(NodeInfo.Integer)) => true
      case (_, NodeInfo.Decimal) if (inherentType.isSubtypeOf(NodeInfo.Integer)) => true
      case (NodeInfo.Float, NodeInfo.Double) => true
      case (NodeInfo.Float, NodeInfo.Decimal) => true
      case (NodeInfo.Double, NodeInfo.Decimal) => true
      case (NodeInfo.Nothing, _) => true
      case (_, NodeInfo.AnyType) => true
      case _ => false
    }

    if (!allowCoercion) {
      if (tunable.allowExpressionResultCoercion) {
        SDW(
          WarnID.DeprecatedExpressionResultCoercion,
          "In expression %s, result type (%s) should be manually cast to the expected type (%s) with the appropriate constructor." +
            "Performing deprecated automatic conversion.",
          wholeExpressionText,
          inherentType,
          targetType
        )
      } else {
        SDE(
          "In expression %s, result type (%s) must be manually cast to the expected type (%s) with the approrpriate constructor.",
          wholeExpressionText,
          inherentType,
          targetType
        )
      }
    }

    targetType
  }