aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/imports/builtins/builtins.qmltypes14
-rw-r--r--src/qmlcompiler/qqmljscodegenerator.cpp24
-rw-r--r--src/qmlcompiler/qqmljscompiler.cpp1
-rw-r--r--src/qmlcompiler/qqmljsfunctioninitializer.cpp11
-rw-r--r--src/qmlcompiler/qqmljsimporter.cpp5
-rw-r--r--src/qmlcompiler/qqmljsimportvisitor.cpp6
-rw-r--r--src/qmlcompiler/qqmljsregistercontent.cpp8
-rw-r--r--src/qmlcompiler/qqmljsscope.cpp86
-rw-r--r--src/qmlcompiler/qqmljsscope_p.h9
-rw-r--r--src/qmlcompiler/qqmljsstoragegeneralizer.cpp6
-rw-r--r--src/qmlcompiler/qqmljstyperesolver.cpp179
-rw-r--r--src/qmlcompiler/qqmljstyperesolver_p.h14
12 files changed, 205 insertions, 158 deletions
diff --git a/src/imports/builtins/builtins.qmltypes b/src/imports/builtins/builtins.qmltypes
index f76acc93e1..7a74279ee8 100644
--- a/src/imports/builtins/builtins.qmltypes
+++ b/src/imports/builtins/builtins.qmltypes
@@ -154,6 +154,20 @@ Module {
}
Component {
+ file: "qqmllist.h"
+ name: "QQmlListProperty<QObject>"
+ accessSemantics: "sequence"
+ valueType: "QObject"
+ }
+
+ Component {
+ file: "qobject.h"
+ name: "QObjectList"
+ accessSemantics: "sequence"
+ valueType: "QObject"
+ }
+
+ Component {
name: "int"
extension: "Number"
exports: ["QML/int 1.0"]
diff --git a/src/qmlcompiler/qqmljscodegenerator.cpp b/src/qmlcompiler/qqmljscodegenerator.cpp
index 72db1e11db..d0297a1abb 100644
--- a/src/qmlcompiler/qqmljscodegenerator.cpp
+++ b/src/qmlcompiler/qqmljscodegenerator.cpp
@@ -1794,9 +1794,21 @@ void QQmlJSCodeGenerator::generate_DefineArray(int argc, int args)
registerVariable(args + i));
}
- m_body += m_state.accumulatorVariableOut + u" = "_s + stored->internalName() + u'{';
- m_body += initializer.join(u", "_s);
- m_body += u"};\n";
+ if (stored->isListProperty()) {
+ reject(u"creating a QQmlListProperty not backed by a property"_s);
+
+ // We can, technically, generate code for this. But it's dangerous:
+ //
+ // const QString storage = m_state.accumulatorVariableOut + u"_storage"_s;
+ // m_body += stored->internalName() + u"::ListType " + storage
+ // + u" = {"_s + initializer.join(u", "_s) + u"};\n"_s;
+ // m_body += m_state.accumulatorVariableOut
+ // + u" = " + stored->internalName() + u"(nullptr, &"_s + storage + u");\n"_s;
+ } else {
+ m_body += m_state.accumulatorVariableOut + u" = "_s + stored->internalName() + u'{';
+ m_body += initializer.join(u", "_s);
+ m_body += u"};\n";
+ }
}
void QQmlJSCodeGenerator::generate_DefineObjectLiteral(int internalClassId, int argc, int args)
@@ -1994,6 +2006,9 @@ QString QQmlJSCodeGenerator::contentPointer(const QQmlJSRegisterContent &content
return u'&' + var;
}
+ if (stored->isListProperty() && m_typeResolver->containedType(content)->isListProperty())
+ return u'&' + var;
+
reject(u"content pointer of non-QVariant wrapper type "_s + content.descriptiveName());
return QString();
}
@@ -2017,6 +2032,9 @@ QString QQmlJSCodeGenerator::contentType(const QQmlJSRegisterContent &content, c
return metaTypeFromType(m_typeResolver->intType());
}
+ if (stored->isListProperty() && m_typeResolver->containedType(content)->isListProperty())
+ return metaTypeFromType(m_typeResolver->listPropertyType());
+
reject(u"content type of non-QVariant wrapper type "_s + content.descriptiveName());
return QString();
}
diff --git a/src/qmlcompiler/qqmljscompiler.cpp b/src/qmlcompiler/qqmljscompiler.cpp
index 5bd7a7f0b0..53798db475 100644
--- a/src/qmlcompiler/qqmljscompiler.cpp
+++ b/src/qmlcompiler/qqmljscompiler.cpp
@@ -746,6 +746,7 @@ QQmlJSAotFunction QQmlJSAotCompiler::globalCode() const
u"QtQml/qqmlcomponent.h"_s,
u"QtQml/qqmlcontext.h"_s,
u"QtQml/qqmlengine.h"_s,
+ u"QtQml/qqmllist.h"_s,
u"QtCore/qdatetime.h"_s,
u"QtCore/qobject.h"_s,
diff --git a/src/qmlcompiler/qqmljsfunctioninitializer.cpp b/src/qmlcompiler/qqmljsfunctioninitializer.cpp
index 54bef282ea..b3c448072c 100644
--- a/src/qmlcompiler/qqmljsfunctioninitializer.cpp
+++ b/src/qmlcompiler/qqmljsfunctioninitializer.cpp
@@ -206,12 +206,11 @@ QQmlJSCompilePass::Function QQmlJSFunctionInitializer::run(
}
const auto property = m_objectType->property(propertyName);
- function.returnType = property.isList()
- ? m_typeResolver->listType(property.type(), QQmlJSTypeResolver::UseQObjectList)
- : QQmlJSScope::ConstPtr(property.type());
-
-
- if (!function.returnType) {
+ if (const QQmlJSScope::ConstPtr propertyType = property.type()) {
+ function.returnType = propertyType->isListProperty()
+ ? m_typeResolver->qObjectListType()
+ : propertyType;
+ } else {
diagnose(u"Cannot resolve property type %1 for binding on %2"_s.arg(
property.typeName(), propertyName),
QtWarningMsg, bindingLocation, error);
diff --git a/src/qmlcompiler/qqmljsimporter.cpp b/src/qmlcompiler/qqmljsimporter.cpp
index c5048705c9..f8adeb79c2 100644
--- a/src/qmlcompiler/qqmljsimporter.cpp
+++ b/src/qmlcompiler/qqmljsimporter.cpp
@@ -462,9 +462,12 @@ void QQmlJSImporter::processImport(const QQmlJSScope::Import &importDescription,
// resolve enumerations (which can potentially create new child scopes)
// before resolving the type fully
const QQmlJSScope::ConstPtr intType = tempTypes.cppNames.type(u"int"_s).scope;
+ const QQmlJSScope::ConstPtr arrayType = tempTypes.cppNames.type(u"Array"_s).scope;
for (auto it = import.objects.begin(); it != import.objects.end(); ++it) {
- if (!it->scope.factory())
+ if (!it->scope.factory()) {
QQmlJSScope::resolveEnums(it->scope, intType);
+ QQmlJSScope::resolveList(it->scope, arrayType);
+ }
}
for (auto it = import.objects.begin(); it != import.objects.end(); ++it) {
diff --git a/src/qmlcompiler/qqmljsimportvisitor.cpp b/src/qmlcompiler/qqmljsimportvisitor.cpp
index 369159e68a..7392d44ad7 100644
--- a/src/qmlcompiler/qqmljsimportvisitor.cpp
+++ b/src/qmlcompiler/qqmljsimportvisitor.cpp
@@ -558,7 +558,9 @@ void QQmlJSImportVisitor::processDefaultProperties()
const QQmlJSMetaProperty defaultProp = parentScope->property(defaultPropertyName);
- if (it.value().size() > 1 && !defaultProp.isList()) {
+ if (it.value().size() > 1
+ && !defaultProp.isList()
+ && !defaultProp.type()->isListProperty()) {
m_logger->log(
QStringLiteral("Cannot assign multiple objects to a default non-list property"),
qmlNonListProperty, it.value().constFirst()->sourceLocation());
@@ -1477,7 +1479,7 @@ bool QQmlJSImportVisitor::visit(UiPublicMember *publicMember)
const auto type =
isAlias ? QQmlJSScope::ConstPtr() : m_rootScopeImports.type(typeName).scope;
if (type) {
- prop.setType(type);
+ prop.setType(prop.isList() ? type->listType() : type);
const QString internalName = type->internalName();
prop.setTypeName(internalName.isEmpty() ? typeName : internalName);
} else if (!isAlias) {
diff --git a/src/qmlcompiler/qqmljsregistercontent.cpp b/src/qmlcompiler/qqmljsregistercontent.cpp
index 60f51bc302..1573f889a1 100644
--- a/src/qmlcompiler/qqmljsregistercontent.cpp
+++ b/src/qmlcompiler/qqmljsregistercontent.cpp
@@ -63,11 +63,9 @@ bool QQmlJSRegisterContent::isList() const
case Type:
return std::get<QQmlJSScope::ConstPtr>(m_content)->accessSemantics()
== QQmlJSScope::AccessSemantics::Sequence;
- case Property: {
- const auto prop = std::get<QQmlJSMetaProperty>(m_content);
- return prop.isList()
- || prop.type()->accessSemantics() == QQmlJSScope::AccessSemantics::Sequence;
- }
+ case Property:
+ return std::get<QQmlJSMetaProperty>(m_content).type()->accessSemantics()
+ == QQmlJSScope::AccessSemantics::Sequence;
case Conversion:
return std::get<ConvertedTypes>(m_content).result->accessSemantics()
== QQmlJSScope::AccessSemantics::Sequence;
diff --git a/src/qmlcompiler/qqmljsscope.cpp b/src/qmlcompiler/qqmljsscope.cpp
index 5b064c5233..94177f6672 100644
--- a/src/qmlcompiler/qqmljsscope.cpp
+++ b/src/qmlcompiler/qqmljsscope.cpp
@@ -379,8 +379,35 @@ QQmlJSScope::ImportedScope<QQmlJSScope::ConstPtr> QQmlJSScope::findType(
return *type;
}
+ const auto findListType = [&](const QString &prefix, const QString &postfix)
+ -> ImportedScope<ConstPtr> {
+ if (name.startsWith(prefix) && name.endsWith(postfix)) {
+ const qsizetype prefixLength = prefix.length();
+ const QString &elementName
+ = name.mid(prefixLength, name.length() - prefixLength - postfix.length());
+ const ImportedScope<ConstPtr> element
+ = findType(elementName, contextualTypes, usedTypes);
+ if (element.scope) {
+ useType();
+ return { element.scope->listType(), element.revision };
+ }
+ }
+
+ return {};
+ };
+
switch (contextualTypes.context()) {
case ContextualTypes::INTERNAL: {
+ if (const auto listType = findListType(u"QList<"_s, u">"_s);
+ listType.scope && !listType.scope->isReferenceType()) {
+ return listType;
+ }
+
+ if (const auto listType = findListType(u"QQmlListProperty<"_s, u">"_s);
+ listType.scope && listType.scope->isReferenceType()) {
+ return listType;
+ }
+
// look for c++ namescoped enums!
const auto colonColon = name.lastIndexOf(QStringLiteral("::"));
if (colonColon == -1)
@@ -407,6 +434,10 @@ QQmlJSScope::ImportedScope<QQmlJSScope::ConstPtr> QQmlJSScope::findType(
useType();
return inlineComponent;
}
+
+ if (const auto listType = findListType(u"list<"_s, u">"_s); listType.scope)
+ return listType;
+
break;
}
}
@@ -417,6 +448,11 @@ QTypeRevision QQmlJSScope::resolveType(
const QQmlJSScope::Ptr &self, const QQmlJSScope::ContextualTypes &context,
QSet<QString> *usedTypes)
{
+ if (self->accessSemantics() == AccessSemantics::Sequence
+ && self->internalName().startsWith(u"QQmlListProperty<"_s)) {
+ self->setIsListProperty(true);
+ }
+
const QString baseTypeName = self->baseTypeName();
const auto baseType = findType(baseTypeName, context, usedTypes);
if (!self->m_baseType.scope && !baseTypeName.isEmpty())
@@ -447,13 +483,16 @@ QTypeRevision QQmlJSScope::resolveType(
continue;
if (const auto type = findType(typeName, context, usedTypes); type.scope) {
- it->setType(type.scope);
+ it->setType(it->isList() ? type.scope->listType() : type.scope);
continue;
}
const auto enumeration = self->m_enumerations.find(typeName);
- if (enumeration != self->m_enumerations.end())
- it->setType(enumeration->type());
+ if (enumeration != self->m_enumerations.end()) {
+ it->setType(it->isList()
+ ? enumeration->type()->listType()
+ : QQmlJSScope::ConstPtr(enumeration->type()));
+ }
}
for (auto it = self->m_methods.begin(), end = self->m_methods.end(); it != end; ++it) {
@@ -540,6 +579,7 @@ QTypeRevision QQmlJSScope::resolveTypes(
const QQmlJSScope::ContextualTypes &contextualTypes,
QSet<QString> *usedTypes) {
resolveEnums(self, contextualTypes.intType());
+ resolveList(self, contextualTypes.arrayType());
return resolveType(self, contextualTypes, usedTypes);
};
return resolveTypesInternal(resolveAll, updateChildScope, self, contextualTypes, usedTypes);
@@ -570,6 +610,40 @@ void QQmlJSScope::resolveEnums(const QQmlJSScope::Ptr &self, const QQmlJSScope::
}
}
+void QQmlJSScope::resolveList(const QQmlJSScope::Ptr &self, const QQmlJSScope::ConstPtr &arrayType)
+{
+ if (self->listType() || self->accessSemantics() == AccessSemantics::Sequence)
+ return;
+
+ Q_ASSERT(!arrayType.isNull());
+ QQmlJSScope::Ptr listType = QQmlJSScope::create();
+ listType->setAccessSemantics(AccessSemantics::Sequence);
+ listType->setValueTypeName(self->internalName());
+
+ if (self->isComposite()) {
+ // There is no internalName for this thing. Just set the value type right away
+ listType->setInternalName(u"QQmlListProperty<>"_s);
+ listType->m_valueType = QQmlJSScope::ConstPtr(self);
+ } else if (self->isReferenceType()) {
+ listType->setInternalName(u"QQmlListProperty<%2>"_s.arg(self->internalName()));
+ // Do not set a filePath on the list type, so that we have to generalize it
+ // even in direct mode.
+ } else {
+ listType->setInternalName(u"QList<%2>"_s.arg(self->internalName()));
+ listType->setFilePath(self->filePath());
+ }
+
+ const QQmlJSImportedScope element = {self, QTypeRevision()};
+ const QQmlJSImportedScope array = {arrayType, QTypeRevision()};
+ QQmlJSScope::ContextualTypes contextualTypes(
+ QQmlJSScope::ContextualTypes::INTERNAL, { { self->internalName(), element }, },
+ QQmlJSScope::ConstPtr(), arrayType);
+ QQmlJSScope::resolveTypes(listType, contextualTypes);
+
+ Q_ASSERT(listType->valueType() == self);
+ self->m_listType = listType;
+}
+
void QQmlJSScope::resolveGeneralizedGroup(
const Ptr &self, const ConstPtr &baseType,
const QQmlJSScope::ContextualTypes &contextualTypes, QSet<QString> *usedTypes)
@@ -1003,6 +1077,7 @@ void QDeferredFactory<QQmlJSScope>::populate(const QSharedPointer<QQmlJSScope> &
m_importer->m_globalWarnings.append(typeReader.errors());
scope->setInternalName(internalName());
QQmlJSScope::resolveEnums(scope, m_importer->builtinInternalNames().intType());
+ QQmlJSScope::resolveList(scope, m_importer->builtinInternalNames().arrayType());
if (m_isSingleton && !scope->isSingleton()) {
m_importer->m_globalWarnings.append(
@@ -1054,7 +1129,10 @@ bool QQmlJSScope::canAssign(const QQmlJSScope::ConstPtr &derived) const
return true;
}
- return internalName() == u"QVariant"_s || internalName() == u"QJSValue"_s;
+ if (internalName() == u"QVariant"_s || internalName() == u"QJSValue"_s)
+ return true;
+
+ return isListProperty() && valueType()->canAssign(derived);
}
bool QQmlJSScope::isInCustomParserParent() const
diff --git a/src/qmlcompiler/qqmljsscope_p.h b/src/qmlcompiler/qqmljsscope_p.h
index 3a5b26e3f0..0745acd668 100644
--- a/src/qmlcompiler/qqmljsscope_p.h
+++ b/src/qmlcompiler/qqmljsscope_p.h
@@ -81,6 +81,7 @@ public:
WrappedInImplicitComponent = 0x80,
HasBaseTypeError = 0x100,
HasExtensionNamespace = 0x200,
+ IsListProperty = 0x400,
};
Q_DECLARE_FLAGS(Flags, Flag)
Q_FLAGS(Flags);
@@ -490,6 +491,8 @@ public:
QString valueTypeName() const { return m_valueTypeName; }
void setValueTypeName(const QString &name) { m_valueTypeName = name; }
QQmlJSScope::ConstPtr valueType() const { return m_valueType; }
+ QQmlJSScope::ConstPtr listType() const { return m_listType; }
+ QQmlJSScope::Ptr listType() { return m_listType; }
void addOwnRuntimeFunctionIndex(QQmlJSMetaMethod::AbsoluteFunctionIndex index)
{
@@ -531,6 +534,9 @@ public:
void setIsWrappedInImplicitComponent(bool v) { m_flags.setFlag(WrappedInImplicitComponent, v); }
void setExtensionIsNamespace(bool v) { m_flags.setFlag(HasExtensionNamespace, v); }
+ bool isListProperty() const { return m_flags.testFlag(IsListProperty); }
+ void setIsListProperty(bool v) { m_flags.setFlag(IsListProperty, v); }
+
void setAccessSemantics(AccessSemantics semantics) { m_semantics = semantics; }
AccessSemantics accessSemantics() const { return m_semantics; }
bool isReferenceType() const { return m_semantics == QQmlJSScope::AccessSemantics::Reference; }
@@ -574,6 +580,8 @@ public:
QSet<QString> *usedTypes = nullptr);
static void resolveEnums(
const QQmlJSScope::Ptr &self, const QQmlJSScope::ConstPtr &intType);
+ static void resolveList(
+ const QQmlJSScope::Ptr &self, const QQmlJSScope::ConstPtr &arrayType);
static void resolveGeneralizedGroup(
const QQmlJSScope::Ptr &self, const QQmlJSScope::ConstPtr &baseType,
const QQmlJSScope::ContextualTypes &contextualTypes,
@@ -738,6 +746,7 @@ private:
*/
QString m_valueTypeName;
QQmlJSScope::WeakConstPtr m_valueType;
+ QQmlJSScope::Ptr m_listType;
/*!
The extension is provided as either a type (QML_{NAMESPACE_}EXTENDED) or as a
diff --git a/src/qmlcompiler/qqmljsstoragegeneralizer.cpp b/src/qmlcompiler/qqmljsstoragegeneralizer.cpp
index 22cfd4c175..ed3743bc61 100644
--- a/src/qmlcompiler/qqmljsstoragegeneralizer.cpp
+++ b/src/qmlcompiler/qqmljsstoragegeneralizer.cpp
@@ -43,8 +43,10 @@ QQmlJSCompilePass::InstructionAnnotations QQmlJSStorageGeneralizer::run(
const auto transformRegisters
= [&](QFlatMap<int, QQmlJSRegisterContent> &registers) {
- for (auto j = registers.begin(), jEnd = registers.end(); j != jEnd; ++j)
- transformRegister(j.value());
+ for (auto j = registers.begin(), jEnd = registers.end(); j != jEnd; ++j) {
+ QQmlJSRegisterContent &content = j.value();
+ transformRegister(content);
+ }
};
for (QQmlJSRegisterContent &argument : function->argumentTypes) {
diff --git a/src/qmlcompiler/qqmljstyperesolver.cpp b/src/qmlcompiler/qqmljstyperesolver.cpp
index 8c2e1896de..3bda081121 100644
--- a/src/qmlcompiler/qqmljstyperesolver.cpp
+++ b/src/qmlcompiler/qqmljstyperesolver.cpp
@@ -21,7 +21,7 @@ Q_LOGGING_CATEGORY(lcTypeResolver, "qt.qml.compiler.typeresolver", QtInfoMsg);
QQmlJSTypeResolver::QQmlJSTypeResolver(QQmlJSImporter *importer)
: m_imports(importer->builtinInternalNames())
- , m_typeTracker(std::make_unique<TypeTracker>())
+ , m_trackedTypes(std::make_unique<QHash<QQmlJSScope::ConstPtr, TrackedType>>())
{
const QQmlJSImporter::ImportedTypes &builtinTypes = m_imports;
m_voidType = builtinTypes.type(u"void"_s).scope;
@@ -39,6 +39,8 @@ QQmlJSTypeResolver::QQmlJSTypeResolver(QQmlJSImporter *importer)
m_variantListType = builtinTypes.type(u"QVariantList"_s).scope;
m_varType = builtinTypes.type(u"QVariant"_s).scope;
m_jsValueType = builtinTypes.type(u"QJSValue"_s).scope;
+ m_listPropertyType = builtinTypes.type(u"QQmlListProperty<QObject>"_s).scope;
+ m_qObjectListType = builtinTypes.type(u"QObjectList"_s).scope;
QQmlJSScope::Ptr emptyListType = QQmlJSScope::create();
emptyListType->setInternalName(u"void*"_s);
@@ -53,15 +55,6 @@ QQmlJSTypeResolver::QQmlJSTypeResolver(QQmlJSImporter *importer)
jsPrimitiveType->setAccessSemantics(QQmlJSScope::AccessSemantics::Value);
m_jsPrimitiveType = jsPrimitiveType;
- QQmlJSScope::Ptr listPropertyType = QQmlJSScope::create();
- listPropertyType->setInternalName(u"QQmlListProperty<QObject>"_s);
- listPropertyType->setFilePath(u"qqmllist.h"_s);
- listPropertyType->setAccessSemantics(QQmlJSScope::AccessSemantics::Sequence);
- listPropertyType->setValueTypeName(u"QObject"_s);
- QQmlJSScope::resolveTypes(listPropertyType, builtinTypes);
- Q_ASSERT(!listPropertyType->extensionType().scope.isNull());
- m_listPropertyType = listPropertyType;
-
QQmlJSScope::Ptr metaObjectType = QQmlJSScope::create();
metaObjectType->setInternalName(u"const QMetaObject"_s);
metaObjectType->setFilePath(u"qmetaobject.h"_s);
@@ -126,49 +119,18 @@ QQmlJSScope::ConstPtr QQmlJSTypeResolver::scopeForId(
return m_objectsById.scope(id, referrer);
}
-QQmlJSScope::ConstPtr QQmlJSTypeResolver::listType(
- const QQmlJSScope::ConstPtr &elementType, ListMode mode) const
-{
- if (elementType.isNull())
- return QQmlJSScope::ConstPtr();
-
- auto it = m_typeTracker->listTypes.find(elementType);
- if (it != m_typeTracker->listTypes.end())
- return *it;
-
- switch (elementType->accessSemantics()) {
- case QQmlJSScope::AccessSemantics::Reference:
- if (mode == UseListReference)
- return m_listPropertyType;
- if (elementType->internalName() != u"QObject"_s)
- 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>"_s.arg(elementType->augmentedInternalName()));
- listType->setFilePath(elementType->filePath());
- const QQmlJSImportedScope element = {elementType, QTypeRevision()};
- const QQmlJSImportedScope array = {m_arrayType, QTypeRevision()};
- QQmlJSScope::ContextualTypes contextualTypes(
- QQmlJSScope::ContextualTypes::INTERNAL,
- { { elementType->internalName(), element } },
- m_intType, m_arrayType);
- QQmlJSScope::resolveTypes(listType, contextualTypes);
- Q_ASSERT(equals(listType->valueType(), elementType));
- m_typeTracker->listTypes[elementType] = listType;
- return listType;
- }
- default:
- break;
- }
- return QQmlJSScope::ConstPtr();
-}
-
QQmlJSScope::ConstPtr QQmlJSTypeResolver::typeFromAST(QQmlJS::AST::Type *type) const
{
- return m_imports.type(QmlIR::IRBuilder::asString(type->typeId)).scope;
+ const QString typeId = QmlIR::IRBuilder::asString(type->typeId);
+#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
+ if (!type->typeArgument)
+ return m_imports.type(typeId).scope;
+ if (typeId == u"list"_s)
+ return typeForName(type->typeArgument->toString())->listType();
+ return QQmlJSScope::ConstPtr();
+#else
+ return m_imports.type(typeId).scope;
+#endif
}
QQmlJSScope::ConstPtr QQmlJSTypeResolver::typeForConst(QV4::ReturnedValue rv) const
@@ -309,12 +271,8 @@ QQmlJSTypeResolver::containedType(const QQmlJSRegisterContent &container) const
{
if (container.isType())
return container.type();
- if (container.isProperty()) {
- const QQmlJSMetaProperty prop = container.property();
- return prop.isList()
- ? listType(prop.type(), UseListReference)
- : QQmlJSScope::ConstPtr(prop.type());
- }
+ if (container.isProperty())
+ return container.property().type();
if (container.isEnumeration())
return container.enumeration().type();
if (container.isMethod())
@@ -335,33 +293,17 @@ QQmlJSTypeResolver::containedType(const QQmlJSRegisterContent &container) const
Q_UNREACHABLE_RETURN({});
}
-void QQmlJSTypeResolver::trackListPropertyType(
- const QQmlJSScope::ConstPtr &trackedListElementType) const
-{
- if (m_cloneMode == QQmlJSTypeResolver::DoNotCloneTypes)
- return;
-
- if (m_typeTracker->trackedTypes.contains(trackedListElementType)
- && !m_typeTracker->listTypes.contains(trackedListElementType)) {
- const QQmlJSScope::ConstPtr list = listType(
- comparableType(trackedListElementType), UseListReference);
- QQmlJSScope::Ptr clone = QQmlJSScope::clone(list);
- m_typeTracker->listTypes[trackedListElementType] = clone;
- m_typeTracker->trackedTypes[clone] = { list, QQmlJSScope::ConstPtr(), clone };
- }
-}
-
QQmlJSScope::ConstPtr QQmlJSTypeResolver::trackedType(const QQmlJSScope::ConstPtr &type) const
{
if (m_cloneMode == QQmlJSTypeResolver::DoNotCloneTypes)
return type;
// If origin is in fact an already tracked type, track the original of that one instead.
- const auto it = m_typeTracker->trackedTypes.find(type);
- QQmlJSScope::ConstPtr orig = (it == m_typeTracker->trackedTypes.end()) ? type : it->original;
+ const auto it = m_trackedTypes->find(type);
+ QQmlJSScope::ConstPtr orig = (it == m_trackedTypes->end()) ? type : it->original;
QQmlJSScope::Ptr clone = QQmlJSScope::clone(orig);
- m_typeTracker->trackedTypes[clone] = { std::move(orig), QQmlJSScope::ConstPtr(), clone };
+ m_trackedTypes->insert(clone, { std::move(orig), QQmlJSScope::ConstPtr(), clone });
return clone;
}
@@ -378,8 +320,6 @@ QQmlJSRegisterContent QQmlJSTypeResolver::transformed(
if (origin.isProperty()) {
QQmlJSMetaProperty prop = origin.property();
prop.setType((this->*op)(prop.type()));
- if (prop.isList())
- trackListPropertyType(prop.type());
return QQmlJSRegisterContent::create(
(this->*op)(origin.storedType()), prop,
origin.variant(), (this->*op)(origin.scopeType()));
@@ -487,7 +427,7 @@ QQmlJSScope::ConstPtr QQmlJSTypeResolver::trackedContainedType(
const QQmlJSRegisterContent &container) const
{
const QQmlJSScope::ConstPtr type = containedType(container);
- return m_typeTracker->trackedTypes.contains(type) ? type : QQmlJSScope::ConstPtr();
+ return m_trackedTypes->contains(type) ? type : QQmlJSScope::ConstPtr();
}
QQmlJSScope::ConstPtr QQmlJSTypeResolver::originalContainedType(
@@ -502,8 +442,8 @@ void QQmlJSTypeResolver::adjustTrackedType(
if (m_cloneMode == QQmlJSTypeResolver::DoNotCloneTypes)
return;
- const auto it = m_typeTracker->trackedTypes.find(tracked);
- Q_ASSERT(it != m_typeTracker->trackedTypes.end());
+ const auto it = m_trackedTypes->find(tracked);
+ Q_ASSERT(it != m_trackedTypes->end());
it->replacement = comparableType(conversion);
*it->clone = std::move(*QQmlJSScope::clone(conversion));
}
@@ -514,8 +454,8 @@ void QQmlJSTypeResolver::adjustTrackedType(
if (m_cloneMode == QQmlJSTypeResolver::DoNotCloneTypes)
return;
- const auto it = m_typeTracker->trackedTypes.find(tracked);
- Q_ASSERT(it != m_typeTracker->trackedTypes.end());
+ const auto it = m_trackedTypes->find(tracked);
+ Q_ASSERT(it != m_trackedTypes->end());
QQmlJSScope::Ptr mutableTracked = it->clone;
QQmlJSScope::ConstPtr result;
for (const QQmlJSScope::ConstPtr &type : conversions)
@@ -534,8 +474,8 @@ void QQmlJSTypeResolver::generalizeType(const QQmlJSScope::ConstPtr &type) const
if (m_cloneMode == QQmlJSTypeResolver::DoNotCloneTypes)
return;
- const auto it = m_typeTracker->trackedTypes.find(type);
- Q_ASSERT(it != m_typeTracker->trackedTypes.end());
+ const auto it = m_trackedTypes->find(type);
+ Q_ASSERT(it != m_trackedTypes->end());
*it->clone = std::move(*QQmlJSScope::clone(genericType(type)));
if (it->replacement)
it->replacement = genericType(it->replacement);
@@ -714,8 +654,9 @@ bool QQmlJSTypeResolver::canHoldUndefined(const QQmlJSRegisterContent &content)
return false;
}
-QQmlJSScope::ConstPtr QQmlJSTypeResolver::genericType(const QQmlJSScope::ConstPtr &type,
- ComponentIsGeneric allowComponent) const
+QQmlJSScope::ConstPtr QQmlJSTypeResolver::genericType(
+ const QQmlJSScope::ConstPtr &type,
+ ComponentIsGeneric allowComponent) const
{
if (type->isScript())
return m_jsValueType;
@@ -757,7 +698,10 @@ QQmlJSScope::ConstPtr QQmlJSTypeResolver::genericType(const QQmlJSScope::ConstPt
return m_jsValueType;
}
- if (isPrimitive(type) || equals(type, m_jsValueType) || equals(type, m_listPropertyType)
+ if (type->isListProperty())
+ return m_listPropertyType;
+
+ if (isPrimitive(type) || equals(type, m_jsValueType)
|| equals(type, m_urlType) || equals(type, m_dateTimeType)
|| equals(type, m_variantListType) || equals(type, m_varType)
|| equals(type, m_stringListType) || equals(type, m_emptyListType)
@@ -772,10 +716,16 @@ QQmlJSScope::ConstPtr QQmlJSTypeResolver::genericType(const QQmlJSScope::ConstPt
return m_realType;
if (type->accessSemantics() == QQmlJSScope::AccessSemantics::Sequence) {
- if (equals(type, m_listPropertyType))
- return type;
- if (const QQmlJSScope::ConstPtr valueType = type->valueType())
- return listType(genericType(valueType), UseQObjectList);
+ if (const QQmlJSScope::ConstPtr valueType = type->valueType()) {
+ switch (valueType->accessSemantics()) {
+ case QQmlJSScope::AccessSemantics::Value:
+ return genericType(valueType)->listType();
+ case QQmlJSScope::AccessSemantics::Reference:
+ return m_qObjectListType;
+ default:
+ break;
+ }
+ }
}
return m_varType;
@@ -868,9 +818,7 @@ QQmlJSRegisterContent QQmlJSTypeResolver::scopedType(const QQmlJSScope::ConstPtr
}
}
result = QQmlJSRegisterContent::create(
- prop.isList()
- ? listType(prop.type(), UseListReference)
- : storedType(prop.type()),
+ storedType(prop.type()),
prop, scopeContentVariant(mode, false), scope);
return true;
}
@@ -1062,9 +1010,7 @@ QQmlJSRegisterContent QQmlJSTypeResolver::memberType(const QQmlJSScope::ConstPtr
if (scope->hasOwnProperty(name)) {
const auto prop = scope->ownProperty(name);
result = QQmlJSRegisterContent::create(
- prop.isList()
- ? listType(prop.type(), UseListReference)
- : storedType(prop.type()),
+ storedType(prop.type()),
prop,
mode == QQmlJSScope::NotExtension
? QQmlJSRegisterContent::ObjectProperty
@@ -1156,16 +1102,8 @@ QQmlJSRegisterContent QQmlJSTypeResolver::memberType(const QQmlJSRegisterContent
// we might have an enum of the attaching type.
return memberEnumType(type.scopeType(), name);
}
- if (type.isProperty()) {
- const auto prop = type.property();
- if (prop.isList()) {
- const QQmlJSScope::ConstPtr propType = listType(prop.type(), UseListReference);
- if (name == u"length"_s)
- return lengthProperty(true, propType);
- return memberType(propType, name);
- }
- return memberType(prop.type(), name);
- }
+ if (type.isProperty())
+ return memberType(type.property().type(), name);
if (type.isEnumeration()) {
const auto enumeration = type.enumeration();
if (!type.enumMember().isEmpty() || !enumeration.hasKey(name))
@@ -1225,13 +1163,8 @@ QQmlJSRegisterContent QQmlJSTypeResolver::valueType(const QQmlJSRegisterContent
value = valueType(list.conversionResult());
} else if (list.isProperty()) {
const auto prop = list.property();
- if (prop.isList()) {
- scope = listType(prop.type(), UseListReference);
- value = prop.type();
- } else {
- scope = prop.type();
- value = valueType(scope);
- }
+ scope = prop.type();
+ value = valueType(scope);
}
if (value.isNull())
@@ -1268,12 +1201,8 @@ bool QQmlJSTypeResolver::registerContains(const QQmlJSRegisterContent &reg,
return equals(reg.type(), type);
if (reg.isConversion())
return equals(reg.conversionResult(), type);
- if (reg.isProperty()) {
- const auto prop = reg.property();
- return prop.isList()
- ? equals(type, listType(prop.type(), UseListReference))
- : equals(type, prop.type());
- }
+ if (reg.isProperty())
+ return equals(type, reg.property().type());
if (reg.isEnumeration())
return equals(type, reg.enumeration().type());
if (reg.isMethod())
@@ -1303,8 +1232,8 @@ QQmlJSScope::ConstPtr QQmlJSTypeResolver::storedType(const QQmlJSScope::ConstPtr
QQmlJSScope::ConstPtr QQmlJSTypeResolver::originalType(const QQmlJSScope::ConstPtr &type) const
{
- const auto it = m_typeTracker->trackedTypes.find(type);
- return it == m_typeTracker->trackedTypes.end() ? type : it->original;
+ const auto it = m_trackedTypes->find(type);
+ return it == m_trackedTypes->end() ? type : it->original;
}
/*!
@@ -1336,8 +1265,8 @@ QQmlJSRegisterContent QQmlJSTypeResolver::convert(
QQmlJSScope::ConstPtr QQmlJSTypeResolver::comparableType(const QQmlJSScope::ConstPtr &type) const
{
- const auto it = m_typeTracker->trackedTypes.constFind(type);
- if (it == m_typeTracker->trackedTypes.constEnd())
+ const auto it = m_trackedTypes->constFind(type);
+ if (it == m_trackedTypes->constEnd())
return type;
return it->replacement ? it->replacement : it->original;
}
diff --git a/src/qmlcompiler/qqmljstyperesolver_p.h b/src/qmlcompiler/qqmljstyperesolver_p.h
index b18937fa6e..993529464f 100644
--- a/src/qmlcompiler/qqmljstyperesolver_p.h
+++ b/src/qmlcompiler/qqmljstyperesolver_p.h
@@ -32,6 +32,7 @@ class Q_QMLCOMPILER_PRIVATE_EXPORT QQmlJSTypeResolver
public:
enum ParentMode { UseDocumentParent, UseParentProperty };
enum CloneMode { CloneTypes, DoNotCloneTypes };
+ enum ListMode { UseListProperty, UseQObjectList };
QQmlJSTypeResolver(QQmlJSImporter *importer);
@@ -59,6 +60,7 @@ public:
QQmlJSScope::ConstPtr metaObjectType() const { return m_metaObjectType; }
QQmlJSScope::ConstPtr functionType() const { return m_functionType; }
QQmlJSScope::ConstPtr jsGlobalObject() const { return m_jsGlobalObject; }
+ QQmlJSScope::ConstPtr qObjectListType() const { return m_qObjectListType; }
QQmlJSScope::ConstPtr scopeForLocation(const QV4::CompiledData::Location &location) const;
QQmlJSScope::ConstPtr scopeForId(
@@ -69,8 +71,6 @@ public:
return m_imports.hasType(name) && !m_imports.type(name).scope;
}
- enum ListMode { UseListReference, UseQObjectList };
- QQmlJSScope::ConstPtr listType(const QQmlJSScope::ConstPtr &elementType, ListMode mode) const;
QQmlJSScope::ConstPtr typeForName(const QString &name) const
{
return m_imports.type(name).scope;
@@ -169,7 +169,6 @@ protected:
bool canPrimitivelyConvertFromTo(
const QQmlJSScope::ConstPtr &from, const QQmlJSScope::ConstPtr &to) const;
QQmlJSRegisterContent lengthProperty(bool isWritable, const QQmlJSScope::ConstPtr &scope) const;
- void trackListPropertyType(const QQmlJSScope::ConstPtr &trackedListElementType) const;
QQmlJSRegisterContent transformed(
const QQmlJSRegisterContent &origin,
QQmlJSScope::ConstPtr (QQmlJSTypeResolver::*op)(const QQmlJSScope::ConstPtr &) const) const;
@@ -199,6 +198,7 @@ protected:
QQmlJSScope::ConstPtr m_jsValueType;
QQmlJSScope::ConstPtr m_jsPrimitiveType;
QQmlJSScope::ConstPtr m_listPropertyType;
+ QQmlJSScope::ConstPtr m_qObjectListType;
QQmlJSScope::ConstPtr m_metaObjectType;
QQmlJSScope::ConstPtr m_functionType;
QQmlJSScope::ConstPtr m_jsGlobalObject;
@@ -225,13 +225,7 @@ protected:
QQmlJSScope::Ptr clone;
};
- struct TypeTracker
- {
- QHash<QQmlJSScope::ConstPtr, QQmlJSScope::Ptr> listTypes;
- QHash<QQmlJSScope::ConstPtr, TrackedType> trackedTypes;
- };
-
- std::unique_ptr<TypeTracker> m_typeTracker;
+ std::unique_ptr<QHash<QQmlJSScope::ConstPtr, TrackedType>> m_trackedTypes;
};
QT_END_NAMESPACE