SequenceType::Ptr SubsequenceFN::staticType() const { const SequenceType::Ptr opType(m_operands.first()->staticType()); const Cardinality opCard(opType->cardinality()); /* Optimization: we can do much stronger inference here. If the length is a * constant, we can constrain the range at least upwards of the * cardinality, for instance. */ /* The subsequence(expr, 1, 1), add empty-sequence() to the static type. * * Note that we cannot do all these inferences before we've typechecked our * operands. The only known case of where our staticType() is called before * typeCheck() is through xmlpatternsview, although it wouldn't be * surprising if the more exotic paths can achieve that too. */ if(m_hasTypeChecked && m_operands.at(1)->isEvaluated() && m_operands.count() == 3 && m_operands.at(2)->isEvaluated() && m_operands.at(1)->as<Literal>()->item().as<Numeric>()->round()->toInteger() == 1 && m_operands.at(2)->as<Literal>()->item().as<Numeric>()->round()->toInteger() == 1) { return makeGenericSequenceType(opType->itemType(), opCard.toWithoutMany()); } else { return makeGenericSequenceType(opType->itemType(), opCard | Cardinality::zeroOrOne()); } }
Expression::Ptr CastableAs::typeCheck(const StaticContext::Ptr &context, const SequenceType::Ptr &reqType) { checkTargetType(context); const Expression::Ptr me(SingleContainer::typeCheck(context, reqType)); return me; if(BuiltinTypes::xsQName->xdtTypeMatches(m_targetType->itemType())) { const SequenceType::Ptr seqt(m_operand->staticType()); /* We can cast a string literal, an xs:QName value, and an * empty sequence(if empty is allowed), to xs:QName. */ if(m_operand->is(IDStringValue) || BuiltinTypes::xsQName->xdtTypeMatches(seqt->itemType()) || (*seqt->itemType() == *CommonSequenceTypes::Empty && m_targetType->cardinality().allowsEmpty())) { return wrapLiteral(CommonValues::BooleanTrue, context, this)->typeCheck(context, reqType); } else return wrapLiteral(CommonValues::BooleanFalse, context, this)->typeCheck(context, reqType); } else { /* Let the CastingPlatform look up its AtomicCaster. */ prepareCasting(context, m_operand->staticType()->itemType()); return me; } }
SequenceType::Ptr IfThenClause::staticType() const { const SequenceType::Ptr t1(m_operand2->staticType()); const SequenceType::Ptr t2(m_operand3->staticType()); return makeGenericSequenceType(t1->itemType() | t2->itemType(), t1->cardinality() | t2->cardinality()); }
SequenceType::Ptr InsertBeforeFN::staticType() const { const SequenceType::Ptr t1(m_operands.first()->staticType()); const SequenceType::Ptr t2(m_operands.last()->staticType()); return makeGenericSequenceType(t1->itemType() | t2->itemType(), t1->cardinality() + t2->cardinality()); }
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()); } }
Expression::Ptr InstanceOf::compress(const StaticContext::Ptr &context) { const Expression::Ptr me(SingleContainer::compress(context)); if(me.data() != this || m_operand->has(DisableTypingDeduction)) return me; const SequenceType::Ptr opType(m_operand->staticType()); const ItemType::Ptr itType(m_targetType->itemType()); const ItemType::Ptr ioType(opType->itemType()); if(m_targetType->cardinality().isMatch(opType->cardinality())) { if(itType->xdtTypeMatches(ioType)) return wrapLiteral(CommonValues::BooleanTrue, context, this); else if(!ioType->xdtTypeMatches(itType)) { return wrapLiteral(CommonValues::BooleanFalse, context, this); } } /* The cardinality is not guaranteed to match; it will need testing. */ else if(!ioType->xdtTypeMatches(itType)) { /* There's no way it's gonna match. The cardinality is not only * wrong, but the item type as well. */ return wrapLiteral(CommonValues::BooleanFalse, context, this); } return me; }
bool SequenceType::matches(const SequenceType::Ptr other) const { Q_ASSERT(other); return itemType()->xdtTypeMatches(other->itemType()) && cardinality().isMatch(other->cardinality()); }
SequenceType::Ptr CombineNodes::staticType() const { const SequenceType::Ptr t1(m_operand1->staticType()); const SequenceType::Ptr t2(m_operand2->staticType()); Cardinality card; /* Optimization: the cardinality can be better inferred for * Intersect and Except, although it's not trivial code. */ if(m_operator == Union) card = t1->cardinality() | t2->cardinality(); else /* Except. */ card = Cardinality::zeroOrMore(); return makeGenericSequenceType(t1->itemType() | t2->itemType(), card); }
SequenceType::Ptr DistinctValuesFN::staticType() const { const SequenceType::Ptr t(m_operands.first()->staticType()); return makeGenericSequenceType(t->itemType(), t->cardinality().allowsMany() ? Cardinality::oneOrMore() : Cardinality::exactlyOne()); }
CastableAs::CastableAs(const Expression::Ptr &operand, const SequenceType::Ptr &tType) : SingleContainer(operand), m_targetType(tType) { Q_ASSERT(tType); Q_ASSERT(!tType->cardinality().allowsMany()); Q_ASSERT(tType->itemType()->isAtomicType()); }
bool BySequenceTypeIdentifier::matches(const Expression::Ptr &expr) const { const SequenceType::Ptr t(expr->staticType()); return m_seqType->itemType()->xdtTypeMatches(t->itemType()) && m_seqType->cardinality().isMatch(t->cardinality()); }
SequenceType::Ptr ForClause::staticType() const { const SequenceType::Ptr returnType(m_operand2->staticType()); return makeGenericSequenceType(returnType->itemType(), m_operand1->staticType()->cardinality() * /* multiply operator */ returnType->cardinality()); }
SequenceType::Ptr Path::staticType() const { const SequenceType::Ptr opType(m_operand2->staticType()); /* For each parent step, we evaluate the child step. So multiply the two * cardinalities. */ return makeGenericSequenceType(opType->itemType(), m_operand1->staticType()->cardinality() * opType->cardinality()); }
Expression::Ptr CountFN::typeCheck(const StaticContext::Ptr &context, const SequenceType::Ptr &reqType) { if(*CommonSequenceTypes::EBV->itemType() == *reqType->itemType()) { return ByIDCreator::create(IDExistsFN, operands(), context, this)->typeCheck(context, reqType); } else return FunctionCall::typeCheck(context, reqType); }
Expression::Ptr CastAs::typeCheck(const StaticContext::Ptr &context, const SequenceType::Ptr &reqType) { checkTargetType(context); const SequenceType::Ptr seqt(m_operand->staticType()); ItemType::Ptr t(seqt->itemType()); /* Special case xs:QName */ if(BuiltinTypes::xsQName->xdtTypeMatches(m_targetType->itemType())) { /* Ok, We're casting to xs:QName. */ if(m_operand->is(IDStringValue)) /* A valid combination, let's do the cast. */ return castToQName(context)->typeCheck(context, reqType); else if(BuiltinTypes::xsQName->xdtTypeMatches(t)) return m_operand->typeCheck(context, reqType); else if(seqt->cardinality().isEmpty() && m_targetType->cardinality().allowsEmpty()) return EmptySequence::create(this, context); else if(!(seqt->cardinality().isEmpty() && !m_targetType->cardinality().allowsEmpty())) { context->error(QtXmlPatterns::tr("When casting to %1 or types " "derived from it, the source " "value must be of the same type, " "or it must be a string literal. " "Type %2 is not allowed.") .arg(formatType(context->namePool(), BuiltinTypes::xsQName)) .arg(formatType(context->namePool(), seqt)), ReportContext::XPTY0004, this); return Expression::Ptr(this); } } const Expression::Ptr me(SingleContainer::typeCheck(context, reqType)); /* Type may have changed, such as that atomization has been applied. */ t = m_operand->staticType()->itemType(); if(m_targetType->itemType()->xdtTypeMatches(t) && !BuiltinTypes::xsDayTimeDuration->xdtTypeMatches(t) && !BuiltinTypes::xsYearMonthDuration->xdtTypeMatches(t)) { /* At least casting is superflorous. */ if(m_operand->staticType()->cardinality().isMatch(m_targetType->cardinality())) return m_operand; /* The whole cast expression is redundant. */ else { /* Only cardinality check is needed, rewrite to CardinalityVerifier. */ return Expression::Ptr(new CardinalityVerifier(m_operand, m_targetType->cardinality(), ReportContext::FORG0001)); } } /* Let the CastingPlatform look up its AtomicCaster. */ prepareCasting(context, t); return me; }
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 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); }
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; }
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; }
SequenceType::Ptr Atomizer::staticType() const { const SequenceType::Ptr opt(m_operand->staticType()); return makeGenericSequenceType(opt->itemType()->atomizedType(), opt->cardinality()); }
SequenceType::Ptr GenericPredicate::staticType() const { const SequenceType::Ptr type(m_operand1->staticType()); return makeGenericSequenceType(type->itemType(), type->cardinality() | Cardinality::zeroOrOne()); }
Expression::Ptr TypeChecker::verifyType(const Expression::Ptr &operand, const SequenceType::Ptr &reqSeqType, const StaticContext::Ptr &context, const ReportContext::ErrorCode code, const Options options) { const ItemType::Ptr reqType(reqSeqType->itemType()); const Expression::Properties props(operand->properties()); /* If operand requires a focus, do the necessary type checking for that. */ if(props.testFlag(Expression::RequiresFocus) && options.testFlag(CheckFocus)) { const ItemType::Ptr contextType(context->contextItemType()); if(contextType) { if(props.testFlag(Expression::RequiresContextItem)) { Q_ASSERT_X(operand->expectedContextItemType(), Q_FUNC_INFO, "When the Expression sets the RequiresContextItem property, it must " "return a type in expectedContextItemType()"); const ItemType::Ptr expectedContextType(operand->expectedContextItemType()); /* Allow the empty sequence. We don't want to trigger XPTY0020 on ()/... . */ if(!expectedContextType->xdtTypeMatches(contextType) && contextType != CommonSequenceTypes::Empty) { context->error(wrongType(context->namePool(), operand->expectedContextItemType(), contextType), ReportContext::XPTY0020, operand.data()); return operand; } } } else { context->error(QtXmlPatterns::tr("The focus is undefined."), ReportContext::XPDY0002, operand.data()); return operand; } } SequenceType::Ptr operandSeqType(operand->staticType()); ItemType::Ptr operandType(operandSeqType->itemType()); /* This returns the operand if the types are identical or if operandType * is a subtype of reqType. */ if(reqType->xdtTypeMatches(operandType) || *operandType == *CommonSequenceTypes::Empty) return operand; /* Since we haven't exited yet, it means that the operandType is a super type * of reqType, and that there hence is a path down to it through the * type hierachy -- but that doesn't necessarily mean that a up-cast(down the * hierarchy) would succeed. */ Expression::Ptr result(operand); if(reqType->isAtomicType()) { const Expression::ID opID = operand->id(); if((opID == Expression::IDArgumentReference || (opID == Expression::IDCardinalityVerifier && operand->operands().first()->is(Expression::IDArgumentReference))) && *BuiltinTypes::item == *operandType) return Expression::Ptr(new ArgumentConverter(result, reqType)); if(!operandType->isAtomicType()) { result = Expression::Ptr(new Atomizer(result)); /* The atomizer might know more about the type. */ operandType = result->staticType()->itemType(); } if(reqType->xdtTypeMatches(operandType)) { /* Atomization was sufficient. Either the expected type is xs:anyAtomicType * or the type the Atomizer knows it returns, matches the required type. */ return result; } const bool compatModeEnabled = context->compatModeEnabled(); if((options.testFlag(AutomaticallyConvert) && BuiltinTypes::xsUntypedAtomic->xdtTypeMatches(operandType)) || (compatModeEnabled && BuiltinTypes::xsString->xdtTypeMatches(reqType))) { if(*reqType == *BuiltinTypes::numeric) { result = typeCheck(new UntypedAtomicConverter(result, BuiltinTypes::xsDouble, code), context, reqSeqType); } else result = typeCheck(new UntypedAtomicConverter(result, reqType, code), context, reqSeqType); /* The UntypedAtomicConverter might know more about the type, so reload. */ operandType = result->staticType()->itemType(); } else if(compatModeEnabled && *reqType == *BuiltinTypes::xsDouble) { const FunctionFactory::Ptr functions(context->functionSignatures()); Expression::List numberArgs; numberArgs.append(operand); result = functions->createFunctionCall(QXmlName(StandardNamespaces::fn, StandardLocalNames::number), numberArgs, context, operand.data())->typeCheck(context, reqSeqType); operandType = result->staticType()->itemType(); context->wrapExpressionWith(operand.data(), result); } if(reqType->xdtTypeMatches(operandType)) return result; /* Test if promotion will solve it; the xdtTypeMatches didn't * do that. */ if(options.testFlag(AutomaticallyConvert) && promotionPossible(operandType, reqType, context)) { if(options.testFlag(GeneratePromotion)) return Expression::Ptr(new UntypedAtomicConverter(result, reqType)); else return result; } if(operandType->xdtTypeMatches(reqType)) { /* For example, operandType is numeric, and reqType is xs:integer. */ return Expression::Ptr(new ItemVerifier(result, reqType, code)); } else { context->error(wrongType(context->namePool(), reqType, operandType), code, operand.data()); return result; } } else if(reqType->isNodeType()) { ReportContext::ErrorCode myCode; if(*reqType == *CommonSequenceTypes::EBV->itemType()) myCode = ReportContext::FORG0006; else myCode = code; /* empty-sequence() is considered valid because it's ok to do * for example nilled( () ). That is, to pass an empty sequence to a * function requiring for example node()?. */ if(*operandType == *CommonSequenceTypes::Empty) return result; else if(!operandType->xdtTypeMatches(reqType)) { context->error(wrongType(context->namePool(), reqType, operandType), myCode, operand.data()); return result; } /* Operand must be an item. Thus, the sequence can contain both * nodes and atomic values: we have to verify. */ return Expression::Ptr(new ItemVerifier(result, reqType, myCode)); } else { Q_ASSERT(*reqType == *CommonSequenceTypes::Empty); /* element() doesn't match empty-sequence(), but element()* does. */ if(!reqType->xdtTypeMatches(operandType) && !operandSeqType->cardinality().allowsEmpty()) { context->error(wrongType(context->namePool(), reqType, operandType), code, operand.data()); return result; } } /* This line should be reached if required type is * EBVType, and the operand is compatible. */ return result; }
SequenceType::Ptr FirstItemPredicate::staticType() const { const SequenceType::Ptr t(m_operand->staticType()); return makeGenericSequenceType(t->itemType(), t->cardinality().toWithoutMany()); }
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); }