QmlCompiler: Fix conversion from/to void

We can convert everything to void, but we can only convert from void if
the result is either void or the invalid type.

Pick-to: 6.6
Fixes: QTBUG-116088
Change-Id: I532055405865c5b1581f79cc5d76c253bce6138d
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
Ulf Hermann 2023-08-21 15:52:39 +02:00
parent d554714a6c
commit 8d9dfd3347
7 changed files with 42 additions and 7 deletions

View File

@ -3338,10 +3338,14 @@ QString QQmlJSCodeGenerator::convertStored(
return u"std::numeric_limits<double>::quiet_NaN()"_s;
if (m_typeResolver->equals(to, m_typeResolver->stringType()))
return QQmlJSUtils::toLiteral(u"undefined"_s);
if (m_typeResolver->equals(to, m_typeResolver->varType()))
return u"QVariant()"_s;
if (m_typeResolver->equals(to, m_typeResolver->jsValueType()))
return u"QJSValue();"_s;
if (m_typeResolver->equals(to, m_typeResolver->jsPrimitiveType()))
return u"QJSPrimitiveValue()"_s;
if (m_typeResolver->equals(from, to))
return QString();
// Anything else is just the default constructed type.
return to->augmentedInternalName() + u"()"_s;
}
if (m_typeResolver->equals(from, m_typeResolver->nullType())) {

View File

@ -83,9 +83,10 @@ void QQmlJSTypePropagator::generate_Ret()
if (m_function->isSignalHandler) {
// Signal handlers cannot return anything.
} else if (!m_returnType.isValid() && m_state.accumulatorIn().isValid()
&& !m_typeResolver->registerContains(
m_state.accumulatorIn(), m_typeResolver->voidType())) {
} else if (m_typeResolver->registerContains(
m_state.accumulatorIn(), m_typeResolver->voidType())) {
// You can always return undefined.
} else if (!m_returnType.isValid() && m_state.accumulatorIn().isValid()) {
setError(u"function without return type annotation returns %1"_s
.arg(m_state.accumulatorIn().descriptiveName()));

View File

@ -1192,11 +1192,11 @@ bool QQmlJSTypeResolver::canPrimitivelyConvertFromTo(
return true;
}
if (equals(from, m_voidType) || equals(to, m_voidType))
if (equals(to, m_voidType))
return true;
if (to.isNull())
return false;
return equals(from, m_voidType);
const auto types = { m_dateTimeType, m_dateType, m_timeType, m_stringType };
for (const auto &originType : types) {

View File

@ -245,6 +245,7 @@ set(qml_files
variantReturn.qml
variantlist.qml
versionmismatch.qml
voidConversion.qml
voidfunction.qml
dummy_imports.qml
)

View File

@ -0,0 +1,10 @@
import QtQml
QtObject {
id: item
property point p: Qt.point(20, 10)
Component.onCompleted: {
item.p = undefined
}
}

View File

@ -206,6 +206,7 @@ private slots:
void variantMapLookup();
void variantReturn();
void variantlist();
void voidConversion();
void voidFunction();
};
@ -4189,6 +4190,23 @@ void tst_QmlCppCodegen::variantlist()
QCOMPARE(things[1].toInt(), 30);
}
void tst_QmlCppCodegen::voidConversion()
{
QQmlEngine engine;
const QUrl url(u"qrc:/qt/qml/TestTypes/voidConversion.qml"_s);
QQmlComponent c(&engine, url);
QVERIFY2(c.isReady(), qPrintable(c.errorString()));
QTest::ignoreMessage(
QtWarningMsg,
qPrintable(url.toString() + u":8: Error: Cannot assign [undefined] to QPointF"_s));
QScopedPointer<QObject> o(c.create());
QVERIFY(o);
QCOMPARE(o->property("p"), QPointF(20, 10));
}
void tst_QmlCppCodegen::voidFunction()
{
QQmlEngine engine;

View File

@ -5,5 +5,6 @@ Item {
anchors.horizontalCenter: undefined
anchors.verticalCenter: undefined
anchors.baseline: undefined
Component.onCompleted: anchors.bottom = undefined
}
}