OK, I think I may have nailed it...
With the following form:
date: year, default=2019
result0 = decimal-date-time("")
result1 = decimal-date-time(${year})
result2 = decimal-date-time(concat(${year},""))
result3 = decimal-date-time(concat(${year},"2019-01-01"))
result4 = decimal-date-time(concat(${year},"-01-01"))
Validate barfs on result4! I think what is happening is that, as part of validating function argument type checking, Validate is actually attempting to dynamically evaluate the calculate XPath expressions (!) in an attempt to determine whether the date function's (string) argument is in fact a valid date string. Unfortunately, this is before the form has actually started executing, so $(year) is still basically null, (even though I explicitly gave it a default value, although that's not the root of the problem). Which is why result3 is actually deemed to be OK (wrong!) - because concat(null,"2019-01-01") -> "2019-01-01"
which is a valid date; but concat(null,"-01-01") -> "-01-01"
is not a valid date. So Validate incorrectly determines there a type mismatch in the latter, and throws a error "XPathTypeMismatchException: The problem was located in calculate expression for ${result4} XPath evaluation: type mismatch converting to date".
I believe the root of the problem is that Validate probably should not attempt to dynamically evaluate XPath expressions in order to guess the type of (string) operands when checking XPath function arguments. The string value of these arguments can only be reliably determined at actual runtime, for all the reasons described above. There is fundamentally a limited ability to perform XPath type checking during a static analysis of a form's XPath expressions, so I think in this case we should instead leave it to the runtime javaRosa XPath evaluator (in Collect) throw a NaN/NULL/whatever when it fails to convert (string) arguments to their expected type.
But this seems like it could be a not insignificant change in javaRosa/Validate behavior, so I'm not sure how best to proceed. Thoughts anyone? @yanokwa, @ggalmazor, @martijnr, @aurdipas ? [I can move over to Slack, and/or open a github issue to continue the technical discussion if preferred]