aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/qmlcompiler/qqmljsbasicblocks.cpp41
-rw-r--r--src/qmlcompiler/qqmljsbasicblocks_p.h3
-rw-r--r--src/qmlcompiler/qqmljscodegenerator.cpp38
-rw-r--r--src/qmlcompiler/qqmljsfunctioninitializer.cpp2
-rw-r--r--src/qmlcompiler/qqmljstypepropagator.cpp9
-rw-r--r--src/qmlcompiler/qqmljstyperesolver.cpp23
-rw-r--r--src/qmlcompiler/qqmljstyperesolver_p.h3
7 files changed, 101 insertions, 18 deletions
diff --git a/src/qmlcompiler/qqmljsbasicblocks.cpp b/src/qmlcompiler/qqmljsbasicblocks.cpp
index cce7e141eb..6c3a0d71ab 100644
--- a/src/qmlcompiler/qqmljsbasicblocks.cpp
+++ b/src/qmlcompiler/qqmljsbasicblocks.cpp
@@ -140,6 +140,14 @@ void QQmlJSBasicBlocks::generate_ThrowException()
m_skipUntilNextLabel = true;
}
+void QQmlJSBasicBlocks::generate_DefineArray(int argc, int)
+{
+ if (argc == 0)
+ return; // empty array/list, nothing to do
+
+ m_arrayDefinitions.append(currentInstructionOffset());
+}
+
void QQmlJSBasicBlocks::processJump(int offset, JumpMode mode)
{
if (offset < 0)
@@ -377,6 +385,39 @@ void QQmlJSBasicBlocks::adjustTypes()
using NewVirtualRegisters = NewFlatMap<int, QQmlJSRegisterContent>;
QHash<int, QList<int>> liveConversions;
+
+ // Handle the array definitions first.
+ // Changing the array type changes the expected element types.
+ for (int instructionOffset : m_arrayDefinitions) {
+ auto it = m_readerLocations.find(instructionOffset);
+ if (it == m_readerLocations.end())
+ continue;
+
+ const InstructionAnnotation &annotation = m_annotations[instructionOffset];
+
+ Q_ASSERT(it->trackedTypes.length() == 1);
+ Q_ASSERT(it->trackedTypes[0] == m_typeResolver->containedType(annotation.changedRegister));
+ Q_ASSERT(!annotation.readRegisters.isEmpty());
+
+ m_typeResolver->adjustTrackedType(it->trackedTypes[0], it->typeReaders.values());
+
+ // Now we don't adjust the type we store, but rather the type we expect to read. We
+ // can do this because we've tracked the read type when we defined the array in
+ // QQmlJSTypePropagator.
+ if (QQmlJSScope::ConstPtr valueType = it->trackedTypes[0]->valueType()) {
+ m_typeResolver->adjustTrackedType(
+ m_typeResolver->containedType(annotation.readRegisters.begin().value()),
+ valueType);
+ }
+
+ for (const QList<int> &conversions : qAsConst(it->registerReadersAndConversions)) {
+ for (int conversion : conversions)
+ liveConversions[conversion].append(it->trackedRegister);
+ }
+
+ m_readerLocations.erase(it);
+ }
+
for (auto it = m_readerLocations.begin(), end = m_readerLocations.end(); it != end; ++it) {
for (const QList<int> &conversions : qAsConst(it->registerReadersAndConversions)) {
for (int conversion : conversions)
diff --git a/src/qmlcompiler/qqmljsbasicblocks_p.h b/src/qmlcompiler/qqmljsbasicblocks_p.h
index e895dc7fe6..e5a39104db 100644
--- a/src/qmlcompiler/qqmljsbasicblocks_p.h
+++ b/src/qmlcompiler/qqmljsbasicblocks_p.h
@@ -88,6 +88,8 @@ private:
void generate_Ret() override;
void generate_ThrowException() override;
+ void generate_DefineArray(int argc, int argv) override;
+
enum JumpMode { Unconditional, Conditional };
void processJump(int offset, JumpMode mode);
void populateBasicBlocks();
@@ -97,6 +99,7 @@ private:
InstructionAnnotations m_annotations;
QFlatMap<int, BasicBlock> m_basicBlocks;
QHash<int, RegisterAccess> m_readerLocations;
+ QList<int> m_arrayDefinitions;
bool m_skipUntilNextLabel = false;
bool m_hadBackJumps = false;
};
diff --git a/src/qmlcompiler/qqmljscodegenerator.cpp b/src/qmlcompiler/qqmljscodegenerator.cpp
index 7867a244c2..dd564207d8 100644
--- a/src/qmlcompiler/qqmljscodegenerator.cpp
+++ b/src/qmlcompiler/qqmljscodegenerator.cpp
@@ -1561,15 +1561,37 @@ void QQmlJSCodeGenerator::generate_DeclareVar(int varName, int isDeletable)
void QQmlJSCodeGenerator::generate_DefineArray(int argc, int args)
{
- Q_UNUSED(args);
- if (argc > 0)
- reject(u"DefineArray"_qs);
+ INJECT_TRACE_INFO(generate_DefineArray);
- m_body += m_state.accumulatorVariableOut + u" = "_qs;
- m_body += conversion(m_typeResolver->emptyListType(), m_state.accumulatorOut().storedType(),
- QString());
- m_body += u";\n"_qs;
- generateOutputVariantConversion(m_typeResolver->emptyListType());
+ const QQmlJSScope::ConstPtr stored = m_state.accumulatorOut().storedType();
+
+ if (argc == 0) {
+ m_body += m_state.accumulatorVariableOut + u" = "_qs;
+ m_body += conversion(m_typeResolver->emptyListType(), stored, QString());
+ m_body += u";\n"_qs;
+ generateOutputVariantConversion(m_typeResolver->emptyListType());
+ return;
+ }
+
+ if (stored->accessSemantics() != QQmlJSScope::AccessSemantics::Sequence) {
+ // This rejects any attempt to store the list into a QVariant.
+ // Therefore, we don't have to adjust the contained type below.
+ reject(u"storing an array in a non-sequence type"_qs);
+ return;
+ }
+
+ const QQmlJSScope::ConstPtr value = stored->valueType();
+ Q_ASSERT(value);
+
+ QStringList initializer;
+ for (int i = 0; i < argc; ++i) {
+ initializer += conversion(registerType(args + i).storedType(), value,
+ registerVariable(args + i));
+ }
+
+ m_body += m_state.accumulatorVariableOut + u" = "_qs + stored->internalName() + u'{';
+ m_body += initializer.join(u", "_qs);
+ m_body += u"};\n";
}
void QQmlJSCodeGenerator::generate_DefineObjectLiteral(int internalClassId, int argc, int args)
diff --git a/src/qmlcompiler/qqmljsfunctioninitializer.cpp b/src/qmlcompiler/qqmljsfunctioninitializer.cpp
index c993197399..ce8df3148f 100644
--- a/src/qmlcompiler/qqmljsfunctioninitializer.cpp
+++ b/src/qmlcompiler/qqmljsfunctioninitializer.cpp
@@ -188,7 +188,7 @@ QQmlJSCompilePass::Function QQmlJSFunctionInitializer::run(
const auto property = m_objectType->property(propertyName);
function.returnType = property.isList()
- ? m_typeResolver->listType(property.type())
+ ? m_typeResolver->listType(property.type(), QQmlJSTypeResolver::UseQObjectList)
: QQmlJSScope::ConstPtr(property.type());
diff --git a/src/qmlcompiler/qqmljstypepropagator.cpp b/src/qmlcompiler/qqmljstypepropagator.cpp
index 1e48a615f6..fbcdccafaf 100644
--- a/src/qmlcompiler/qqmljstypepropagator.cpp
+++ b/src/qmlcompiler/qqmljstypepropagator.cpp
@@ -1412,10 +1412,15 @@ void QQmlJSTypePropagator::generate_DeclareVar(int varName, int isDeletable)
void QQmlJSTypePropagator::generate_DefineArray(int argc, int args)
{
- Q_UNUSED(args);
setAccumulator(m_typeResolver->globalType(argc == 0
? m_typeResolver->emptyListType()
- : m_typeResolver->jsValueType()));
+ : m_typeResolver->variantListType()));
+
+ // Track all arguments as the same type.
+ const QQmlJSRegisterContent elementType
+ = m_typeResolver->tracked(m_typeResolver->globalType(m_typeResolver->varType()));
+ for (int i = 0; i < argc; ++i)
+ addReadRegister(args + i, elementType);
}
void QQmlJSTypePropagator::generate_DefineObjectLiteral(int internalClassId, int argc, int args)
diff --git a/src/qmlcompiler/qqmljstyperesolver.cpp b/src/qmlcompiler/qqmljstyperesolver.cpp
index 1b0520e70d..766e8513db 100644
--- a/src/qmlcompiler/qqmljstyperesolver.cpp
+++ b/src/qmlcompiler/qqmljstyperesolver.cpp
@@ -96,6 +96,8 @@ QQmlJSTypeResolver::QQmlJSTypeResolver(QQmlJSImporter *importer)
listPropertyType->setInternalName(u"QQmlListProperty<QObject>"_qs);
listPropertyType->setFilePath(u"qqmllist.h"_qs);
listPropertyType->setAccessSemantics(QQmlJSScope::AccessSemantics::Sequence);
+ listPropertyType->setValueTypeName(u"QObject"_qs);
+ QQmlJSScope::resolveTypes(listPropertyType, builtinTypes);
m_listPropertyType = listPropertyType;
QQmlJSScope::Ptr metaObjectType = QQmlJSScope::create();
@@ -177,7 +179,8 @@ QQmlJSScope::ConstPtr QQmlJSTypeResolver::scopeForId(
return m_objectsById.scope(id, referrer);
}
-QQmlJSScope::ConstPtr QQmlJSTypeResolver::listType(const QQmlJSScope::ConstPtr &elementType) const
+QQmlJSScope::ConstPtr QQmlJSTypeResolver::listType(
+ const QQmlJSScope::ConstPtr &elementType, ListMode mode) const
{
auto it = m_typeTracker->listTypes.find(elementType);
if (it != m_typeTracker->listTypes.end())
@@ -185,12 +188,16 @@ QQmlJSScope::ConstPtr QQmlJSTypeResolver::listType(const QQmlJSScope::ConstPtr &
switch (elementType->accessSemantics()) {
case QQmlJSScope::AccessSemantics::Reference:
- return m_listPropertyType;
+ if (mode == UseListReference)
+ return m_listPropertyType;
+ if (elementType->internalName() != u"QObject"_qs)
+ return listType(genericType(elementType), mode);
+ Q_FALLTHROUGH();
case QQmlJSScope::AccessSemantics::Value: {
QQmlJSScope::Ptr listType = QQmlJSScope::create();
listType->setAccessSemantics(QQmlJSScope::AccessSemantics::Sequence);
listType->setValueTypeName(elementType->internalName());
- listType->setInternalName(u"QList<%1>"_qs.arg(elementType->internalName()));
+ listType->setInternalName(u"QList<%1>"_qs.arg(elementType->augmentedInternalName()));
listType->setFilePath(elementType->filePath());
const QQmlJSImportedScope element = {elementType, QTypeRevision()};
QQmlJSScope::resolveTypes(listType, {{elementType->internalName(), element}});
@@ -344,7 +351,9 @@ QQmlJSTypeResolver::containedType(const QQmlJSRegisterContent &container) const
return container.type();
if (container.isProperty()) {
const QQmlJSMetaProperty prop = container.property();
- return prop.isList() ? listType(prop.type()) : QQmlJSScope::ConstPtr(prop.type());
+ return prop.isList()
+ ? listType(prop.type(), UseListReference)
+ : QQmlJSScope::ConstPtr(prop.type());
}
if (container.isEnumeration())
return container.enumeration().type();
@@ -709,7 +718,9 @@ QQmlJSScope::ConstPtr QQmlJSTypeResolver::genericType(const QQmlJSScope::ConstPt
return m_intType;
if (type->accessSemantics() == QQmlJSScope::AccessSemantics::Sequence) {
- return listType(genericType(type->valueType()));
+ return equals(type, m_listPropertyType)
+ ? type
+ : listType(genericType(type->valueType()), UseQObjectList);
}
return m_varType;
@@ -977,7 +988,7 @@ bool QQmlJSTypeResolver::canPrimitivelyConvertFromTo(
if (equals(to, m_jsPrimitiveType))
return isPrimitive(from);
- if (equals(from, m_emptyListType))
+ if (equals(from, m_emptyListType) || equals(from, m_variantListType))
return to->accessSemantics() == QQmlJSScope::AccessSemantics::Sequence;
const bool matchByName = !to->isComposite();
diff --git a/src/qmlcompiler/qqmljstyperesolver_p.h b/src/qmlcompiler/qqmljstyperesolver_p.h
index 32c64b89f7..4426a31f86 100644
--- a/src/qmlcompiler/qqmljstyperesolver_p.h
+++ b/src/qmlcompiler/qqmljstyperesolver_p.h
@@ -89,7 +89,8 @@ public:
return m_imports.contains(name) && !m_imports[name].scope;
}
- QQmlJSScope::ConstPtr listType(const QQmlJSScope::ConstPtr &elementType) const;
+ enum ListMode { UseListReference, UseQObjectList };
+ QQmlJSScope::ConstPtr listType(const QQmlJSScope::ConstPtr &elementType, ListMode mode) const;
QQmlJSScope::ConstPtr typeForName(const QString &name) const { return m_imports[name].scope; }
QQmlJSScope::ConstPtr typeFromAST(QQmlJS::AST::Type *type) const;
QQmlJSScope::ConstPtr typeForConst(QV4::ReturnedValue rv) const;