aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2022-11-18 11:40:10 +0100
committerUlf Hermann <ulf.hermann@qt.io>2022-11-24 13:07:04 +0100
commit39aba03d4c4bf80a54dbf5b6735b81854dd99220 (patch)
treeaafa2b2ecb0f2b1e678a602fa08c726088876e74
parent0fbb39435e04e02ecff4a95983be102d57d29e94 (diff)
QmlCompiler: Fix comparison of null and undefined
Those are not stored. If we compare null to null or undefined to undefined, we do not have to generate a comparison at all. the result is statically known. Fixes: QTBUG-108634 Change-Id: I6a5323c2e0c023838609aec90d7ecc15b885dc08 Reviewed-by: Sami Shalayel <sami.shalayel@qt.io> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> (cherry picked from commit bce216d5c086a5aa8f88d13933eeccebca316359)
-rw-r--r--src/qmlcompiler/qqmljscodegenerator.cpp32
-rw-r--r--tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt1
-rw-r--r--tests/auto/qml/qmlcppcodegen/data/nullComparison.qml26
-rw-r--r--tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp16
4 files changed, 64 insertions, 11 deletions
diff --git a/src/qmlcompiler/qqmljscodegenerator.cpp b/src/qmlcompiler/qqmljscodegenerator.cpp
index be0a937fc0..04926ca519 100644
--- a/src/qmlcompiler/qqmljscodegenerator.cpp
+++ b/src/qmlcompiler/qqmljscodegenerator.cpp
@@ -35,6 +35,15 @@ using namespace Qt::StringLiterals;
m_body += u"// "_s + QStringLiteral(#function) + u'\n'; \
}
+
+static bool isTypeStorable(const QQmlJSTypeResolver *resolver, const QQmlJSScope::ConstPtr &type)
+{
+ return !type.isNull()
+ && !resolver->equals(type, resolver->nullType())
+ && !resolver->equals(type, resolver->emptyListType())
+ && !resolver->equals(type, resolver->voidType());
+}
+
QString QQmlJSCodeGenerator::castTargetName(const QQmlJSScope::ConstPtr &type) const
{
return type->augmentedInternalName();
@@ -75,14 +84,6 @@ QString QQmlJSCodeGenerator::metaObject(const QQmlJSScope::ConstPtr &objectType)
return QString();
}
-static bool isTypeStorable(const QQmlJSTypeResolver *resolver, const QQmlJSScope::ConstPtr &type)
-{
- return !type.isNull()
- && !resolver->equals(type, resolver->nullType())
- && !resolver->equals(type, resolver->emptyListType())
- && !resolver->equals(type, resolver->voidType());
-}
-
QQmlJSAotFunction QQmlJSCodeGenerator::run(
const Function *function, const InstructionAnnotations *annotations,
QQmlJS::DiagnosticMessage *error)
@@ -2315,9 +2316,18 @@ void QQmlJSCodeGenerator::generateEqualityOperation(int lhs, const QString &func
const auto primitive = m_typeResolver->jsPrimitiveType();
if (m_typeResolver->equals(lhsType, rhsType) && !m_typeResolver->equals(lhsType, primitive)) {
- m_body += conversion(m_typeResolver->boolType(), m_state.accumulatorOut().storedType(),
- registerVariable(lhs) + (invert ? u" != "_s : u" == "_s)
- + m_state.accumulatorVariableIn);
+ if (isTypeStorable(m_typeResolver, lhsType)) {
+ m_body += conversion(m_typeResolver->boolType(), m_state.accumulatorOut().storedType(),
+ registerVariable(lhs) + (invert ? u" != "_s : u" == "_s)
+ + m_state.accumulatorVariableIn);
+ } else if (m_typeResolver->equals(lhsType, m_typeResolver->emptyListType())) {
+ // We cannot compare two empty lists, because we don't know whether it's
+ // the same instance or not. "[] === []" is false, but "var a = []; a === a" is true;
+ reject(u"comparison of two empty lists"_s);
+ } else {
+ // null === null and undefined === undefined
+ m_body += invert ? u"false"_s : u"true"_s;
+ }
} else {
m_body += conversion(
m_typeResolver->boolType(), m_state.accumulatorOut().storedType(),
diff --git a/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt b/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt
index 8d062c5c35..2cd63be039 100644
--- a/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt
+++ b/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt
@@ -117,6 +117,7 @@ set(qml_files
notEqualsInt.qml
notNotString.qml
nullAccess.qml
+ nullComparison.qml
objectInVar.qml
outOfBounds.qml
overriddenMember.qml
diff --git a/tests/auto/qml/qmlcppcodegen/data/nullComparison.qml b/tests/auto/qml/qmlcppcodegen/data/nullComparison.qml
new file mode 100644
index 0000000000..1f9af7169b
--- /dev/null
+++ b/tests/auto/qml/qmlcppcodegen/data/nullComparison.qml
@@ -0,0 +1,26 @@
+pragma Strict
+import QtQml
+
+QtObject {
+ property int v: 1
+ property int w: 1
+ property int x: 1
+ property int y: 1
+ Component.onCompleted: {
+ var g = null;
+ if (g !== null) {
+ v = 2;
+ }
+ if (g === null) {
+ w = 3;
+ }
+
+ var h = undefined;
+ if (h !== undefined) {
+ x = 4;
+ }
+ if (h === undefined) {
+ y = 5;
+ }
+ }
+}
diff --git a/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp b/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp
index 74510d6097..063fede02e 100644
--- a/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp
+++ b/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp
@@ -134,6 +134,7 @@ private slots:
void notNotString();
void inaccessibleProperty();
void typePropagationLoop();
+ void nullComparison();
};
void tst_QmlCppCodegen::simpleBinding()
@@ -2462,6 +2463,21 @@ void tst_QmlCppCodegen::typePropagationLoop()
QCOMPARE(o->property("j").toInt(), 3);
}
+void tst_QmlCppCodegen::nullComparison()
+{
+ QQmlEngine engine;
+
+ QQmlComponent c(&engine, QUrl(u"qrc:/TestTypes/nullComparison.qml"_s));
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
+ QScopedPointer<QObject> o(c.create());
+ QVERIFY(!o.isNull());
+
+ QCOMPARE(o->property("v").toInt(), 1);
+ QCOMPARE(o->property("w").toInt(), 3);
+ QCOMPARE(o->property("x").toInt(), 1);
+ QCOMPARE(o->property("y").toInt(), 5);
+};
+
QTEST_MAIN(tst_QmlCppCodegen)
#include "tst_qmlcppcodegen.moc"