Use V4 binding for non-final properties where possible
[profile/ivi/qtdeclarative.git] / src / qml / qml / qqmlcompiler.cpp
index fd42ab8..6f27925 100644 (file)
@@ -1413,6 +1413,8 @@ void QQmlCompiler::genValueTypeProperty(QQmlScript::Object *obj,QQmlScript::Prop
     pop.type = prop->type;
     pop.bindingSkipList = 0;
     output->addInstruction(pop);
+
+    genPropertyAssignment(prop, obj);
 }
 
 void QQmlCompiler::genComponent(QQmlScript::Object *obj)
@@ -2106,10 +2108,15 @@ bool QQmlCompiler::buildGroupedProperty(QQmlScript::Property *prop,
         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"));
+                        }
+                    }
                 }
             }
 
@@ -2117,7 +2124,6 @@ bool QQmlCompiler::buildGroupedProperty(QQmlScript::Property *prop,
                 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;
@@ -2126,7 +2132,26 @@ bool QQmlCompiler::buildGroupedProperty(QQmlScript::Property *prop,
 
             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"));
         }
@@ -3433,6 +3458,7 @@ void QQmlCompiler::genBindingAssignment(QQmlScript::Value *binding,
 
         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;
@@ -3448,11 +3474,18 @@ void QQmlCompiler::genBindingAssignment(QQmlScript::Value *binding,
         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;
@@ -3461,6 +3494,7 @@ void QQmlCompiler::genBindingAssignment(QQmlScript::Value *binding,
         } else {
             store.isRoot = (compileState->root == obj);
         }
+        store.isFallback = js.compiledIndex > -1;
         store.line = binding->location.start.line;
         store.column = binding->location.start.column;
 
@@ -3489,6 +3523,7 @@ void QQmlCompiler::genBindingAssignment(QQmlScript::Value *binding,
         } else {
             store.isRoot = (compileState->root == obj);
         }
+        store.isFallback = false;
 
         Q_ASSERT(js.bindingContext.owner == 0 ||
                  (js.bindingContext.owner != 0 && valueTypeProperty));
@@ -3554,13 +3589,22 @@ bool QQmlCompiler::completeComponentBuild()
         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
@@ -3572,12 +3616,17 @@ bool QQmlCompiler::completeComponentBuild()
         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)
@@ -3614,7 +3663,10 @@ bool QQmlCompiler::completeComponentBuild()
 
             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);