Expression::Ptr ExpressionSequence::typeCheck(const StaticContext::Ptr &context, const SequenceType::Ptr &reqType) { Q_ASSERT(reqType); Expression::List::iterator it(m_operands.begin()); const Expression::List::iterator end(m_operands.end()); /* We treat the cardinality differently here by allowing the empty sequence * for each individual Expression, since the Cardinality can be conformed to by * the ExpressionSequence as a whole(which we check for at the end). */ const SequenceType::Ptr testOnlyIT(makeGenericSequenceType(reqType->itemType(), Cardinality::empty() | reqType->cardinality())); for(; it != end; ++it) *it = (*it)->typeCheck(context, testOnlyIT); /* The above loop is only guaranteed to find item type errors, but the cardinality * can still be wrong since the operands were treated individually. */ return CardinalityVerifier::verifyCardinality(Expression::Ptr(this), reqType->cardinality(), context); }
SequenceType::Ptr RemoveFN::staticType() const { const SequenceType::Ptr opType(m_operands.first()->staticType()); const Cardinality c(opType->cardinality()); if(c.minimum() == 0) return makeGenericSequenceType(opType->itemType(), c); else { return makeGenericSequenceType(opType->itemType(), Cardinality::fromRange(c.minimum() - 1, c.maximum())); } }
SequenceType::Ptr SumFN::staticType() const { const SequenceType::Ptr t(m_operands.first()->staticType()); if(m_operands.count() == 1) { return makeGenericSequenceType(t->itemType() | BuiltinTypes::xsInteger, Cardinality::exactlyOne()); } else { return makeGenericSequenceType(t->itemType() | m_operands.at(1)->staticType()->itemType(), t->cardinality().toWithoutMany()); } }
SequenceType::Ptr AvgFN::staticType() const { const SequenceType::Ptr opt(m_operands.first()->staticType()); ItemType::Ptr t(opt->itemType()); if(BuiltinTypes::xsUntypedAtomic->xdtTypeMatches(t)) t = BuiltinTypes::xsDouble; /* xsUntypedAtomics are converted to xsDouble. */ else if(BuiltinTypes::xsInteger->xdtTypeMatches(t)) t = BuiltinTypes::xsDecimal; /* else, it means the type is xsDayTimeDuration, xsYearMonthDuration, * xsDouble, xsFloat or xsAnyAtomicType, which we use as is. */ return makeGenericSequenceType(BuiltinTypes::xsAnyAtomicType->xdtTypeMatches(t) ? t : ItemType::Ptr(BuiltinTypes::xsAnyAtomicType), opt->cardinality().toWithoutMany()); }
SequenceType::Ptr Aggregator::staticType() const { const SequenceType::Ptr t(m_operands.first()->staticType()); ItemType::Ptr itemType(t->itemType()); /* Since we have types that are derived from xs:integer, this ensures that * the static type is xs:integer even if the argument is for * instance xs:unsignedShort. */ if(BuiltinTypes::xsInteger->xdtTypeMatches(itemType) && !itemType->xdtTypeMatches(BuiltinTypes::xsInteger)) { itemType = BuiltinTypes::xsInteger; } return makeGenericSequenceType(itemType, t->cardinality().toWithoutMany()); }
Expression::Ptr InstanceOf::compress(const StaticContext::Ptr &context) { const Expression::Ptr me(SingleContainer::compress(context)); if(me != this || m_operand->has(DisableTypingDeduction)) return me; const SequenceType::Ptr opType(m_operand->staticType()); const ItemType::Ptr targetType(m_targetType->itemType()); const ItemType::Ptr operandType(opType->itemType()); if(m_targetType->cardinality().isMatch(opType->cardinality())) { if(*operandType == *CommonSequenceTypes::Empty || targetType->xdtTypeMatches(operandType)) return wrapLiteral(CommonValues::BooleanTrue, context, this); else if(!operandType->xdtTypeMatches(targetType)) return wrapLiteral(CommonValues::BooleanFalse, context, this); } /* Optimization: rule out the case where instance of will always fail. */ return me; }
Expression::Ptr CastableAs::compress(const StaticContext::Ptr &context) { const Expression::Ptr me(SingleContainer::compress(context)); if(me.data() != this) /* We already managed to const fold, how convenient. */ return me; const AtomicType::Ptr t(m_targetType->itemType()); const SequenceType::Ptr opType(m_operand->staticType()); /* Casting to these always succeeds. */ if(*t == *BuiltinTypes::xsString || *t == *BuiltinTypes::xsUntypedAtomic || (*t == *opType->itemType() && (m_targetType->cardinality().isMatch(opType->cardinality())))) { return wrapLiteral(CommonValues::BooleanTrue, context, this); } else return me; }
SequenceType::Ptr Atomizer::staticType() const { const SequenceType::Ptr opt(m_operand->staticType()); return makeGenericSequenceType(opt->itemType()->atomizedType(), opt->cardinality()); }
SequenceType::Ptr ArithmeticExpression::staticType() const { Cardinality card; /* These variables are important because they ensure staticType() only * gets called once from this function. Before, this lead to strange * semi-infinite recursion involving many arithmetic expressions. */ const SequenceType::Ptr st1(m_operand1->staticType()); const SequenceType::Ptr st2(m_operand2->staticType()); if(st1->cardinality().allowsEmpty() || st2->cardinality().allowsEmpty()) { card = Cardinality::zeroOrOne(); } else card = Cardinality::exactlyOne(); if(m_op == AtomicMathematician::IDiv) return makeGenericSequenceType(BuiltinTypes::xsInteger, card); const ItemType::Ptr t1(st1->itemType()); const ItemType::Ptr t2(st2->itemType()); ItemType::Ptr returnType; /* Please, make this beautiful? */ if(BuiltinTypes::xsTime->xdtTypeMatches(t1) || BuiltinTypes::xsDate->xdtTypeMatches(t1) || BuiltinTypes::xsDateTime->xdtTypeMatches(t1)) { if(BuiltinTypes::xsDuration->xdtTypeMatches(t2)) returnType = t1; else returnType = BuiltinTypes::xsDayTimeDuration; } else if(BuiltinTypes::xsYearMonthDuration->xdtTypeMatches(t1)) { if(m_op == AtomicMathematician::Div && BuiltinTypes::xsYearMonthDuration->xdtTypeMatches(t2)) { returnType = BuiltinTypes::xsDecimal; } else if(BuiltinTypes::numeric->xdtTypeMatches(t2)) returnType = BuiltinTypes::xsYearMonthDuration; else returnType = t2; } else if(BuiltinTypes::xsYearMonthDuration->xdtTypeMatches(t2)) { returnType = BuiltinTypes::xsYearMonthDuration; } else if(BuiltinTypes::xsDayTimeDuration->xdtTypeMatches(t1)) { if(m_op == AtomicMathematician::Div && BuiltinTypes::xsDayTimeDuration->xdtTypeMatches(t2)) { returnType = BuiltinTypes::xsDecimal; } else if(BuiltinTypes::numeric->xdtTypeMatches(t2)) returnType = BuiltinTypes::xsDayTimeDuration; else returnType = t2; } else if(BuiltinTypes::xsDayTimeDuration->xdtTypeMatches(t2)) { returnType = BuiltinTypes::xsDayTimeDuration; } else if(BuiltinTypes::xsDouble->xdtTypeMatches(t1) || BuiltinTypes::xsDouble->xdtTypeMatches(t2)) { returnType = BuiltinTypes::xsDouble; } else if(BuiltinTypes::xsFloat->xdtTypeMatches(t1) || BuiltinTypes::xsFloat->xdtTypeMatches(t2)) { if(m_isCompat) returnType = BuiltinTypes::xsFloat; else returnType = BuiltinTypes::xsDouble; } else if(BuiltinTypes::xsInteger->xdtTypeMatches(t1) && BuiltinTypes::xsInteger->xdtTypeMatches(t2)) { if(m_isCompat) returnType = BuiltinTypes::xsDouble; else { /* "A div B numeric numeric op:numeric-divide(A, B) * numeric; but xs:decimal if both operands are xs:integer" */ if(m_op == AtomicMathematician::Div) returnType = BuiltinTypes::xsDecimal; else returnType = BuiltinTypes::xsInteger; } } else if(m_isCompat && (BuiltinTypes::xsInteger->xdtTypeMatches(t1) && BuiltinTypes::xsInteger->xdtTypeMatches(t2))) { returnType = BuiltinTypes::xsDouble; } else { /* If typeCheck() has been called, our operands conform to expectedOperandTypes(), and * the types are hence either xs:decimals, or xs:anyAtomicType(meaning the static type could * not be inferred), or empty-sequence(). So we use the union of the two types. The combinations * could also be wrong.*/ returnType = t1 | t2; /* However, if we're called before typeCheck(), we could potentially have nodes, so we need to make * sure that the type is at least atomic. */ if(!BuiltinTypes::xsAnyAtomicType->xdtTypeMatches(returnType)) returnType = BuiltinTypes::xsAnyAtomicType; } return makeGenericSequenceType(returnType, card); }
SequenceType::Ptr FirstItemPredicate::staticType() const { const SequenceType::Ptr t(m_operand->staticType()); return makeGenericSequenceType(t->itemType(), t->cardinality().toWithoutMany()); }
Expression::Ptr TypeChecker::applyFunctionConversion(const Expression::Ptr &operand, const SequenceType::Ptr &reqType, const StaticContext::Ptr &context, const ReportContext::ErrorCode code, const Options options) { Q_ASSERT_X(!ReportContext::codeToString(code).isEmpty(), Q_FUNC_INFO, "This test ensures 'code' exists, otherwise codeToString() would assert."); Q_ASSERT(operand); Q_ASSERT(reqType); Q_ASSERT(context); /* Do it in two steps: verify type, and then cardinality. */ const Expression::Ptr cardVerified(CardinalityVerifier::verifyCardinality(operand, reqType->cardinality(), context, code)); return verifyType(cardVerified, reqType, context, code, options); }
SequenceType::Ptr GenericPredicate::staticType() const { const SequenceType::Ptr type(m_operand1->staticType()); return makeGenericSequenceType(type->itemType(), type->cardinality() | Cardinality::zeroOrOne()); }