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
}