aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2024-02-16 15:08:20 +0100
committerUlf Hermann <ulf.hermann@qt.io>2024-02-23 14:17:58 +0100
commit0638f66267131254d543702132935a865c8ea835 (patch)
treecb9049087bed8c8c010599dd5d4f254a361b1447
parent71e6735e229dfba70ffc1cfbd396f886617b24bd (diff)
QmlCompiler: Fix conditions around as casts
We can only generate an as-cast from an optional value type if we know that the optional type is actually the requested one. Otherwise we have to reject for now. We might add more logic here in a further iteration, and process more complicated type assertions. However, we should pick such logic back to 6.6. Amends commit 05f56d7c78754855c643470ad4e8dfd35c96f927. Change-Id: I37fc1b6018bfb0663e5ce4fd80084c7d13c6d3e3 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> Reviewed-by: Olivier De Cannière <olivier.decanniere@qt.io> (cherry picked from commit e2611e8ee948b32a627277bb9783ce8f35cc2d69) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> (cherry picked from commit 32ab9996e28284f85dafc756ce868327cac50873)
-rw-r--r--src/qmlcompiler/qqmljscodegenerator.cpp49
-rw-r--r--src/qmlcompiler/qqmljstyperesolver.cpp24
-rw-r--r--src/qmlcompiler/qqmljstyperesolver_p.h4
-rw-r--r--tests/auto/qml/qmlcppcodegen/data/valueTypeCast.qml18
-rw-r--r--tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp6
5 files changed, 82 insertions, 19 deletions
diff --git a/src/qmlcompiler/qqmljscodegenerator.cpp b/src/qmlcompiler/qqmljscodegenerator.cpp
index be83414172..383561f6cd 100644
--- a/src/qmlcompiler/qqmljscodegenerator.cpp
+++ b/src/qmlcompiler/qqmljscodegenerator.cpp
@@ -2482,17 +2482,27 @@ 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()
+ ? m_typeResolver->containedType(originalContent)
+ : m_typeResolver->extractNonVoidFromOptionalType(originalContent);
- const QQmlJSScope::ConstPtr contained = m_typeResolver->containedType(originalContent);
+ if (!target) {
+ reject(u"type assertion to unknown type"_s);
+ return;
+ }
+
+ const bool isTrivial = m_typeResolver->inherits(
+ m_typeResolver->originalContainedType(inputContent), target);
+
+ m_body += m_state.accumulatorVariableOut + u" = "_s;
- if (contained->isReferenceType()) {
- const QQmlJSScope::ConstPtr genericContained = m_typeResolver->genericType(contained);
+ if (!isTrivial && target->isReferenceType()) {
+ const QQmlJSScope::ConstPtr genericContained = m_typeResolver->genericType(target);
const QString inputConversion = inputContent.storedType()->isReferenceType()
? input
: convertStored(inputContent.storedType(), genericContained, input);
- m_body += m_state.accumulatorVariableOut + u" = "_s;
- if (contained->isComposite() && m_typeResolver->equals(
+ if (target->isComposite() && m_typeResolver->equals(
m_state.accumulatorIn().storedType(), m_typeResolver->metaObjectType())) {
m_body += conversion(
genericContained, outputContent,
@@ -2500,33 +2510,36 @@ void QQmlJSCodeGenerator::generate_As(int lhs)
} else {
m_body += conversion(
genericContained, outputContent,
- u'(' + metaObject(contained) + u")->cast("_s + inputConversion + u')');
+ u'(' + metaObject(target) + u")->cast("_s + inputConversion + u')');
}
m_body += u";\n"_s;
return;
- } else if (m_typeResolver->equals(inputContent.storedType(), m_typeResolver->varType())) {
- if (originalContent.isConversion()) {
- const auto origins = originalContent.conversionOrigins();
- Q_ASSERT(origins.size() == 2);
+ }
- const auto target = m_typeResolver->equals(origins[0], m_typeResolver->voidType())
- ? origins[1]
- : origins[0];
+ if (m_typeResolver->registerIsStoredIn(inputContent, m_typeResolver->varType())
+ || m_typeResolver->registerIsStoredIn(inputContent, m_typeResolver->jsPrimitiveType())) {
- Q_ASSERT(!m_typeResolver->equals(target, m_typeResolver->voidType()));
+ const auto source = m_typeResolver->extractNonVoidFromOptionalType(
+ m_typeResolver->original(inputContent));
- m_body += m_state.accumulatorVariableOut + u" = "_s;
+ 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());
+ + u" : " + conversion(
+ m_typeResolver->globalType(m_typeResolver->voidType()),
+ outputContent, QString());
m_body += u";\n"_s;
return;
}
}
- reject(u"unsupported type assertion"_s);
+ if (isTrivial) {
+ // No actual conversion necessary. The 'as' is a no-op
+ m_body += conversion(inputContent, m_state.accumulatorOut(), input) + u";\n"_s;
+ return;
+ }
+ reject(u"non-trivial value type assertion"_s);
}
void QQmlJSCodeGenerator::generate_UNot()
diff --git a/src/qmlcompiler/qqmljstyperesolver.cpp b/src/qmlcompiler/qqmljstyperesolver.cpp
index 95f944a438..22ba23be21 100644
--- a/src/qmlcompiler/qqmljstyperesolver.cpp
+++ b/src/qmlcompiler/qqmljstyperesolver.cpp
@@ -799,6 +799,30 @@ bool QQmlJSTypeResolver::canHoldUndefined(const QQmlJSRegisterContent &content)
return false;
}
+bool QQmlJSTypeResolver::isOptionalType(const QQmlJSRegisterContent &content) const
+{
+ if (!content.isConversion())
+ return false;
+
+ const auto origins = content.conversionOrigins();
+ if (origins.length() != 2)
+ return false;
+
+ return equals(origins[0], m_voidType) || equals(origins[1], m_voidType);
+}
+
+QQmlJSScope::ConstPtr QQmlJSTypeResolver::extractNonVoidFromOptionalType(
+ const QQmlJSRegisterContent &content) const
+{
+ if (!isOptionalType(content))
+ return QQmlJSScope::ConstPtr();
+
+ const auto origins = content.conversionOrigins();
+ const QQmlJSScope::ConstPtr result = equals(origins[0], m_voidType) ? origins[1] : origins[0];
+ Q_ASSERT(!equals(result, m_voidType));
+ return result;
+}
+
QQmlJSScope::ConstPtr QQmlJSTypeResolver::genericType(
const QQmlJSScope::ConstPtr &type,
ComponentIsGeneric allowComponent) const
diff --git a/src/qmlcompiler/qqmljstyperesolver_p.h b/src/qmlcompiler/qqmljstyperesolver_p.h
index 7ef6b7b295..6196963e42 100644
--- a/src/qmlcompiler/qqmljstyperesolver_p.h
+++ b/src/qmlcompiler/qqmljstyperesolver_p.h
@@ -173,6 +173,10 @@ public:
const QQmlJSScope::ConstPtr &b) const;
bool canHoldUndefined(const QQmlJSRegisterContent &content) const;
+ bool isOptionalType(const QQmlJSRegisterContent &content) const;
+ QQmlJSScope::ConstPtr extractNonVoidFromOptionalType(
+ const QQmlJSRegisterContent &content) const;
+
bool isNumeric(const QQmlJSScope::ConstPtr &type) const;
bool isIntegral(const QQmlJSScope::ConstPtr &type) const;
bool isSignedInteger(const QQmlJSScope::ConstPtr &type) const;
diff --git a/tests/auto/qml/qmlcppcodegen/data/valueTypeCast.qml b/tests/auto/qml/qmlcppcodegen/data/valueTypeCast.qml
index d1c9198cbd..708c833477 100644
--- a/tests/auto/qml/qmlcppcodegen/data/valueTypeCast.qml
+++ b/tests/auto/qml/qmlcppcodegen/data/valueTypeCast.qml
@@ -1,9 +1,25 @@
-pragma Strict
pragma ValueTypeBehavior: Addressable
import QtQml
QtObject {
+ id: root
property rect r: Qt.rect(10, 20, 3, 4)
property var v: r
property real x: (v as rect).x
+
+ function f(input: bool) : var {
+ if (input)
+ return 0
+ return Qt.point(2, 2)
+ }
+
+ property var vv: Qt.point(5, 5)
+ property var uu: undefined
+
+ property int tv3: (root.vv as point)?.x
+ property var tv4: (root.uu as rect)?.x
+ property int tc3: (root?.vv as point)?.y
+ property var tc6: (root?.uu as rect)?.height
+ property var tc7: (f(true) as point)?.x
+ property var tc8: (f(false) as point)?.x
}
diff --git a/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp b/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp
index ad89fb10c5..cc8e6a81c5 100644
--- a/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp
+++ b/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp
@@ -4260,6 +4260,12 @@ void tst_QmlCppCodegen::valueTypeBehavior()
// If the binding throws an exception, the value doesn't change.
QCOMPARE(o->property("x"), 10);
+
+ QCOMPARE(o->property("tv3"), 5);
+ QCOMPARE(o->property("tc3"), 5);
+ QCOMPARE(o->property("tc6"), QVariant());
+ QCOMPARE(o->property("tc7"), QVariant());
+ QCOMPARE(o->property("tc8"), 2);
}
}