diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/imports/builtins/builtins.qmltypes | 14 | ||||
| -rw-r--r-- | src/qmlcompiler/qqmljscodegenerator.cpp | 24 | ||||
| -rw-r--r-- | src/qmlcompiler/qqmljscompiler.cpp | 1 | ||||
| -rw-r--r-- | src/qmlcompiler/qqmljsfunctioninitializer.cpp | 11 | ||||
| -rw-r--r-- | src/qmlcompiler/qqmljsimporter.cpp | 5 | ||||
| -rw-r--r-- | src/qmlcompiler/qqmljsimportvisitor.cpp | 6 | ||||
| -rw-r--r-- | src/qmlcompiler/qqmljsregistercontent.cpp | 8 | ||||
| -rw-r--r-- | src/qmlcompiler/qqmljsscope.cpp | 86 | ||||
| -rw-r--r-- | src/qmlcompiler/qqmljsscope_p.h | 9 | ||||
| -rw-r--r-- | src/qmlcompiler/qqmljsstoragegeneralizer.cpp | 6 | ||||
| -rw-r--r-- | src/qmlcompiler/qqmljstyperesolver.cpp | 179 | ||||
| -rw-r--r-- | src/qmlcompiler/qqmljstyperesolver_p.h | 14 |
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> ®isters) { - 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 ®, 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 |
