}
if (exp instanceof Value) {
try {
exp = ExpressionTool.eagerEvaluate(cexp, null);
} catch (XPathException err) {
throw new StaticError(err);
}
} else {
cexp.adoptChildExpression(exp);
exp = cexp;
}
suppliedItemType = reqItemType;
}
// Handle conversion of untypedAtomic to the required type
if (suppliedItemType.getPrimitiveType() == Type.UNTYPED_ATOMIC) {
itemTypeOK = true;
ComputedExpression cexp;
if (allowsMany) {
cexp = new AtomicSequenceConverter(exp, (AtomicType)reqItemType);
} else {
cexp = new CastExpression(exp, (AtomicType)reqItemType, true);
}
if (exp instanceof Value) {
try {
exp = ExpressionTool.eagerEvaluate(cexp, null);
} catch (XPathException err) {
throw new StaticError(err);
}
} else {
cexp.adoptChildExpression(exp);
exp = cexp;
}
suppliedItemType = reqItemType;
}
}
}
// If both the cardinality and item type are statically OK, return now.
if (itemTypeOK && cardOK) {
return exp;
}
// If we haven't evaluated the cardinality of the supplied expression, do it now
if (suppliedCard == -1) {
suppliedCard = exp.getCardinality();
if (!cardOK) {
cardOK = Cardinality.subsumes(reqCard, suppliedCard);
}
}
// If an empty sequence was explicitly supplied, and empty sequence is allowed,
// then the item type doesn't matter
if (cardOK && suppliedCard==StaticProperty.EMPTY) {
return exp;
}
// If we haven't evaluated the item type of the supplied expression, do it now
if (suppliedItemType == null) {
suppliedItemType = exp.getItemType();
}
if (suppliedCard==StaticProperty.EMPTY && ((reqCard & StaticProperty.ALLOWS_ZERO) == 0) ) {
StaticError err = new StaticError(
"An empty sequence is not allowed as the " + role.getMessage(),
ExpressionTool.getLocator(supplied));
err.setErrorCode(role.getErrorCode());
err.setIsTypeError(true);
throw err;
}
// Handle the special rules for 1.0 compatibility mode
if (backwardsCompatible && !allowsMany) {
if (Type.isSubType(reqItemType, Type.STRING_TYPE)) {
if (!Type.isSubType(suppliedItemType, Type.ANY_ATOMIC_TYPE)) {
ComputedExpression cexp = new Atomizer(exp);
cexp.adoptChildExpression(exp);
exp = cexp;
}
ComputedExpression cexp2 = new ConvertToString(exp);
if (exp instanceof Value) {
try {
exp = ExpressionTool.eagerEvaluate(cexp2, null);
} catch (XPathException err) {
throw new StaticError(err);
}
} else {
cexp2.adoptChildExpression(exp);
exp = cexp2;
}
suppliedItemType = Type.STRING_TYPE;
suppliedCard = StaticProperty.EXACTLY_ONE;
cardOK = Cardinality.subsumes(reqCard, suppliedCard);
} else if (reqItemType == Type.NUMBER_TYPE || Type.isSubType(reqItemType, Type.DOUBLE_TYPE)) {
// TODO: in the Nov 2003 draft, the rules have changed so that number() is called
// only if the supplied value doesn't match the expected type. We're currently
// returning different results for round(()) depending on whether the arg value
// is known statically or not.
NumberFn fn = (NumberFn)SystemFunction.makeSystemFunction("number", env.getNamePool());
Expression[] args = new Expression[1];
args[0] = exp;
fn.setArguments(args);
if (exp instanceof Value) {
try {
exp = ExpressionTool.eagerEvaluate(fn, null);
} catch (XPathException err) {
throw new StaticError(err);
}
} else {
fn.adoptChildExpression(exp);
exp = fn;
}
suppliedItemType = Type.DOUBLE_TYPE;
suppliedCard = StaticProperty.EXACTLY_ONE;
cardOK = Cardinality.subsumes(reqCard, suppliedCard);
} else if (reqItemType instanceof AnyNodeTest ||
reqItemType instanceof AnyItemType
|| reqItemType == Type.ANY_ATOMIC_TYPE ) {
// TODO: this last condition isn't in the rules for function calls,
// but is needed for arithmetic expressions
if (Cardinality.allowsMany(suppliedCard)) {
ComputedExpression cexp = new FirstItemExpression(exp);
cexp.adoptChildExpression(exp);
exp = cexp;
}
suppliedCard = StaticProperty.ALLOWS_ZERO_OR_ONE;
cardOK = Cardinality.subsumes(reqCard, suppliedCard);
}
}
// If the required type is atomic, and the supplied type is not statically
// guaranteed to be atomic, add an Atomizer
if ((reqItemType instanceof AtomicType) &&
!(suppliedItemType instanceof AtomicType) &&
!(suppliedCard == StaticProperty.EMPTY)) {
ComputedExpression cexp = new Atomizer(exp);
exp = cexp;
suppliedItemType = exp.getItemType();
suppliedCard = exp.getCardinality();
cardOK = Cardinality.subsumes(reqCard, suppliedCard);
}
// If the required type is a subtype of ATOMIC, and the supplied type is
// capable of producing untyped atomic values, add an Untyped Atomic Converter
if (reqItemType != Type.ANY_ATOMIC_TYPE &&
(reqItemType instanceof AtomicType) &&
(suppliedItemType instanceof AtomicType) &&
(suppliedItemType == Type.ANY_ATOMIC_TYPE ||
suppliedItemType == Type.UNTYPED_ATOMIC_TYPE) &&
!(suppliedCard == StaticProperty.EMPTY)) {
ComputedExpression cexp = new UntypedAtomicConverter(exp, (AtomicType)reqItemType);
cexp.adoptChildExpression(exp);
exp = cexp;
suppliedItemType = exp.getItemType();
suppliedCard = exp.getCardinality();
cardOK = Cardinality.subsumes(reqCard, suppliedCard);
}
// Try a static type check. We only throw it out if the call cannot possibly succeed.
int relation = Type.relationship(suppliedItemType, reqItemType);
if (relation == Type.DISJOINT) {
// The item types may be disjoint, but if both the supplied and required types permit
// an empty sequence, we can't raise a static error. Raise a warning instead.
if (Cardinality.allowsZero(suppliedCard) &&
Cardinality.allowsZero(reqCard)) {
if (suppliedCard != StaticProperty.EMPTY) {
String msg = "Required item type of " + role.getMessage() +
" is " + reqItemType.toString(env.getNamePool()) +
"; supplied value has item type " +
suppliedItemType.toString(env.getNamePool()) +
". The expression can succeed only if the supplied value is an empty sequence.";
env.issueWarning(msg);
}
} else {
StaticError err = new StaticError(
"Required item type of " + role.getMessage() +
" is " + reqItemType.toString(env.getNamePool()) +
"; supplied value has item type " +
suppliedItemType.toString(env.getNamePool()),
ExpressionTool.getLocator(supplied));
err.setErrorCode(role.getErrorCode());
err.setIsTypeError(true);
throw err;
}
}
// }
//}
// Unless the type is guaranteed to match, add a dynamic type check,
// unless the value is already known in which case we might as well report
// the error now.
//if (!itemTypeOK) {
// if (exp instanceof Value) {
// StaticError err = new StaticError(
// "Required type of " + role.getMessage() +
// " is " + reqItemType.toString(env.getNamePool()) +
// "; supplied value has type " +
// suppliedItemType.toString(env.getNamePool()),
// ExpressionTool.getLocator(supplied));
// err.setIsTypeError(true);
// throw err;
// } else {
if (!(relation == Type.SAME_TYPE || relation == Type.SUBSUMED_BY)) {
ComputedExpression cexp = new ItemChecker(exp, reqItemType, role);
cexp.adoptChildExpression(exp);
exp = cexp;
}
// }
// }
if (!cardOK) {
if (exp instanceof Value) {
StaticError err = new StaticError (
"Required cardinality of " + role.getMessage() +
" is " + Cardinality.toString(reqCard) +
"; supplied value has cardinality " +
Cardinality.toString(suppliedCard),
ExpressionTool.getLocator(supplied));
err.setIsTypeError(true);
err.setErrorCode(role.getErrorCode());
throw err;
} else {
ComputedExpression cexp = new CardinalityChecker(exp, reqCard, role);
cexp.adoptChildExpression(exp);
exp = cexp;