Skip to content

Commit f839171

Browse files
committed
QmlCompiler: Allow creation of actual QVariantMaps from object literals
There are places where we need this: a, If the method in question actually takes a QVariantMap as argument. b, If the resulting value can be shadowed. In that case we expect a QVariant. The engine has to internally convert to the expected type then. Change-Id: Ic5b3faab4578d64ca757de644fe69660fd70e52a Reviewed-by: Fabian Kosmale <[email protected]> Reviewed-by: Sami Shalayel <[email protected]> Reviewed-by: Qt CI Bot <[email protected]>
1 parent 5551254 commit f839171

File tree

7 files changed

+94
-9
lines changed

7 files changed

+94
-9
lines changed

src/qmlcompiler/qqmljsbasicblocks.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -648,13 +648,19 @@ void QQmlJSBasicBlocks::adjustTypes()
648648
const InstructionAnnotation &annotation = m_annotations[object.instructionOffset];
649649

650650
Q_ASSERT(it->trackedTypes.size() == 1);
651-
Q_ASSERT(it->trackedTypes[0] == m_typeResolver->containedType(annotation.changedRegister));
651+
QQmlJSScope::ConstPtr resultType = it->trackedTypes[0];
652+
653+
Q_ASSERT(resultType == m_typeResolver->containedType(annotation.changedRegister));
652654
Q_ASSERT(!annotation.readRegisters.isEmpty());
653655

654-
if (!m_typeResolver->adjustTrackedType(it->trackedTypes[0], it->typeReaders.values()))
655-
setError(adjustErrorMessage(it->trackedTypes[0], it->typeReaders.values()));
656+
if (!m_typeResolver->adjustTrackedType(resultType, it->typeReaders.values()))
657+
setError(adjustErrorMessage(resultType, it->typeReaders.values()));
656658

657-
QQmlJSScope::ConstPtr resultType = it->trackedTypes[0];
659+
if (m_typeResolver->equals(resultType, m_typeResolver->varType())
660+
|| m_typeResolver->equals(resultType, m_typeResolver->variantMapType())) {
661+
// It's all variant anyway
662+
return;
663+
}
658664

659665
const int classSize = m_jsUnitGenerator->jsClassSize(object.internalClassId);
660666
Q_ASSERT(object.argc >= classSize);

