QmlCompiler: Don't crash on CallWithSpread

When preparing for such a call, the byte code loads an "empty" constant.
This has to be represented in the type system so that we don't hit the
assert at the end of the instruction.

Pick-to: 6.4 6.2
Task-number: QTBUG-108441
Change-Id: I66220bfae3d3a4b8e9600d84d4cfc43ac858b77e
Reviewed-by: Sami Shalayel <sami.shalayel@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
Ulf Hermann 2022-11-15 16:34:27 +01:00
parent 8f827de1a1
commit df01095a66
5 changed files with 30 additions and 0 deletions

View File

@ -42,6 +42,10 @@ QQmlJSTypeResolver::QQmlJSTypeResolver(QQmlJSImporter *importer)
m_listPropertyType = builtinTypes.type(u"QQmlListProperty<QObject>"_s).scope;
m_qObjectListType = builtinTypes.type(u"QObjectList"_s).scope;
QQmlJSScope::Ptr emptyType = QQmlJSScope::create();
emptyType->setAccessSemantics(QQmlJSScope::AccessSemantics::None);
m_emptyType = emptyType;
QQmlJSScope::Ptr emptyListType = QQmlJSScope::create();
emptyListType->setInternalName(u"void*"_s);
emptyListType->setAccessSemantics(QQmlJSScope::AccessSemantics::Sequence);
@ -151,6 +155,9 @@ QQmlJSScope::ConstPtr QQmlJSTypeResolver::typeForConst(QV4::ReturnedValue rv) co
if (value.isNull())
return nullType();
if (value.isEmpty())
return emptyType();
return {};
}

View File

@ -40,6 +40,7 @@ public:
void init(QQmlJSImportVisitor *visitor, QQmlJS::AST::Node *program);
QQmlJSScope::ConstPtr voidType() const { return m_voidType; }
QQmlJSScope::ConstPtr emptyType() const { return m_emptyType; }
QQmlJSScope::ConstPtr emptyListType() const { return m_emptyListType; }
QQmlJSScope::ConstPtr nullType() const { return m_nullType; }
QQmlJSScope::ConstPtr realType() const { return m_realType; }
@ -180,6 +181,7 @@ protected:
QQmlJSScope::ConstPtr m_voidType;
QQmlJSScope::ConstPtr m_emptyListType;
QQmlJSScope::ConstPtr m_emptyType;
QQmlJSScope::ConstPtr m_nullType;
QQmlJSScope::ConstPtr m_numberPrototype;
QQmlJSScope::ConstPtr m_arrayType;

View File

@ -54,6 +54,7 @@ set(qml_files
blockComments.qml
boundComponents.qml
callContextPropertyLookupResult.qml
callWithSpread.qml
childobject.qml
colorAsVariant.qml
colorString.qml

View File

@ -0,0 +1,9 @@
import QtQml
QtObject {
Component.onCompleted: {
let f = console.error;
const data = [f, ["That is great!"]]
data[0](...data[1]);
}
}

View File

@ -144,6 +144,7 @@ private slots:
void listAsArgument();
void letAndConst();
void signalIndexMismatch();
void callWithSpread();
};
void tst_QmlCppCodegen::initTestCase()
@ -2791,6 +2792,16 @@ void tst_QmlCppCodegen::signalIndexMismatch()
QCOMPARE(visualIndexBeforeMoveList, QList<QVariant>({ 0, 1, 2 }));
QCOMPARE(visualIndexAfterMoveList, QList<QVariant>({ 0, 1, 2 }));
}
void tst_QmlCppCodegen::callWithSpread()
{
QQmlEngine engine;
QQmlComponent c(&engine, QUrl(u"qrc:/qt/qml/TestTypes/callWithSpread.qml"_s));
QVERIFY2(c.isReady(), qPrintable(c.errorString()));
QTest::ignoreMessage(QtCriticalMsg, "That is great!");
QScopedPointer<QObject> o(c.create());
QVERIFY(!o.isNull());
};
QTEST_MAIN(tst_QmlCppCodegen)