pop.type = prop->type;
pop.bindingSkipList = 0;
output->addInstruction(pop);
+
+ genPropertyAssignment(prop, obj);
}
void QQmlCompiler::genComponent(QQmlScript::Object *obj)
if (prop->type >= 0 && enginePrivate->valueTypes[prop->type]) {
if (!prop->values.isEmpty()) {
- if (prop->values.first()->location < prop->value->location) {
- COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
- } else {
- COMPILE_EXCEPTION(prop->values.first(), tr( "Property has already been assigned a value"));
+ // Only error if we are assigning values, and not e.g. a property interceptor
+ for (Property *dotProp = prop->value->properties.first(); dotProp; dotProp = prop->value->properties.next(dotProp)) {
+ if (!dotProp->values.isEmpty()) {
+ if (prop->values.first()->location < prop->value->location) {
+ COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value"));
+ } else {
+ COMPILE_EXCEPTION(prop->values.first(), tr( "Property has already been assigned a value"));
+ }
+ }
}
}
COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
}
-
if (prop->isAlias) {
for (Property *vtProp = prop->value->properties.first(); vtProp; vtProp = prop->value->properties.next(vtProp)) {
vtProp->isAlias = true;
COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type],
prop->value, obj, ctxt.incr()));
+
+ // When building a value type where sub components are declared, this
+ // code path is followed from buildProperty, even if there is a previous
+ // assignment to the value type as a whole. Therefore we need to look
+ // for (and build) assignments to the entire value type before looking
+ // for any onValue assignments.
+ for (Value *v = prop->values.first(); v; v = Property::ValueList::next(v)) {
+ if (v->object) {
+ COMPILE_EXCEPTION(v->object, tr("Objects cannot be assigned to value types"));
+ }
+ COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt));
+ }
+
+ for (Value *v = prop->onValues.first(); v; v = Property::ValueList::next(v)) {
+ Q_ASSERT(v->object);
+ COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt));
+ }
+
obj->addValueTypeProperty(prop);
+
} else {
COMPILE_EXCEPTION(prop, tr("Invalid grouped property access"));
}
Instruction::StoreV4Binding store;
store.value = js.compiledIndex;
+ store.fallbackValue = js.sharedIndex;
store.context = js.bindingContext.stack;
store.owner = js.bindingContext.owner;
store.isAlias = prop->isAlias;
store.line = binding->location.start.line;
store.column = binding->location.start.column;
output->addInstruction(store);
+
+ if (store.fallbackValue > -1) {
+ //also create v8 instruction (needed to properly configure the fallback v8 binding)
+ JSBindingReference &js = static_cast<JSBindingReference &>(*binding->bindingReference);
+ js.dataType = BindingReference::V8;
+ genBindingAssignment(binding, prop, obj, valueTypeProperty);
+ }
} else if (ref.dataType == BindingReference::V8) {
const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
Instruction::StoreV8Binding store;
- store.value = js.compiledIndex;
+ store.value = js.sharedIndex;
store.context = js.bindingContext.stack;
store.owner = js.bindingContext.owner;
store.isAlias = prop->isAlias;
} else {
store.isRoot = (compileState->root == obj);
}
+ store.isFallback = js.compiledIndex > -1;
store.line = binding->location.start.line;
store.column = binding->location.start.column;
} else {
store.isRoot = (compileState->root == obj);
}
+ store.isFallback = false;
Q_ASSERT(js.bindingContext.owner == 0 ||
(js.bindingContext.owner != 0 && valueTypeProperty));
expr.property = binding.property;
expr.expression = binding.expression;
- int index = bindingCompiler.compile(expr, enginePrivate);
+ bool needsFallback = false;
+ int index = bindingCompiler.compile(expr, enginePrivate, &needsFallback);
if (index != -1) {
+ // Ensure the index value fits within the available space
+ Q_ASSERT(index < (1 << 15));
+
binding.dataType = BindingReference::V4;
binding.compiledIndex = index;
+ binding.sharedIndex = -1;
if (componentStats)
componentStats->componentStat.optimizedBindings.append(b->value->location);
- continue;
+
+ if (!needsFallback)
+ continue;
+
+ // Drop through. We need to create a V8 binding in case the V4 binding is invalidated
}
// Pre-rewrite the expression
binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
if (isSharable && binding.property->type != qMetaTypeId<QQmlBinding*>()) {
- binding.dataType = BindingReference::V8;
sharedBindings.append(b);
- if (componentStats)
- componentStats->componentStat.sharedBindings.append(b->value->location);
+ if (!needsFallback) {
+ binding.dataType = BindingReference::V8;
+ binding.compiledIndex = -1;
+
+ if (componentStats)
+ componentStats->componentStat.sharedBindings.append(b->value->location);
+ }
} else {
+ Q_ASSERT(!needsFallback);
binding.dataType = BindingReference::QtScript;
if (componentStats)
functionArray += expression.toUtf8();
lineNumber += expression.count(QLatin1Char('\n'));
- reference->compiledIndex = ii;
+
+ // Ensure the index value fits within the available space
+ Q_ASSERT(ii < (1 << 15));
+ reference->sharedIndex = ii;
}
functionArray.append("]", 1);