src/qmlcompiler/qqmljscodegenerator.cpp

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2376,6 +2376,45 @@ void QQmlJSCodeGenerator::generate_DefineObjectLiteral(int internalClassId, int
23762376

23772377
const QQmlJSScope::ConstPtr contained = m_typeResolver->containedType(m_state.accumulatorOut());
23782378

2379+
const int classSize = m_jsUnitGenerator->jsClassSize(internalClassId);
2380+
Q_ASSERT(argc >= classSize);
2381+
2382+
if (m_typeResolver->equals(contained, m_typeResolver->varType())
2383+
|| m_typeResolver->equals(contained, m_typeResolver->variantMapType())) {
2384+
2385+
m_body += m_state.accumulatorVariableOut + u" = QVariantMap {\n";
2386+
const QQmlJSScope::ConstPtr propType = m_typeResolver->varType();
2387+
for (int i = 0; i < classSize; ++i) {
2388+
m_body += u"{ "_s
2389+
+ QQmlJSUtils::toLiteral(m_jsUnitGenerator->jsClassMember(internalClassId, i))
2390+
+ u", "_s;
2391+
const int currentArg = args + i;
2392+
const QQmlJSScope::ConstPtr argType = registerType(currentArg).storedType();
2393+
const QString consumedArg = consumedRegisterVariable(currentArg);
2394+
m_body += convertStored(argType, propType, consumedArg) + u" },\n";
2395+
}
2396+
2397+
for (int i = classSize; i < argc; i += 3) {
2398+
const int nameArg = argc + i + 1;
2399+
m_body += u"{ "_s
2400+
+ conversion(
2401+
registerType(nameArg),
2402+
m_typeResolver->globalType(m_typeResolver->stringType()),
2403+
consumedRegisterVariable(nameArg))
2404+
+ u", "_s;
2405+
2406+
const int valueArg = argc + i + 2;
2407+
m_body += convertStored(
2408+
registerType(valueArg).storedType(),
2409+
propType,
2410+
consumedRegisterVariable(valueArg))
2411+
+ u" },\n";
2412+
}
2413+
2414+
m_body += u"};\n";
2415+
return;
2416+
}
2417+
23792418
m_body += m_state.accumulatorVariableOut + u" = "_s + stored->augmentedInternalName();
23802419
const bool isVariantOrPrimitive = m_typeResolver->equals(stored, m_typeResolver->varType())
23812420
|| m_typeResolver->equals(stored, m_typeResolver->jsPrimitiveType());
@@ -2390,6 +2429,9 @@ void QQmlJSCodeGenerator::generate_DefineObjectLiteral(int internalClassId, int
23902429
}
23912430
m_body += u";\n";
23922431

2432+
if (argc == 0)
2433+
return;
2434+
23932435
bool isExtension = false;
23942436
if (!m_typeResolver->canPopulate(contained, m_typeResolver->variantMapType(), &isExtension)) {
23952437
reject(u"storing an object literal in a non-structured value type"_s);
@@ -2399,11 +2441,6 @@ void QQmlJSCodeGenerator::generate_DefineObjectLiteral(int internalClassId, int
23992441
? contained->extensionType().scope
24002442
: contained;
24012443

2402-
const int classSize = m_jsUnitGenerator->jsClassSize(internalClassId);
2403-
Q_ASSERT(argc >= classSize);
2404-
if (argc == 0)
2405-
return;
2406-
24072444
m_body += u"{\n";
24082445
m_body += u" const QMetaObject *meta = ";
24092446
if (!isExtension && isVariantOrPrimitive)

src/qmlcompiler/qqmljstypepropagator.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1979,6 +1979,8 @@ void QQmlJSTypePropagator::generate_DefineObjectLiteral(int internalClassId, int
19791979
for (int i = classSize; i < argc; i += 3) {
19801980
// layout for remaining members is:
19811981
// 0: ObjectLiteralArgument - Value|Method|Getter|Setter
1982+
// We cannot do anything useful with this. Any code that would call a getter/setter/method
1983+
// could not be compiled to C++. Ignore it.
19821984

19831985
// 1: name of argument
19841986
addReadRegister(
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import QtQml
2+
3+
QtObject {
4+
property rect r
5+
}

tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ set(cpp_sources
3030
set(qml_files
3131
AccessModelMethodsFromOutside.qml
3232
ArraySequenceLengthInterop.qml
33+
B.qml
3334
BadType.qml
3435
BaseMember.qml
3536
BindingExpression.qml
@@ -241,6 +242,7 @@ set(qml_files
241242
valueTypeLists.qml
242243
valueTypeProperty.qml
243244
valueTypeReference.qml
245+
variantMap.qml
244246
variantMapLookup.qml
245247
variantReturn.qml
246248
variantlist.qml
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
pragma Strict
2+
import QtQml
3+
4+
QtObject {
5+
property Component shadowable: QtObject {}
6+
property B b: B { id: theB }
7+
property rect r: theB.r
8+
9+
property Component c: Component {
10+
id: unshadowable
11+
QtObject {}
12+
}
13+
14+
objectName: {
15+
return shadowable.createObject(this, {objectName: "a"}).objectName
16+
+ " " + unshadowable.createObject(this, {objectName: "b"}).objectName
17+
}
18+
19+
Component.onCompleted: b.r = { x: 12, y: 13, width: 14, height: 15 }
20+
}

tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ private slots:
206206
void variantMapLookup();
207207
void variantReturn();
208208
void variantlist();
209+
void variantMap();
209210
void voidConversion();
210211
void voidFunction();
211212
void writeBack();
@@ -4208,6 +4209,18 @@ void tst_QmlCppCodegen::variantlist()
42084209
QCOMPARE(things[1].toInt(), 30);
42094210
}
42104211

4212+
void tst_QmlCppCodegen::variantMap()
4213+
{
4214+
QQmlEngine engine;
4215+
QQmlComponent c(&engine, QUrl(u"qrc:/qt/qml/TestTypes/variantMap.qml"_s));
4216+
QVERIFY2(c.isReady(), qPrintable(c.errorString()));
4217+
QScopedPointer<QObject> o(c.create());
4218+
QVERIFY(o);
4219+
4220+
QCOMPARE(o->objectName(), "a b"_L1);
4221+
QCOMPARE(o->property("r"), QVariant::fromValue(QRectF(12, 13, 14, 15)));
4222+
}
4223+
42114224
void tst_QmlCppCodegen::voidConversion()
42124225
{
42134226
QQmlEngine engine;

0 commit comments

Comments
 (0)