QmlCompiler: Create QQmlJSRegisterContent unstored

Add a separate pass to populate the stored types and only run that after
we're done with all the type propagation and optimization.

Task-number: QTBUG-124670
Change-Id: I740063908b22684f5d2c72d6261fad98850d8636
Reviewed-by: Olivier De Cannière <olivier.decanniere@qt.io>
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
Ulf Hermann 2024-06-10 11:21:15 +02:00
parent 9542b4b935
commit dd731b880b
16 changed files with 313 additions and 220 deletions

View File

@ -34,6 +34,7 @@ qt_internal_add_module(QmlCompiler
qqmljscontextualtypes_p.h
qqmljsshadowcheck.cpp qqmljsshadowcheck_p.h
qqmljsstoragegeneralizer.cpp qqmljsstoragegeneralizer_p.h
qqmljsstorageinitializer.cpp qqmljsstorageinitializer_p.h
qqmljstypedescriptionreader.cpp qqmljstypedescriptionreader_p.h
qqmljstypepropagator.cpp qqmljstypepropagator_p.h
qqmljstypereader.cpp qqmljstypereader_p.h

View File

@ -213,7 +213,7 @@ QT_WARNING_POP
if (!registerIsArgument
&& registerIndex != Accumulator
&& registerIndex != This
&& !registerIsStoredIn(
&& !m_typeResolver->registerContains(
function->registerTypes[registerIndex - firstRegisterIndex()],
m_typeResolver->voidType())) {
result.code += registerIt->variableName + u" = "_s;
@ -223,10 +223,9 @@ QT_WARNING_POP
const int argumentIndex = registerIndex - FirstArgument;
const QQmlJSRegisterContent argument
= m_function->argumentTypes[argumentIndex];
const QQmlJSRegisterContent original
= m_typeResolver->original(argument);
const QQmlJSRegisterContent originalArgument = original(argument);
const bool needsConversion = argument != original;
const bool needsConversion = argument != originalArgument;
if (!isPointer && registerIt->numTracked == 1 && !needsConversion) {
// Not a pointer, never written to, and doesn't need any initial conversion.
// This is a readonly argument.
@ -240,11 +239,11 @@ QT_WARNING_POP
result.code += registerIt->variableName + u" = "_s;
const QString originalValue
= u"(*static_cast<"_s + castTargetName(original.storedType())
= u"(*static_cast<"_s + castTargetName(originalArgument.storedType())
+ u"*>(argv["_s + QString::number(argumentIndex + 1) + u"]))"_s;
if (needsConversion)
result.code += conversion(original, argument, originalValue);
result.code += conversion(originalArgument, argument, originalValue);
else
result.code += originalValue;
} else {
@ -683,9 +682,11 @@ void QQmlJSCodeGenerator::generate_LoadQmlContextPropertyLookup(int index)
const int nameIndex = m_jsUnitGenerator->lookupNameIndex(index);
const QString name = m_jsUnitGenerator->stringForIndex(nameIndex);
if (m_state.accumulatorOut().variant() == QQmlJSRegisterContent::JavaScriptGlobal) {
// This produces a QJSValue. The QQmlJSMetaProperty used to analyze it may have more details
// but the QQmlJSAotContext API does not reflect them.
m_body += m_state.accumulatorVariableOut + u" = "_s
+ conversion(
m_typeResolver->original(m_state.accumulatorOut()), m_state.accumulatorOut(),
m_typeResolver->jsValueType(), m_state.accumulatorOut(),
u"aotContext->javaScriptGlobalProperty("_s + QString::number(nameIndex) + u")")
+ u";\n"_s;
return;
@ -775,7 +776,7 @@ void QQmlJSCodeGenerator::generate_LoadElement(int base)
}
const QString voidAssignment = u" "_s + m_state.accumulatorVariableOut + u" = "_s +
conversion(m_typeResolver->globalType(m_typeResolver->voidType()),
conversion(global(m_typeResolver->voidType()),
m_state.accumulatorOut(), QString()) + u";\n"_s;
QString indexName = m_state.accumulatorVariableIn;
@ -812,7 +813,7 @@ void QQmlJSCodeGenerator::generate_LoadElement(int base)
if (registerIsStoredIn(baseType, m_typeResolver->listPropertyType())) {
// Our QQmlListProperty only keeps plain QObject*.
const auto elementType = m_typeResolver->globalType(m_typeResolver->qObjectType());
const auto elementType = global(m_typeResolver->qObjectType());
m_body += u"if ("_s + indexName + u" < "_s + baseName
+ u".count(&"_s + baseName + u"))\n"_s;
@ -825,7 +826,9 @@ void QQmlJSCodeGenerator::generate_LoadElement(int base)
return;
}
const auto elementType = m_typeResolver->valueType(baseType);
// Since we can do .at() below, we know that we can natively store the element type.
QQmlJSRegisterContent elementType = m_typeResolver->valueType(baseType);
elementType = elementType.storedIn(m_typeResolver->storedType(elementType.containedType()));
QString access = baseName + u".at("_s + indexName + u')';
@ -865,8 +868,8 @@ void QQmlJSCodeGenerator::generate_StoreElement(int base, int index)
const QString indexName = registerVariable(index);
const auto valueType = m_typeResolver->valueType(baseType);
const auto elementType = m_typeResolver->globalType(m_typeResolver->genericType(
m_typeResolver->containedType(valueType)));
const auto elementType = global(m_typeResolver->genericType(
m_typeResolver->containedType(valueType)));
addInclude(u"QtQml/qjslist.h"_s);
if (!m_typeResolver->isNativeArrayIndex(indexType))
@ -1078,8 +1081,7 @@ void QQmlJSCodeGenerator::generateVariantEqualityComparison(
: m_typeResolver->containedType(storableContent);
if (contained->isReferenceType()) {
const QQmlJSRegisterContent comparable
= m_typeResolver->builtinType(m_typeResolver->qObjectType());
const QQmlJSRegisterContent comparable = builtin(m_typeResolver->qObjectType());
m_body += m_state.accumulatorVariableOut + u" = "_s + (invert ? u"!"_s : QString()) + u"(("
+ varRegisterName + u".metaType().flags() & QMetaType::PointerToQObject) "_s
+ u" && "_s + conversion(storableContent, comparable, typedRegisterName) + u" == "_s
@ -1088,8 +1090,7 @@ void QQmlJSCodeGenerator::generateVariantEqualityComparison(
}
if (m_typeResolver->isPrimitive(contained)) {
const QQmlJSRegisterContent comparable
= m_typeResolver->builtinType(m_typeResolver->jsPrimitiveType());
const QQmlJSRegisterContent comparable = builtin(m_typeResolver->jsPrimitiveType());
m_body += m_state.accumulatorVariableOut + u" = "_s + (invert ? u"!"_s : QString())
+ conversion(storableContent, comparable, typedRegisterName)
+ u".strictlyEquals("_s
@ -1457,7 +1458,7 @@ void QQmlJSCodeGenerator::generate_GetLookupHelper(int index)
if (stored->isListProperty()) {
m_body += m_state.accumulatorVariableOut + u" = "_s;
m_body += conversion(
m_typeResolver->globalType(m_typeResolver->sizeType()),
global(m_typeResolver->sizeType()),
m_state.accumulatorOut(),
m_state.accumulatorVariableIn + u".count("_s + u'&'
+ m_state.accumulatorVariableIn + u')');
@ -1465,7 +1466,7 @@ void QQmlJSCodeGenerator::generate_GetLookupHelper(int index)
} else if (stored->accessSemantics() == QQmlJSScope::AccessSemantics::Sequence
|| m_typeResolver->equals(stored, m_typeResolver->stringType())) {
m_body += m_state.accumulatorVariableOut + u" = "_s
+ conversion(m_typeResolver->globalType(m_typeResolver->sizeType()),
+ conversion(global(m_typeResolver->sizeType()),
m_state.accumulatorOut(),
m_state.accumulatorVariableIn + u".length()"_s)
+ u";\n"_s;
@ -1476,7 +1477,7 @@ void QQmlJSCodeGenerator::generate_GetLookupHelper(int index)
QString mapLookup = m_state.accumulatorVariableIn + u"["_s
+ QQmlJSUtils::toLiteral(m_jsUnitGenerator->lookupName(index)) + u"]"_s;
m_body += m_state.accumulatorVariableOut + u" = "_s;
m_body += conversion(m_typeResolver->globalType(m_typeResolver->varType()),
m_body += conversion(global(m_typeResolver->varType()),
m_state.accumulatorOut(), mapLookup);
m_body += u";\n"_s;
} else {
@ -2189,7 +2190,7 @@ bool QQmlJSCodeGenerator::inlineArrayMethod(const QString &name, int base, int a
call += u")";
const auto outType = baseType.storedType()->isListProperty()
? m_typeResolver->globalType(m_typeResolver->qObjectListType())
? global(m_typeResolver->qObjectListType())
: baseType;
m_body += m_state.accumulatorVariableOut + u" = "_s
@ -2347,9 +2348,9 @@ void QQmlJSCodeGenerator::generate_Construct(int func, int argc, int argv)
INJECT_TRACE_INFO(generate_Construct);
Q_UNUSED(func);
const auto original = m_typeResolver->original(m_state.accumulatorOut());
const auto originalResult = original(m_state.accumulatorOut());
if (m_typeResolver->registerContains(original, m_typeResolver->dateTimeType())) {
if (m_typeResolver->registerContains(originalResult, m_typeResolver->dateTimeType())) {
m_body += m_state.accumulatorVariableOut + u" = ";
if (argc == 0) {
m_body += conversion(
@ -2382,7 +2383,7 @@ void QQmlJSCodeGenerator::generate_Construct(int func, int argc, int argv)
return;
}
if (m_typeResolver->registerContains(original, m_typeResolver->variantListType())) {
if (m_typeResolver->registerContains(originalResult, m_typeResolver->variantListType())) {
rejectIfBadArray();
if (argc == 1
@ -2464,8 +2465,7 @@ void QQmlJSCodeGenerator::generate_ThrowException()
generateSetInstructionPointer();
m_body += u"aotContext->engine->throwError("_s
+ conversion(m_state.accumulatorIn(), m_typeResolver->globalType(
m_typeResolver->jsValueType()),
+ conversion(m_state.accumulatorIn(), global(m_typeResolver->jsValueType()),
m_state.accumulatorVariableIn) + u");\n"_s;
generateReturnError();
m_skipUntilNextLabel = true;
@ -2593,10 +2593,14 @@ void QQmlJSCodeGenerator::generate_IteratorNext(int value, int offset)
reject(u"using non-iterator as iterator"_s);
m_body += u"if (" + m_state.accumulatorVariableIn + u"->hasNext(" + qjsList + u")) {\n ";
// We know that this works because we can do ->next() below.
QQmlJSRegisterContent iteratorValue = m_typeResolver->valueType(iteratorContent);
iteratorValue = iteratorValue.storedIn(iteratorValue.containedType());
m_body += changedRegisterVariable() + u" = "
+ conversion(
m_typeResolver->valueType(iteratorContent),
m_state.changedRegister(),
iteratorValue, m_state.changedRegister(),
m_state.accumulatorVariableIn + u"->next(" + qjsList + u')')
+ u";\n";
m_body += u"} else {\n ";
@ -2700,7 +2704,7 @@ void QQmlJSCodeGenerator::generate_DefineObjectLiteral(int internalClassId, int
m_body += u"{ "_s
+ conversion(
registerType(nameArg),
m_typeResolver->globalType(m_typeResolver->stringType()),
global(m_typeResolver->stringType()),
consumedRegisterVariable(nameArg))
+ u", "_s;
@ -2891,15 +2895,13 @@ void QQmlJSCodeGenerator::generate_CheckException()
void QQmlJSCodeGenerator::generate_CmpEqNull()
{
INJECT_TRACE_INFO(generate_CmpEqNull);
generateEqualityOperation(
m_typeResolver->globalType(m_typeResolver->nullType()), QString(), u"equals"_s, false);
generateEqualityOperation(global(m_typeResolver->nullType()), QString(), u"equals"_s, false);
}
void QQmlJSCodeGenerator::generate_CmpNeNull()
{
INJECT_TRACE_INFO(generate_CmlNeNull);
generateEqualityOperation(
m_typeResolver->globalType(m_typeResolver->nullType()), QString(), u"equals"_s, true);
generateEqualityOperation(global(m_typeResolver->nullType()), QString(), u"equals"_s, true);
}
QString QQmlJSCodeGenerator::getLookupPreparation(
@ -2973,8 +2975,7 @@ void QQmlJSCodeGenerator::generate_CmpEqInt(int lhsConst)
INJECT_TRACE_INFO(generate_CmpEqInt);
generateEqualityOperation(
m_typeResolver->globalType(m_typeResolver->int32Type()), QString::number(lhsConst),
u"equals"_s, false);
global(m_typeResolver->int32Type()), QString::number(lhsConst), u"equals"_s, false);
}
void QQmlJSCodeGenerator::generate_CmpNeInt(int lhsConst)
@ -2982,8 +2983,7 @@ void QQmlJSCodeGenerator::generate_CmpNeInt(int lhsConst)
INJECT_TRACE_INFO(generate_CmpNeInt);
generateEqualityOperation(
m_typeResolver->globalType(m_typeResolver->int32Type()), QString::number(lhsConst),
u"equals"_s, true);
global(m_typeResolver->int32Type()), QString::number(lhsConst), u"equals"_s, true);
}
void QQmlJSCodeGenerator::generate_CmpEq(int lhs)
@ -3056,8 +3056,8 @@ void QQmlJSCodeGenerator::generate_As(int lhs)
// If the original output is a conversion, we're supposed to check for the contained
// type and if it doesn't match, set the result to null or undefined.
const QQmlJSRegisterContent originalContent = m_typeResolver->original(outputContent);
const QQmlJSScope::ConstPtr target = originalContent.storedType()->isReferenceType()
const QQmlJSRegisterContent originalContent = original(outputContent);
const QQmlJSScope::ConstPtr target = originalContent.containedType()->isReferenceType()
? m_typeResolver->containedType(originalContent)
: m_typeResolver->extractNonVoidFromOptionalType(originalContent);
@ -3095,14 +3095,13 @@ void QQmlJSCodeGenerator::generate_As(int lhs)
|| registerIsStoredIn(inputContent, m_typeResolver->jsPrimitiveType())) {
const auto source = m_typeResolver->extractNonVoidFromOptionalType(
m_typeResolver->original(inputContent));
original(inputContent));
if (source && m_typeResolver->equals(source, target)) {
m_body += input + u".metaType() == "_s + metaType(target)
+ u" ? " + conversion(inputContent, outputContent, input)
+ u" : " + conversion(
m_typeResolver->globalType(m_typeResolver->voidType()),
outputContent, QString());
global(m_typeResolver->voidType()), outputContent, QString());
m_body += u";\n"_s;
return;
}
@ -3244,7 +3243,7 @@ void QQmlJSCodeGenerator::generate_Exp(int lhs)
Q_ASSERT(m_error->isValid() || !lhsString.isEmpty());
Q_ASSERT(m_error->isValid() || !rhsString.isEmpty());
const QQmlJSRegisterContent originalOut = m_typeResolver->original(m_state.accumulatorOut());
const QQmlJSRegisterContent originalOut = original(m_state.accumulatorOut());
m_body += m_state.accumulatorVariableOut + u" = "_s;
m_body += conversion(
originalOut, m_state.accumulatorOut(),
@ -3412,20 +3411,20 @@ void QQmlJSCodeGenerator::generateEqualityOperation(
const auto retrieveOriginal = [this](const QQmlJSRegisterContent &content) {
const auto contained = m_typeResolver->containedType(content);
const auto original = m_typeResolver->original(content);
const auto containedOriginal = m_typeResolver->containedType(original);
const auto originalContent = original(content);
const auto containedOriginal = m_typeResolver->containedType(originalContent);
if (m_typeResolver->equals(
m_typeResolver->genericType(containedOriginal), original.storedType())) {
m_typeResolver->genericType(containedOriginal), originalContent.storedType())) {
// The original type doesn't need any wrapping.
return original;
return originalContent;
} else if (m_typeResolver->equals(contained, containedOriginal)) {
if (original.isConversion()) {
if (originalContent.isConversion()) {
// The original conversion origins are more accurate
return original.storedIn(content.storedType());
return originalContent.storedIn(content.storedType());
}
} else if (m_typeResolver->canHold(contained, containedOriginal)) {
return original.storedIn(content.storedType());
return originalContent.storedIn(content.storedType());
}
return content;
@ -3599,7 +3598,7 @@ void QQmlJSCodeGenerator::generateCompareOperation(int lhs, const QString &cppOp
const auto lhsType = registerType(lhs);
const QQmlJSScope::ConstPtr compareType =
m_typeResolver->isNumeric(lhsType) && m_typeResolver->isNumeric(m_state.accumulatorIn())
? m_typeResolver->merge(lhsType, m_state.accumulatorIn()).storedType()
? m_typeResolver->merge(lhsType.storedType(), m_state.accumulatorIn().storedType())
: m_typeResolver->jsPrimitiveType();
m_body += conversion(
@ -3638,7 +3637,7 @@ void QQmlJSCodeGenerator::generateArithmeticOperation(
Q_ASSERT(m_error->isValid() || !lhs.isEmpty());
Q_ASSERT(m_error->isValid() || !rhs.isEmpty());
const QQmlJSRegisterContent originalOut = m_typeResolver->original(m_state.accumulatorOut());
const QQmlJSRegisterContent originalOut = original(m_state.accumulatorOut());
m_body += m_state.accumulatorVariableOut;
m_body += u" = "_s;
const QString explicitCast
@ -3656,7 +3655,7 @@ void QQmlJSCodeGenerator::generateArithmeticConstOperation(int rhsConst, const Q
generateArithmeticOperation(
conversion(m_state.accumulatorIn(), m_state.readAccumulator(),
consumedAccumulatorVariableIn()),
conversion(m_typeResolver->globalType(m_typeResolver->int32Type()),
conversion(global(m_typeResolver->int32Type()),
m_state.readAccumulator(), QString::number(rhsConst)),
cppOperator);
}
@ -3664,7 +3663,7 @@ void QQmlJSCodeGenerator::generateArithmeticConstOperation(int rhsConst, const Q
void QQmlJSCodeGenerator::generateUnaryOperation(const QString &cppOperator)
{
const auto var = conversion(m_state.accumulatorIn(),
m_typeResolver->original(m_state.readAccumulator()),
original(m_state.readAccumulator()),
consumedAccumulatorVariableIn());
if (var == m_state.accumulatorVariableOut) {
@ -3672,8 +3671,8 @@ void QQmlJSCodeGenerator::generateUnaryOperation(const QString &cppOperator)
return;
}
const auto original = m_typeResolver->original(m_state.accumulatorOut());
if (m_state.accumulatorOut() == original) {
const auto originalResult = original(m_state.accumulatorOut());
if (m_state.accumulatorOut() == originalResult) {
m_body += m_state.accumulatorVariableOut + u" = "_s + var + u";\n"_s;
m_body += m_state.accumulatorVariableOut + u" = "_s
+ cppOperator + m_state.accumulatorVariableOut + u";\n"_s;
@ -3681,7 +3680,7 @@ void QQmlJSCodeGenerator::generateUnaryOperation(const QString &cppOperator)
}
m_body += m_state.accumulatorVariableOut + u" = "_s + conversion(
original, m_state.accumulatorOut(), cppOperator + var) + u";\n"_s;
originalResult, m_state.accumulatorOut(), cppOperator + var) + u";\n"_s;
}
void QQmlJSCodeGenerator::generateInPlaceOperation(const QString &cppOperator)
@ -3699,8 +3698,8 @@ void QQmlJSCodeGenerator::generateInPlaceOperation(const QString &cppOperator)
const QString var = conversion(m_state.accumulatorIn(), m_state.readAccumulator(),
consumedAccumulatorVariableIn());
const auto original = m_typeResolver->original(m_state.accumulatorOut());
if (m_state.accumulatorOut() == original) {
const auto originalResult = original(m_state.accumulatorOut());
if (m_state.accumulatorOut() == originalResult) {
m_body += m_state.accumulatorVariableOut + u" = "_s + var + u";\n"_s;
m_body += cppOperator + m_state.accumulatorVariableOut + u";\n"_s;
return;
@ -3709,7 +3708,7 @@ void QQmlJSCodeGenerator::generateInPlaceOperation(const QString &cppOperator)
m_body += u"{\n"_s;
m_body += u"auto converted = "_s + var + u";\n"_s;
m_body += m_state.accumulatorVariableOut + u" = "_s + conversion(
original, m_state.accumulatorOut(), u'('
originalResult, m_state.accumulatorOut(), u'('
+ cppOperator + u"converted)"_s) + u";\n"_s;
m_body += u"}\n"_s;
}
@ -4024,7 +4023,7 @@ QString QQmlJSCodeGenerator::convertStored(
return variable;
const auto isBoolOrNumber = [&](const QQmlJSScope::ConstPtr &type) {
return m_typeResolver->isNumeric(m_typeResolver->globalType(type))
return m_typeResolver->isNumeric(type)
|| m_typeResolver->equals(type, m_typeResolver->boolType())
|| type->scopeType() == QQmlSA::ScopeType::EnumScope;
};
@ -4259,9 +4258,7 @@ QString QQmlJSCodeGenerator::convertContained(const QQmlJSRegisterContent &from,
input = variable;
argPointer = contentPointer(from, u"arg"_s);
} else {
const QQmlJSRegisterContent argument
= m_typeResolver->globalType(argumentType)
.storedIn(m_typeResolver->genericType(argumentType));
const QQmlJSRegisterContent argument = global(argumentType);
input = conversion(from, argument, variable);
argPointer = contentPointer(argument, u"arg"_s);
}
@ -4274,7 +4271,7 @@ QString QQmlJSCodeGenerator::convertContained(const QQmlJSRegisterContent &from,
+ u", "_s + argPointer + u"); }()"_s;
}
const auto originalFrom = m_typeResolver->original(from);
const auto originalFrom = original(from);
const auto containedOriginalFrom = m_typeResolver->containedType(originalFrom);
if (!m_typeResolver->equals(containedFrom, containedOriginalFrom)
&& m_typeResolver->canHold(containedFrom, containedOriginalFrom)) {
@ -4320,7 +4317,7 @@ QQmlJSCodeGenerator::AccumulatorConverter::AccumulatorConverter(QQmlJSCodeGenera
const bool storable = isTypeStorable(resolver, origStored);
generator->m_state.accumulatorVariableOut = storable ? u"retrieved"_s : QString();
generator->m_state.setRegister(Accumulator, resolver->original(accumulatorOut));
generator->m_state.setRegister(Accumulator, generator->original(accumulatorOut));
generator->m_body += u"{\n"_s;
if (storable) {
generator->m_body += origStored->augmentedInternalName() + u' '

View File

@ -230,7 +230,9 @@ protected:
// we can convert by stored type.
return convertStored(from, to.storedType(), variable);
} else {
return convertContained(m_typeResolver->globalType(from), to, variable);
return convertContained(
m_typeResolver->globalType(from).storedIn(m_typeResolver->storedType(from)),
to, variable);
}
}
@ -335,6 +337,22 @@ private:
const QQmlJSScope::ConstPtr &required, const QQmlJSRegisterContent &actual,
const QString &variable, const QString &errorMessage);
QQmlJSRegisterContent original(const QQmlJSRegisterContent &tracked)
{
const QQmlJSRegisterContent restored = m_typeResolver->original(tracked);
return restored.storedIn(m_typeResolver->originalType(tracked.storedType()));
}
QQmlJSRegisterContent global(const QQmlJSScope::ConstPtr &contained)
{
return m_typeResolver->globalType(contained).storedIn(contained);
}
QQmlJSRegisterContent builtin(const QQmlJSScope::ConstPtr &contained)
{
return m_typeResolver->builtinType(contained).storedIn(contained);
}
bool registerIsStoredIn(
const QQmlJSRegisterContent &reg, const QQmlJSScope::ConstPtr &type) const
{

View File

@ -15,6 +15,7 @@
#include <private/qqmljsparser_p.h>
#include <private/qqmljsshadowcheck_p.h>
#include <private/qqmljsstoragegeneralizer_p.h>
#include <private/qqmljsstorageinitializer_p.h>
#include <private/qqmljstypepropagator_p.h>
#include <QtCore/qfile.h>
@ -775,8 +776,13 @@ QQmlJSAotFunction QQmlJSAotCompiler::doCompile(
if (error->isValid())
return compileError();
QQmlJSStorageInitializer initializer(
m_unitGenerator, &m_typeResolver, m_logger, blocks, annotations);
passResult = initializer.run(function, error);
// Generalize all arguments, registers, and the return type.
QQmlJSStorageGeneralizer generalizer(m_unitGenerator, &m_typeResolver, m_logger, blocks, annotations);
QQmlJSStorageGeneralizer generalizer(
m_unitGenerator, &m_typeResolver, m_logger, blocks, annotations);
passResult = generalizer.run(function, error);
if (error->isValid())
return compileError();

View File

@ -6,6 +6,7 @@
#include <QtQmlCompiler/private/qqmljsimportvisitor_p.h>
#include <QtQmlCompiler/private/qqmljsshadowcheck_p.h>
#include <QtQmlCompiler/private/qqmljsstoragegeneralizer_p.h>
#include <QtQmlCompiler/private/qqmljsstorageinitializer_p.h>
#include <QtQmlCompiler/private/qqmljstypepropagator_p.h>
#include <QtQmlCompiler/private/qqmljsfunctioninitializer_p.h>
@ -91,6 +92,12 @@ bool QQmlJSLinterCodegen::analyzeFunction(const QV4::Compiler::Context *context,
shadowCheck.run(function, error);
}
if (!error->isValid()) {
QQmlJSStorageInitializer initializer(m_unitGenerator, &m_typeResolver, m_logger,
basicBlocks, annotations);
initializer.run(function, error);
}
if (!error->isValid()) {
QQmlJSStorageGeneralizer generalizer(m_unitGenerator, &m_typeResolver, m_logger,
basicBlocks, annotations);

View File

@ -84,11 +84,7 @@ void QQmlJSOptimizations::populateReaderLocations()
it->second.changedRegister = QQmlJSRegisterContent();
} else {
// void the output, rather than deleting it. We still need its variant.
bool adjusted = m_typeResolver->adjustTrackedType(
it->second.changedRegister.storedType(), m_typeResolver->voidType());
Q_ASSERT(adjusted); // Can always convert to void
adjusted = m_typeResolver->adjustTrackedType(
const bool adjusted = m_typeResolver->adjustTrackedType(
m_typeResolver->containedType(it->second.changedRegister),
m_typeResolver->voidType());
Q_ASSERT(adjusted); // Can always convert to void
@ -315,13 +311,6 @@ void QQmlJSOptimizations::adjustTypes()
}
};
const auto transformRegister = [&](const QQmlJSRegisterContent &content) {
const QQmlJSScope::ConstPtr conversion
= m_typeResolver->storedType(m_typeResolver->containedType(content));
if (!m_typeResolver->adjustTrackedType(content.storedType(), conversion))
setError(adjustErrorMessage(content.storedType(), conversion));
};
// Handle the array definitions first.
// Changing the array type changes the expected element types.
auto adjustArray = [&](int instructionOffset, int mode) {
@ -354,9 +343,6 @@ void QQmlJSOptimizations::adjustTypes()
|| !m_typeResolver->equals(contained, m_typeResolver->realType())) {
if (!m_typeResolver->adjustTrackedType(contained, valueType))
setError(adjustErrorMessage(contained, valueType));
// We still need to adjust the stored type, too.
transformRegister(content);
}
}
@ -412,9 +398,6 @@ void QQmlJSOptimizations::adjustTypes()
const QQmlJSScope::ConstPtr contained = m_typeResolver->containedType(content);
if (!m_typeResolver->adjustTrackedType(contained, propType))
setError(adjustErrorMessage(contained, propType));
// We still need to adjust the stored type, too.
transformRegister(content);
}
// The others cannot be adjusted. We don't know their names, yet.
@ -456,9 +439,6 @@ void QQmlJSOptimizations::adjustTypes()
NewVirtualRegisters newRegisters;
for (auto i = m_annotations.begin(), iEnd = m_annotations.end(); i != iEnd; ++i) {
if (i->second.changedRegisterIndex != InvalidRegister)
transformRegister(i->second.changedRegister);
for (auto conversion = i->second.typeConversions.begin(),
conversionEnd = i->second.typeConversions.end(); conversion != conversionEnd;
++conversion) {
@ -475,7 +455,6 @@ void QQmlJSOptimizations::adjustTypes()
if (!m_typeResolver->adjustTrackedType(conversionResult, newResult))
setError(adjustErrorMessage(conversionResult, newResult));
}
transformRegister(content);
newRegisters.appendOrdered(conversion);
}
i->second.typeConversions = newRegisters.take();

View File

@ -2,7 +2,6 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "qqmljsregistercontent_p.h"
#include "qqmljstyperesolver_p.h"
QT_BEGIN_NAMESPACE
@ -121,82 +120,59 @@ QQmlJSScope::ConstPtr QQmlJSRegisterContent::containedType() const
Q_UNREACHABLE_RETURN({});
}
QQmlJSRegisterContent QQmlJSRegisterContent::create(const QQmlJSScope::ConstPtr &storedType,
const QQmlJSScope::ConstPtr &type,
int resultLookupIndex,
QQmlJSRegisterContent::ContentVariant variant,
const QQmlJSScope::ConstPtr &scope)
QQmlJSRegisterContent QQmlJSRegisterContent::create(
const QQmlJSScope::ConstPtr &type, int resultLookupIndex,
QQmlJSRegisterContent::ContentVariant variant, const QQmlJSScope::ConstPtr &scope)
{
QQmlJSRegisterContent result(storedType, scope, variant);
QQmlJSRegisterContent result(scope, variant);
result.m_content = std::make_pair(type, resultLookupIndex);
return result;
}
QQmlJSRegisterContent QQmlJSRegisterContent::create(const QQmlJSScope::ConstPtr &storedType,
const QQmlJSMetaProperty &property,
int baseLookupIndex, int resultLookupIndex,
QQmlJSRegisterContent::ContentVariant variant,
const QQmlJSScope::ConstPtr &scope)
QQmlJSRegisterContent QQmlJSRegisterContent::create(
const QQmlJSMetaProperty &property, int baseLookupIndex, int resultLookupIndex,
QQmlJSRegisterContent::ContentVariant variant, const QQmlJSScope::ConstPtr &scope)
{
QQmlJSRegisterContent result(storedType, scope, variant);
QQmlJSRegisterContent result(scope, variant);
result.m_content = PropertyLookup { property, baseLookupIndex, resultLookupIndex};
return result;
}
QQmlJSRegisterContent QQmlJSRegisterContent::create(const QQmlJSScope::ConstPtr &storedType,
const QQmlJSMetaEnum &enumeration,
const QString &enumMember,
QQmlJSRegisterContent::ContentVariant variant,
const QQmlJSScope::ConstPtr &scope)
QQmlJSRegisterContent QQmlJSRegisterContent::create(
const QQmlJSMetaEnum &enumeration, const QString &enumMember,
QQmlJSRegisterContent::ContentVariant variant, const QQmlJSScope::ConstPtr &scope)
{
QQmlJSRegisterContent result(storedType, scope, variant);
QQmlJSRegisterContent result(scope, variant);
result.m_content = std::make_pair(enumeration, enumMember);
return result;
}
QQmlJSRegisterContent QQmlJSRegisterContent::create(const QQmlJSScope::ConstPtr &storedType,
const QList<QQmlJSMetaMethod> &methods,
QQmlJSRegisterContent::ContentVariant variant,
const QQmlJSScope::ConstPtr &scope)
QQmlJSRegisterContent QQmlJSRegisterContent::create(
const QList<QQmlJSMetaMethod> &methods, const QQmlJSScope::ConstPtr &methodType,
QQmlJSRegisterContent::ContentVariant variant, const QQmlJSScope::ConstPtr &scope)
{
// Methods can only be stored in QJSValue.
Q_ASSERT(storedType->internalName() == u"QJSValue"_s);
QQmlJSRegisterContent result(storedType, scope, variant);
result.m_content = std::make_pair(methods, storedType);
Q_ASSERT(methodType->internalName() == u"QJSValue"_s);
QQmlJSRegisterContent result(scope, variant);
result.m_content = std::make_pair(methods, methodType);
return result;
}
QQmlJSRegisterContent QQmlJSRegisterContent::create(const QQmlJSScope::ConstPtr &storedType,
uint importNamespaceStringId,
QQmlJSRegisterContent::ContentVariant variant,
const QQmlJSScope::ConstPtr &scope)
QQmlJSRegisterContent QQmlJSRegisterContent::create(
uint importNamespaceStringId, const QQmlJSScope::ConstPtr &importNamespaceType,
QQmlJSRegisterContent::ContentVariant variant, const QQmlJSScope::ConstPtr &scope)
{
QQmlJSRegisterContent result(storedType, scope, variant);
switch (variant) {
case ScopeModulePrefix:
// We don't store scope module prefixes
result.m_content = std::make_pair(importNamespaceStringId, storedType);
break;
case ObjectModulePrefix:
// We need to pass the original object through.
result.m_content = std::make_pair(importNamespaceStringId, scope);
break;
default:
Q_UNREACHABLE();
break;
}
QQmlJSRegisterContent result(scope, variant);
result.m_content = std::make_pair(importNamespaceStringId, importNamespaceType);
return result;
}
QQmlJSRegisterContent QQmlJSRegisterContent::create(const QQmlJSScope::ConstPtr &storedType,
const QList<QQmlJSScope::ConstPtr> &origins,
const QQmlJSScope::ConstPtr &conversion,
const QQmlJSScope::ConstPtr &conversionScope,
ContentVariant variant,
const QQmlJSScope::ConstPtr &scope)
QQmlJSRegisterContent QQmlJSRegisterContent::create(
const QList<QQmlJSScope::ConstPtr> &origins, const QQmlJSScope::ConstPtr &conversion,
const QQmlJSScope::ConstPtr &conversionScope, ContentVariant variant,
const QQmlJSScope::ConstPtr &scope)
{
QQmlJSRegisterContent result(storedType, scope, variant);
QQmlJSRegisterContent result(scope, variant);
result.m_content = ConvertedTypes { origins, conversion, conversionScope };
return result;
}

View File

@ -186,33 +186,30 @@ public:
Q_UNREACHABLE_RETURN(seed);
}
static QQmlJSRegisterContent create(const QQmlJSScope::ConstPtr &storedType,
const QQmlJSScope::ConstPtr &type,
static QQmlJSRegisterContent create(const QQmlJSScope::ConstPtr &type,
int resultLookupIndex, ContentVariant variant,
const QQmlJSScope::ConstPtr &scope = {});
static QQmlJSRegisterContent create(const QQmlJSScope::ConstPtr &storedType,
const QQmlJSMetaProperty &property,
static QQmlJSRegisterContent create(const QQmlJSMetaProperty &property,
int baseLookupIndex, int resultLookupIndex,
ContentVariant variant,
const QQmlJSScope::ConstPtr &scope);
static QQmlJSRegisterContent create(const QQmlJSScope::ConstPtr &storedType,
const QQmlJSMetaEnum &enumeration,
static QQmlJSRegisterContent create(const QQmlJSMetaEnum &enumeration,
const QString &enumMember, ContentVariant variant,
const QQmlJSScope::ConstPtr &scope);
static QQmlJSRegisterContent create(const QQmlJSScope::ConstPtr &storedType,
const QList<QQmlJSMetaMethod> &methods,
static QQmlJSRegisterContent create(const QList<QQmlJSMetaMethod> &methods,
const QQmlJSScope::ConstPtr &methodType,
ContentVariant variant,
const QQmlJSScope::ConstPtr &scope);
static QQmlJSRegisterContent create(const QQmlJSScope::ConstPtr &storedType,
uint importNamespaceStringId, ContentVariant variant,
static QQmlJSRegisterContent create(uint importNamespaceStringId,
const QQmlJSScope::ConstPtr &importNamespaceType,
ContentVariant variant,
const QQmlJSScope::ConstPtr &scope = {});
static QQmlJSRegisterContent create(const QQmlJSScope::ConstPtr &storedType,
const QList<QQmlJSScope::ConstPtr> &origins,
static QQmlJSRegisterContent create(const QList<QQmlJSScope::ConstPtr> &origins,
const QQmlJSScope::ConstPtr &conversion,
const QQmlJSScope::ConstPtr &conversionScope,
ContentVariant variant,
@ -292,9 +289,8 @@ private:
ConvertedTypes
>;
QQmlJSRegisterContent(const QQmlJSScope::ConstPtr &storedType,
const QQmlJSScope::ConstPtr &scope, ContentVariant variant)
: m_storedType(storedType), m_scope(scope), m_variant(variant)
QQmlJSRegisterContent(const QQmlJSScope::ConstPtr &scope, ContentVariant variant)
: m_scope(scope), m_variant(variant)
{
}

View File

@ -192,8 +192,6 @@ QQmlJSShadowCheck::Shadowability QQmlJSShadowCheck::checkShadowing(
InstructionAnnotation &currentAnnotation = m_annotations[currentInstructionOffset()];
if (currentAnnotation.changedRegisterIndex != InvalidRegister) {
m_typeResolver->adjustOriginalType(
currentAnnotation.changedRegister.storedType(), varType);
m_typeResolver->adjustOriginalType(
m_typeResolver->containedType(currentAnnotation.changedRegister), varType);
m_adjustedTypes.insert(currentAnnotation.changedRegister);

View File

@ -22,6 +22,7 @@ QT_BEGIN_NAMESPACE
QQmlJSCompilePass::BlocksAndAnnotations
QQmlJSStorageGeneralizer::run(Function *function, QQmlJS::DiagnosticMessage *error)
{
m_function = function;
m_error = error;
if (QQmlJSRegisterContent &returnType = function->returnType; returnType.isValid()) {

View File

@ -0,0 +1,81 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "qqmljsstorageinitializer_p.h"
QT_BEGIN_NAMESPACE
/*!
* \internal
* \class QQmlJSStorageInitializer
*
* The QQmlJSStorageInitializer is a compile pass that initializes the storage
* for all register contents.
*
* QQmlJSStorageInitializer does not have to use the byte code at all but
* operates only on the annotations and the function description.
*/
QQmlJSCompilePass::BlocksAndAnnotations
QQmlJSStorageInitializer::run(Function *function, QQmlJS::DiagnosticMessage *error)
{
m_function = function;
m_error = error;
if (QQmlJSRegisterContent &returnType = function->returnType; returnType.isValid()) {
if (const QQmlJSScope::ConstPtr stored
= m_typeResolver->storedType(returnType.containedType())) {
returnType = returnType.storedIn(m_typeResolver->trackedType(stored));
} else {
setError(QStringLiteral("Cannot store the return type %1.")
.arg(returnType.containedType()->internalName()));
return {};
}
}
const auto storeRegister = [&](QQmlJSRegisterContent &content) {
if (!content.isValid())
return;
const QQmlJSScope::ConstPtr original
= m_typeResolver->originalType(content.containedType());
const QQmlJSScope::ConstPtr originalStored = m_typeResolver->storedType(original);
const QQmlJSScope::ConstPtr originalTracked = m_typeResolver->trackedType(originalStored);
content = content.storedIn(originalTracked);
const QQmlJSScope::ConstPtr adjustedStored
= m_typeResolver->storedType(content.containedType());
if (!m_typeResolver->adjustTrackedType(originalTracked, adjustedStored)) {
setError(QStringLiteral("Cannot adjust stored type for %1.")
.arg(content.containedType()->internalName()));
}
};
const auto storeRegisters = [&](VirtualRegisters &registers) {
for (auto j = registers.begin(), jEnd = registers.end(); j != jEnd; ++j)
storeRegister(j.value().content);
};
storeRegister(function->qmlScope);
for (QQmlJSRegisterContent &argument : function->argumentTypes) {
Q_ASSERT(argument.isValid());
storeRegister(argument);
}
for (QQmlJSRegisterContent &argument : function->registerTypes) {
Q_ASSERT(argument.isValid());
storeRegister(argument);
}
for (auto i = m_annotations.begin(), iEnd = m_annotations.end(); i != iEnd; ++i) {
storeRegister(i->second.changedRegister);
storeRegisters(i->second.typeConversions);
storeRegisters(i->second.readRegisters);
}
return { std::move(m_basicBlocks), std::move(m_annotations) };
}
QT_END_NAMESPACE

View File

@ -0,0 +1,40 @@
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef QQMLJSSTORAGEINITIALIZER_P_H
#define QQMLJSSTORAGEINITIALIZER_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
#include <private/qqmljscompilepass_p.h>
QT_BEGIN_NAMESPACE
class Q_QMLCOMPILER_EXPORT QQmlJSStorageInitializer : public QQmlJSCompilePass
{
public:
QQmlJSStorageInitializer(const QV4::Compiler::JSUnitGenerator *jsUnitGenerator,
const QQmlJSTypeResolver *typeResolver, QQmlJSLogger *logger,
BasicBlocks basicBlocks, InstructionAnnotations annotations)
: QQmlJSCompilePass(jsUnitGenerator, typeResolver, logger, basicBlocks, annotations)
{}
BlocksAndAnnotations run(Function *function, QQmlJS::DiagnosticMessage *error);
protected:
// We don't have to use the byte code here. We only transform the instruction annotations.
Verdict startInstruction(QV4::Moth::Instr::Type) override { return SkipInstruction; }
void endInstruction(QV4::Moth::Instr::Type) override {}
};
QT_END_NAMESPACE
#endif // QQMLJSSTORAGEINITIALIZER_P_H

View File

@ -575,7 +575,7 @@ void QQmlJSTypePropagator::generate_LoadQmlContextPropertyLookup(int index)
if (!m_state.accumulatorOut().isValid() && m_typeResolver->isPrefix(name)) {
const QQmlJSRegisterContent inType = m_typeResolver->globalType(qmlScope);
setAccumulator(QQmlJSRegisterContent::create(
m_typeResolver->voidType(), nameIndex, QQmlJSRegisterContent::ScopeModulePrefix,
nameIndex, m_typeResolver->voidType(), QQmlJSRegisterContent::ScopeModulePrefix,
m_typeResolver->containedType(inType)));
return;
}
@ -833,8 +833,8 @@ void QQmlJSTypePropagator::propagatePropertyLookup(const QString &propertyName,
Q_ASSERT(m_state.accumulatorIn().isValid());
addReadAccumulator(m_state.accumulatorIn());
setAccumulator(QQmlJSRegisterContent::create(
m_state.accumulatorIn().storedType(),
m_jsUnitGenerator->getStringId(propertyName),
m_state.accumulatorIn().containedType(),
QQmlJSRegisterContent::ObjectModulePrefix,
m_typeResolver->containedType(m_state.accumulatorIn())));
return;
@ -929,7 +929,7 @@ void QQmlJSTypePropagator::propagatePropertyLookup(const QString &propertyName,
prop.setType(m_typeResolver->realType());
setAccumulator(
QQmlJSRegisterContent::create(
m_typeResolver->realType(), prop, m_state.accumulatorIn().resultLookupIndex(), lookupIndex,
prop, m_state.accumulatorIn().resultLookupIndex(), lookupIndex,
QQmlJSRegisterContent::GenericObjectProperty, mathObject)
);
@ -1058,7 +1058,7 @@ void QQmlJSTypePropagator::generate_StoreProperty(int nameIndex, int base)
const QQmlJSScope::ConstPtr varType = m_typeResolver->varType();
const QQmlJSRegisterContent readType = m_typeResolver->canHoldUndefined(m_state.accumulatorIn())
? property.storedIn(varType).castTo(varType)
? property.castTo(varType)
: std::move(property);
addReadAccumulator(readType);
addReadRegister(base, callBase);

View File

@ -406,35 +406,35 @@ QQmlJSRegisterContent QQmlJSTypeResolver::transformed(
{
if (origin.isType()) {
return QQmlJSRegisterContent::create(
(this->*op)(origin.storedType()), (this->*op)(origin.type()),
origin.resultLookupIndex(), origin.variant(), (this->*op)(origin.scopeType()));
(this->*op)(origin.type()), origin.resultLookupIndex(), origin.variant(),
(this->*op)(origin.scopeType()));
}
if (origin.isProperty()) {
QQmlJSMetaProperty prop = origin.property();
prop.setType((this->*op)(prop.type()));
return QQmlJSRegisterContent::create(
(this->*op)(origin.storedType()), prop, origin.baseLookupIndex(),
origin.resultLookupIndex(), origin.variant(), (this->*op)(origin.scopeType()));
prop, origin.baseLookupIndex(), origin.resultLookupIndex(), origin.variant(),
(this->*op)(origin.scopeType()));
}
if (origin.isEnumeration()) {
QQmlJSMetaEnum enumeration = origin.enumeration();
enumeration.setType((this->*op)(enumeration.type()));
return QQmlJSRegisterContent::create(
(this->*op)(origin.storedType()), enumeration, origin.enumMember(),
origin.variant(), (this->*op)(origin.scopeType()));
enumeration, origin.enumMember(), origin.variant(),
(this->*op)(origin.scopeType()));
}
if (origin.isMethod()) {
return QQmlJSRegisterContent::create(
(this->*op)(origin.storedType()), origin.method(), origin.variant(),
origin.method(), (this->*op)(origin.methodType()), origin.variant(),
(this->*op)(origin.scopeType()));
}
if (origin.isImportNamespace()) {
return QQmlJSRegisterContent::create(
(this->*op)(origin.storedType()), origin.importNamespace(),
origin.importNamespace(), (this->*op)(origin.importNamespaceType()),
origin.variant(), (this->*op)(origin.scopeType()));
}
@ -453,7 +453,6 @@ QQmlJSRegisterContent QQmlJSTypeResolver::transformed(
}
return QQmlJSRegisterContent::create(
(this->*op)(origin.storedType()),
transformedOrigins,
(this->*op)(origin.conversionResult()),
(this->*op)(origin.conversionResultScope()),
@ -495,13 +494,13 @@ QQmlJSRegisterContent QQmlJSTypeResolver::registerContentForName(
if (type->isSingleton()) {
return QQmlJSRegisterContent::create(
storedType(type), type, QQmlJSRegisterContent::InvalidLookupIndex,
type, QQmlJSRegisterContent::InvalidLookupIndex,
QQmlJSRegisterContent::Singleton, scopeType);
}
if (type->isScript()) {
return QQmlJSRegisterContent::create(
storedType(type), type, QQmlJSRegisterContent::InvalidLookupIndex,
type, QQmlJSRegisterContent::InvalidLookupIndex,
QQmlJSRegisterContent::Script, scopeType);
}
@ -521,7 +520,7 @@ QQmlJSRegisterContent QQmlJSTypeResolver::registerContentForName(
// mode, we will figure this out using the scope type and access any enums of the
// plain type directly. In indirect mode, we can use enum lookups.
return QQmlJSRegisterContent::create(
storedType(attached), attached, QQmlJSRegisterContent::InvalidLookupIndex,
attached, QQmlJSRegisterContent::InvalidLookupIndex,
hasObjectModulePrefix
? QQmlJSRegisterContent::ObjectAttached
: QQmlJSRegisterContent::ScopeAttached, type);
@ -536,13 +535,13 @@ QQmlJSRegisterContent QQmlJSTypeResolver::registerContentForName(
// Store it as QMetaObject.
// This only works with namespaces and object types.
return QQmlJSRegisterContent::create(
metaObjectType(), metaObjectType(), QQmlJSRegisterContent::InvalidLookupIndex,
metaObjectType(), QQmlJSRegisterContent::InvalidLookupIndex,
QQmlJSRegisterContent::MetaType, type);
case QQmlJSScope::AccessSemantics::Sequence:
case QQmlJSScope::AccessSemantics::Value:
if (canAddressValueTypes()) {
return QQmlJSRegisterContent::create(
metaObjectType(), metaObjectType(), QQmlJSRegisterContent::InvalidLookupIndex,
metaObjectType(), QQmlJSRegisterContent::InvalidLookupIndex,
QQmlJSRegisterContent::MetaType, type);
}
// Else this is not actually a type reference. You cannot get the metaobject
@ -746,7 +745,6 @@ QQmlJSRegisterContent QQmlJSTypeResolver::merge(const QQmlJSRegisterContent &a,
origins.erase(erase, origins.end());
return QQmlJSRegisterContent::create(
merge(a.storedType(), b.storedType()),
origins,
merge(containedType(a), containedType(b)),
merge(aResultScope, bResultScope),
@ -988,13 +986,13 @@ QQmlJSRegisterContent QQmlJSTypeResolver::builtinType(const QQmlJSScope::ConstPt
{
Q_ASSERT(storedType(type) == type);
return QQmlJSRegisterContent::create(
type, type, QQmlJSRegisterContent::InvalidLookupIndex, QQmlJSRegisterContent::Builtin);
type, QQmlJSRegisterContent::InvalidLookupIndex, QQmlJSRegisterContent::Builtin);
}
QQmlJSRegisterContent QQmlJSTypeResolver::globalType(const QQmlJSScope::ConstPtr &type) const
{
return QQmlJSRegisterContent::create(
storedType(type), type, QQmlJSRegisterContent::InvalidLookupIndex,
type, QQmlJSRegisterContent::InvalidLookupIndex,
QQmlJSRegisterContent::Unknown);
}
@ -1152,8 +1150,8 @@ QQmlJSRegisterContent QQmlJSTypeResolver::scopedType(const QQmlJSRegisterContent
{
const QQmlJSScope::ConstPtr contained = containedType(scope);
if (QQmlJSScope::ConstPtr identified = m_objectsById.scope(name, contained, options)) {
return QQmlJSRegisterContent::create(storedType(identified), identified, lookupIndex,
QQmlJSRegisterContent::ObjectById, contained);
return QQmlJSRegisterContent::create(
identified, lookupIndex, QQmlJSRegisterContent::ObjectById, contained);
}
if (QQmlJSScope::ConstPtr base = QQmlJSScope::findCurrentQMLScope(contained)) {
@ -1170,8 +1168,7 @@ QQmlJSRegisterContent QQmlJSTypeResolver::scopedType(const QQmlJSRegisterContent
prop.setType(resolveParentProperty(name, base, prop.type()));
result = QQmlJSRegisterContent::create(
storedType(prop.type()), prop,
QQmlJSRegisterContent::InvalidLookupIndex, lookupIndex,
prop, QQmlJSRegisterContent::InvalidLookupIndex, lookupIndex,
scopeContentVariant(mode, false), contained);
return true;
}
@ -1187,8 +1184,7 @@ QQmlJSRegisterContent QQmlJSTypeResolver::scopedType(const QQmlJSRegisterContent
if (methods.isEmpty())
return false;
result = QQmlJSRegisterContent::create(
jsValueType(), methods, scopeContentVariant(mode, true),
contained);
methods, jsValueType(), scopeContentVariant(mode, true), contained);
return true;
}
@ -1206,13 +1202,12 @@ QQmlJSRegisterContent QQmlJSTypeResolver::scopedType(const QQmlJSRegisterContent
if (m_jsGlobalObject->hasProperty(name)) {
return QQmlJSRegisterContent::create(
jsValueType(), m_jsGlobalObject->property(name),
QQmlJSRegisterContent::InvalidLookupIndex, lookupIndex,
QQmlJSRegisterContent::JavaScriptGlobal, m_jsGlobalObject);
m_jsGlobalObject->property(name), QQmlJSRegisterContent::InvalidLookupIndex,
lookupIndex, QQmlJSRegisterContent::JavaScriptGlobal, m_jsGlobalObject);
} else if (m_jsGlobalObject->hasMethod(name)) {
return QQmlJSRegisterContent::create(jsValueType(), m_jsGlobalObject->methods(name),
QQmlJSRegisterContent::JavaScriptGlobal,
m_jsGlobalObject);
return QQmlJSRegisterContent::create(
m_jsGlobalObject->methods(name), jsValueType(),
QQmlJSRegisterContent::JavaScriptGlobal, m_jsGlobalObject);
}
return {};
@ -1245,7 +1240,7 @@ bool QQmlJSTypeResolver::checkEnums(const QQmlJSScope::ConstPtr &scope, const QS
for (const auto &enumeration : enums) {
if ((enumeration.isScoped() || enumeration.isQml()) && enumeration.name() == name) {
*result = QQmlJSRegisterContent::create(
storedType(enumeration.type()), enumeration, QString(),
enumeration, QString(),
inExtension ? QQmlJSRegisterContent::ExtensionObjectEnum
: QQmlJSRegisterContent::ObjectEnum,
scope);
@ -1254,7 +1249,7 @@ bool QQmlJSTypeResolver::checkEnums(const QQmlJSScope::ConstPtr &scope, const QS
if (!enumeration.isScoped() && enumeration.hasKey(name)) {
*result = QQmlJSRegisterContent::create(
storedType(enumeration.type()), enumeration, name,
enumeration, name,
inExtension ? QQmlJSRegisterContent::ExtensionObjectEnum
: QQmlJSRegisterContent::ObjectEnum,
scope);
@ -1523,7 +1518,7 @@ QQmlJSRegisterContent QQmlJSTypeResolver::lengthProperty(
prop.setType(sizeType());
prop.setIsWritable(isWritable);
return QQmlJSRegisterContent::create(
sizeType(), prop, QQmlJSRegisterContent::InvalidLookupIndex,
prop, QQmlJSRegisterContent::InvalidLookupIndex,
QQmlJSRegisterContent::InvalidLookupIndex, QQmlJSRegisterContent::Builtin, scope);
}
@ -1544,7 +1539,7 @@ QQmlJSRegisterContent QQmlJSTypeResolver::memberType(
prop.setType(varType());
prop.setIsWritable(true);
return QQmlJSRegisterContent::create(
varType(), prop, baseLookupIndex, resultLookupIndex,
prop, baseLookupIndex, resultLookupIndex,
QQmlJSRegisterContent::GenericObjectProperty, type);
}
@ -1555,7 +1550,7 @@ QQmlJSRegisterContent QQmlJSTypeResolver::memberType(
prop.setType(jsValueType());
prop.setIsWritable(true);
return QQmlJSRegisterContent::create(
jsValueType(), prop, baseLookupIndex, resultLookupIndex,
prop, baseLookupIndex, resultLookupIndex,
QQmlJSRegisterContent::GenericObjectProperty, type);
}
@ -1570,7 +1565,6 @@ QQmlJSRegisterContent QQmlJSTypeResolver::memberType(
if (scope->hasOwnProperty(name)) {
const auto prop = scope->ownProperty(name);
result = QQmlJSRegisterContent::create(
storedType(prop.type()),
prop, baseLookupIndex, resultLookupIndex,
mode == QQmlJSScope::NotExtension
? QQmlJSRegisterContent::ObjectProperty
@ -1582,7 +1576,7 @@ QQmlJSRegisterContent QQmlJSTypeResolver::memberType(
if (scope->hasOwnMethod(name)) {
const auto methods = scope->ownMethods(name);
result = QQmlJSRegisterContent::create(
jsValueType(), methods,
methods, jsValueType(),
mode == QQmlJSScope::NotExtension
? QQmlJSRegisterContent::ObjectMethod
: QQmlJSRegisterContent::ExtensionObjectMethod,
@ -1608,9 +1602,9 @@ QQmlJSRegisterContent QQmlJSTypeResolver::memberType(
prop.setType(jsValueType());
prop.setIsWritable(!(ownIdentifier.value().isConst));
return QQmlJSRegisterContent::create(jsValueType(), prop, baseLookupIndex,
resultLookupIndex,
QQmlJSRegisterContent::JavaScriptObject, scope);
return QQmlJSRegisterContent::create(
prop, baseLookupIndex, resultLookupIndex,
QQmlJSRegisterContent::JavaScriptObject, scope);
}
}
@ -1628,8 +1622,8 @@ QQmlJSRegisterContent QQmlJSTypeResolver::memberType(
return {};
} else {
return QQmlJSRegisterContent::create(
storedType(attached), attached, resultLookupIndex,
QQmlJSRegisterContent::ObjectAttached, attachedBase);
attached, resultLookupIndex, QQmlJSRegisterContent::ObjectAttached,
attachedBase);
}
}
}
@ -1671,8 +1665,8 @@ QQmlJSRegisterContent QQmlJSTypeResolver::memberType(
const auto enumeration = type.enumeration();
if (!type.enumMember().isEmpty() || !enumeration.hasKey(name))
return {};
return QQmlJSRegisterContent::create(storedType(enumeration.type()), enumeration, name,
QQmlJSRegisterContent::ObjectEnum, type.scopeType());
return QQmlJSRegisterContent::create(
enumeration, name, QQmlJSRegisterContent::ObjectEnum, type.scopeType());
}
if (type.isMethod()) {
QQmlJSMetaProperty prop;
@ -1681,7 +1675,7 @@ QQmlJSRegisterContent QQmlJSTypeResolver::memberType(
prop.setType(jsValueType());
prop.setIsWritable(true);
return QQmlJSRegisterContent::create(
jsValueType(), prop, QQmlJSRegisterContent::InvalidLookupIndex, lookupIndex,
prop, QQmlJSRegisterContent::InvalidLookupIndex, lookupIndex,
QQmlJSRegisterContent::GenericObjectProperty, jsValueType());
}
if (type.isImportNamespace()) {
@ -1770,7 +1764,7 @@ QQmlJSRegisterContent QQmlJSTypeResolver::valueType(const QQmlJSRegisterContent
property.setType(value);
return QQmlJSRegisterContent::create(
storedType(value), property, QQmlJSRegisterContent::InvalidLookupIndex,
property, QQmlJSRegisterContent::InvalidLookupIndex,
QQmlJSRegisterContent::InvalidLookupIndex, QQmlJSRegisterContent::ListValue, scope);
}
@ -1781,7 +1775,7 @@ QQmlJSRegisterContent QQmlJSTypeResolver::returnType(
Q_ASSERT(variant == QQmlJSRegisterContent::MethodReturnValue
|| variant == QQmlJSRegisterContent::JavaScriptReturnValue);
return QQmlJSRegisterContent::create(
storedType(type), type, QQmlJSRegisterContent::InvalidLookupIndex, variant, scope);
type, QQmlJSRegisterContent::InvalidLookupIndex, variant, scope);
}
QQmlJSRegisterContent QQmlJSTypeResolver::iteratorPointer(
@ -1803,7 +1797,7 @@ QQmlJSRegisterContent QQmlJSTypeResolver::iteratorPointer(
prop.setTypeName(iteratorPointer->internalName());
prop.setType(iteratorPointer);
return QQmlJSRegisterContent::create(
storedType(iteratorPointer), prop, lookupIndex,
prop, lookupIndex,
QQmlJSRegisterContent::InvalidLookupIndex, QQmlJSRegisterContent::ListIterator,
listContained);
}
@ -1868,20 +1862,20 @@ QQmlJSRegisterContent QQmlJSTypeResolver::convert(
{
if (from.isConversion()) {
return QQmlJSRegisterContent::create(
to.storedType(), from.conversionOrigins(), containedType(to),
from.conversionOrigins(), containedType(to),
to.scopeType() ? to.scopeType() : from.conversionResultScope(),
from.variant(), from.scopeType());
}
return QQmlJSRegisterContent::create(
to.storedType(), QList<QQmlJSScope::ConstPtr>{containedType(from)},
QList<QQmlJSScope::ConstPtr>{containedType(from)},
containedType(to), to.scopeType(), from.variant(), from.scopeType());
}
QQmlJSRegisterContent QQmlJSTypeResolver::cast(
const QQmlJSRegisterContent &from, const QQmlJSScope::ConstPtr &to) const
{
return from.castTo(to).storedIn(storedType(to));
return from.castTo(to);
}
QQmlJSScope::ConstPtr QQmlJSTypeResolver::comparableType(const QQmlJSScope::ConstPtr &type) const

View File

@ -1374,8 +1374,7 @@ void TestQmllint::compilerWarnings_data()
QTest::newRow("shadowable")
<< QStringLiteral("shadowable.qml")
<< Result { { Message {QStringLiteral(
"with type NotSoSimple (stored as QQuickItem) can be shadowed") } } }
<< Result { { Message {QStringLiteral("with type NotSoSimple can be shadowed") } } }
<< true;
QTest::newRow("tooFewParameters")
<< QStringLiteral("tooFewParams.qml")
@ -1411,20 +1410,20 @@ void TestQmllint::compilerWarnings_data()
<< QStringLiteral("returnTypeAnnotation_component.qml")
<< Result{ { { "Could not compile function comp: function without return type "
"annotation returns (component in" },
{ "returnTypeAnnotation_component.qml)::c with type Comp (stored as "
"QQuickItem). This may prevent proper compilation to Cpp." } } }
{ "returnTypeAnnotation_component.qml)::c with type Comp. "
"This may prevent proper compilation to Cpp." } } }
<< true;
QTest::newRow("returnTypeAnnotation-enum")
<< QStringLiteral("returnTypeAnnotation_enum.qml")
<< Result{ { { "Could not compile function enumeration: function without return type "
"annotation returns QQuickText::HAlignment::AlignRight (stored as int). "
"annotation returns QQuickText::HAlignment::AlignRight. "
"This may prevent proper compilation to Cpp." } } }
<< true;
QTest::newRow("returnTypeAnnotation-method")
<< QStringLiteral("returnTypeAnnotation_method.qml")
<< Result{ { { "Could not compile function method: function without return type "
"annotation returns (component in " }, // Don't check the build folder path
{ "returnTypeAnnotation_method.qml)::f(...) (stored as QJSValue). This may "
{ "returnTypeAnnotation_method.qml)::f(...). This may "
"prevent proper compilation to Cpp." } } }
<< true;
QTest::newRow("returnTypeAnnotation-property")

View File

@ -355,9 +355,9 @@ void tst_qqmljsscope::descriptiveNameOfNull()
property.setPropertyName(u"foo"_s);
property.setTypeName(u"baz"_s);
QQmlJSRegisterContent unscoped = QQmlJSRegisterContent::create(
stored, property, QQmlJSRegisterContent::InvalidLookupIndex,
property, QQmlJSRegisterContent::InvalidLookupIndex,
QQmlJSRegisterContent::InvalidLookupIndex, QQmlJSRegisterContent::ScopeProperty,
QQmlJSScope::ConstPtr());
QQmlJSScope::ConstPtr()).storedIn(stored);
QCOMPARE(unscoped.descriptiveName(), u"(invalid type)::foo with type baz (stored as bar)"_s);
}