aboutsummaryrefslogtreecommitdiffstats
path: root/src/qmlcompiler
diff options
context:
space:
mode:
Diffstat (limited to 'src/qmlcompiler')
-rw-r--r--src/qmlcompiler/qqmljsbasicblocks.cpp2
-rw-r--r--src/qmlcompiler/qqmljscodegenerator.cpp2
-rw-r--r--src/qmlcompiler/qqmljscompilepass_p.h76
-rw-r--r--src/qmlcompiler/qqmljsimportvisitor.cpp37
-rw-r--r--src/qmlcompiler/qqmljsscope.cpp8
-rw-r--r--src/qmlcompiler/qqmljsshadowcheck.cpp2
-rw-r--r--src/qmlcompiler/qqmljstypepropagator.cpp115
-rw-r--r--src/qmlcompiler/qqmljstypepropagator_p.h2
-rw-r--r--src/qmlcompiler/qqmlsa.cpp7
-rw-r--r--src/qmlcompiler/qqmlsa_p.h3
10 files changed, 161 insertions, 93 deletions
diff --git a/src/qmlcompiler/qqmljsbasicblocks.cpp b/src/qmlcompiler/qqmljsbasicblocks.cpp
index d5bbae037f..e95ad114e4 100644
--- a/src/qmlcompiler/qqmljsbasicblocks.cpp
+++ b/src/qmlcompiler/qqmljsbasicblocks.cpp
@@ -216,7 +216,7 @@ void QQmlJSBasicBlocks::populateReaderLocations()
m_readerLocations.erase(reader);
// If it's not a label and has no side effects, we can drop the instruction.
- if (!it->second.hasSideEffects) {
+ if (!it->second.hasInternalSideEffects) {
if (!it->second.readRegisters.isEmpty()) {
it->second.readRegisters.clear();
erasedReaders = true;
diff --git a/src/qmlcompiler/qqmljscodegenerator.cpp b/src/qmlcompiler/qqmljscodegenerator.cpp
index 01ef6a95e6..709dcbea8f 100644
--- a/src/qmlcompiler/qqmljscodegenerator.cpp
+++ b/src/qmlcompiler/qqmljscodegenerator.cpp
@@ -2561,7 +2561,7 @@ QV4::Moth::ByteCodeHandler::Verdict QQmlJSCodeGenerator::startInstruction(
// If the instruction has no side effects and doesn't write any register, it's dead.
// We might still need the label, though, and the source code comment.
- if (!m_state.hasSideEffects() && changedRegisterVariable().isEmpty()) {
+ if (!m_state.hasInternalSideEffects() && changedRegisterVariable().isEmpty()) {
generateJumpCodeWithTypeConversions(0);
return SkipInstruction;
}
diff --git a/src/qmlcompiler/qqmljscompilepass_p.h b/src/qmlcompiler/qqmljscompilepass_p.h
index b35adfb66a..7ca9744bb1 100644
--- a/src/qmlcompiler/qqmljscompilepass_p.h
+++ b/src/qmlcompiler/qqmljscompilepass_p.h
@@ -64,7 +64,8 @@ public:
QQmlJSRegisterContent changedRegister;
int changedRegisterIndex = InvalidRegister;
- bool hasSideEffects = false;
+ bool hasInternalSideEffects = false;
+ bool hasExternalSideEffects = false;
bool isRename = false;
};
@@ -158,16 +159,33 @@ public:
return m_readRegisters.contains(registerIndex);
}
- bool hasSideEffects() const { return m_hasSideEffects; }
- void setHasSideEffects(bool hasSideEffects) {
- m_hasSideEffects = hasSideEffects;
- if (!hasSideEffects)
+ bool hasInternalSideEffects() const { return m_hasInternalSideEffects; }
+ bool hasExternalSideEffects() const { return m_hasExternalSideEffects; }
+
+ void resetSideEffects()
+ {
+ m_hasInternalSideEffects = false;
+ m_hasExternalSideEffects = false;
+ }
+
+ void applyExternalSideEffects(bool hasExternalSideEffects)
+ {
+ if (!hasExternalSideEffects)
return;
for (auto it = registers.begin(), end = registers.end(); it != end; ++it)
it.value().affectedBySideEffects = true;
}
+ void setHasInternalSideEffects() { m_hasInternalSideEffects = true; }
+ void setHasExternalSideEffects()
+ {
+ m_hasExternalSideEffects = true;
+ m_hasInternalSideEffects = true;
+ applyExternalSideEffects(true);
+ }
+
+
bool isRename() const { return m_isRename; }
void setIsRename(bool isRename) { m_isRename = isRename; }
@@ -178,11 +196,36 @@ public:
return m_readRegisters.begin().key();
}
+ void applyAnnotation(const InstructionAnnotation &annotation)
+ {
+ m_readRegisters = annotation.readRegisters;
+
+ m_hasInternalSideEffects = annotation.hasInternalSideEffects;
+ m_hasExternalSideEffects = annotation.hasExternalSideEffects;
+ m_isRename = annotation.isRename;
+
+ for (auto it = annotation.typeConversions.constBegin(),
+ end = annotation.typeConversions.constEnd(); it != end; ++it) {
+ Q_ASSERT(it.key() != InvalidRegister);
+ registers[it.key()] = it.value();
+ }
+
+ if (annotation.changedRegisterIndex != InvalidRegister)
+ setRegister(annotation.changedRegisterIndex, annotation.changedRegister);
+ }
+
private:
VirtualRegisters m_readRegisters;
QQmlJSRegisterContent m_changedRegister;
int m_changedRegisterIndex = InvalidRegister;
- bool m_hasSideEffects = false;
+
+ // If the instruction's value is unused, we still cannot optimize it out.
+ bool m_hasInternalSideEffects = false;
+
+ // Side effect created by calls to other functions or writes to properties,
+ // affects tracked value types and lists. Implies the effects of Internal.
+ bool m_hasExternalSideEffects = false;
+
bool m_isRename = false;
};
@@ -245,23 +288,12 @@ protected:
= oldState.changedRegister();
}
- if (instruction == annotations.constEnd())
- return newState;
-
- newState.setHasSideEffects(instruction->second.hasSideEffects);
- newState.setReadRegisters(instruction->second.readRegisters);
- newState.setIsRename(instruction->second.isRename);
+ // Side effects are applied at the end of an instruction: An instruction with side
+ // effects can still read its registers before the side effects happen.
+ newState.applyExternalSideEffects(oldState.hasExternalSideEffects());
- for (auto it = instruction->second.typeConversions.begin(),
- end = instruction->second.typeConversions.end(); it != end; ++it) {
- Q_ASSERT(it.key() != InvalidRegister);
- newState.registers[it.key()] = it.value();
- }
-
- if (instruction->second.changedRegisterIndex != InvalidRegister) {
- newState.setRegister(instruction->second.changedRegisterIndex,
- instruction->second.changedRegister);
- }
+ if (instruction != annotations.constEnd())
+ newState.applyAnnotation(instruction->second);
return newState;
}
diff --git a/src/qmlcompiler/qqmljsimportvisitor.cpp b/src/qmlcompiler/qqmljsimportvisitor.cpp
index 4bc215add7..bd693cc619 100644
--- a/src/qmlcompiler/qqmljsimportvisitor.cpp
+++ b/src/qmlcompiler/qqmljsimportvisitor.cpp
@@ -18,6 +18,7 @@
#include <QtQml/private/qqmlirbuilder_p.h>
#include "qqmljsscope_p.h"
#include "qqmljsutils_p.h"
+#include "qqmlsa_p.h"
#include <algorithm>
#include <variant>
@@ -799,8 +800,8 @@ void QQmlJSImportVisitor::checkRequiredProperties()
}
}
- const auto isInComponent = [this](const QQmlJSScope::ConstPtr &requiredScope) {
- const auto compType = m_rootScopeImports.type(u"Component"_s).scope;
+ const auto compType = m_rootScopeImports.type(u"Component"_s).scope;
+ const auto isInComponent = [&](const QQmlJSScope::ConstPtr &requiredScope) {
for (auto s = requiredScope; s; s = s->parentScope()) {
if (s->isWrappedInImplicitComponent() || s->baseType() == compType)
return true;
@@ -811,9 +812,11 @@ void QQmlJSImportVisitor::checkRequiredProperties()
const auto requiredHasBinding = [](const QList<QQmlJSScope::ConstPtr> &scopesToSearch,
const QString &propName) {
for (const auto &scope : scopesToSearch) {
+ if (scope->property(propName).isAlias())
+ continue;
const auto &[begin, end] = scope->ownPropertyBindings(propName);
for (auto it = begin; it != end; ++it) {
- if (!scope->property(propName).isAlias())
+ if (QQmlSA::isRegularBindingType(it->bindingType()))
return true;
}
}
@@ -880,16 +883,17 @@ void QQmlJSImportVisitor::checkRequiredProperties()
: u"here"_s;
if (!prevRequiredScope.isNull()) {
- auto sourceScope = prevRequiredScope->baseType();
- suggestion = QQmlJSFixSuggestion{
- "%1:%2:%3: Property marked as required in %4."_L1
- .arg(sourceScope->filePath())
- .arg(sourceScope->sourceLocation().startLine)
- .arg(sourceScope->sourceLocation().startColumn)
- .arg(requiredScopeName),
- sourceScope->sourceLocation()
- };
- suggestion->setFilename(sourceScope->filePath());
+ if (auto sourceScope = prevRequiredScope->baseType()) {
+ suggestion = QQmlJSFixSuggestion{
+ "%1:%2:%3: Property marked as required in %4."_L1
+ .arg(sourceScope->filePath())
+ .arg(sourceScope->sourceLocation().startLine)
+ .arg(sourceScope->sourceLocation().startColumn)
+ .arg(requiredScopeName),
+ sourceScope->sourceLocation()
+ };
+ suggestion->setFilename(sourceScope->filePath());
+ }
} else {
message += " (marked as required by %1)"_L1.arg(requiredScopeName);
}
@@ -902,7 +906,8 @@ void QQmlJSImportVisitor::checkRequiredProperties()
for (const auto &[_, defScope] : m_scopesByIrLocation.asKeyValueRange()) {
if (defScope->parentScope() == m_globalScope || defScope->isInlineComponent()
- || defScope->isComponentRootElement()) {
+ || defScope->isComponentRootElement()
+ || defScope->scopeType() != QQmlJSScope::QMLScope) {
continue;
}
@@ -917,6 +922,8 @@ void QQmlJSImportVisitor::checkRequiredProperties()
for (auto propertyIt = ownProperties.constBegin();
propertyIt != ownProperties.constEnd(); ++propertyIt) {
const QString propName = propertyIt.key();
+ if (descendant->hasOwnPropertyBindings(propName))
+ continue;
QQmlJSScope::ConstPtr prevRequiredScope;
for (QQmlJSScope::ConstPtr requiredScope : std::as_const(scopesToSearch)) {
@@ -1613,7 +1620,7 @@ bool QQmlJSImportVisitor::visit(UiPublicMember *publicMember)
auto tryParseAlias = [&]() {
typeName.clear(); // type name is useless for alias here, so keep it empty
if (!publicMember->statement) {
- m_logger->log(QStringLiteral("Invalid alias expression – an initalizer is needed."),
+ m_logger->log(QStringLiteral("Invalid alias expression - an initalizer is needed."),
qmlSyntax, publicMember->memberType->firstSourceLocation()); // TODO: extend warning to cover until endSourceLocation
return;
}
diff --git a/src/qmlcompiler/qqmljsscope.cpp b/src/qmlcompiler/qqmljsscope.cpp
index 5067210261..29a0db05cf 100644
--- a/src/qmlcompiler/qqmljsscope.cpp
+++ b/src/qmlcompiler/qqmljsscope.cpp
@@ -361,9 +361,15 @@ qFindInlineComponents(QStringView typeName, const QQmlJSScope::ContextualTypes &
if (current->isInlineComponent() && current->inlineComponentName() == inlineComponentName) {
return { current, inlineComponentParent.revision };
}
+
// check alternatively the inline components at layer 1 in current and basetype, then at
// layer 2, etc...
- candidatesForInlineComponents.append(current->childScopes());
+ const auto &childScopes = current->childScopes();
+ for (const auto &child : childScopes) {
+ if (child->scopeType() == QQmlJSScope::ScopeType::QMLScope)
+ candidatesForInlineComponents.enqueue(child);
+ }
+
if (const auto base = current->baseType())
candidatesForInlineComponents.enqueue(base);
}
diff --git a/src/qmlcompiler/qqmljsshadowcheck.cpp b/src/qmlcompiler/qqmljsshadowcheck.cpp
index ead1813afe..600e40d389 100644
--- a/src/qmlcompiler/qqmljsshadowcheck.cpp
+++ b/src/qmlcompiler/qqmljsshadowcheck.cpp
@@ -72,7 +72,7 @@ void QQmlJSShadowCheck::generate_SetLookup(int index, int base)
QV4::Moth::ByteCodeHandler::Verdict QQmlJSShadowCheck::startInstruction(QV4::Moth::Instr::Type)
{
m_state = nextStateFromAnnotations(m_state, *m_annotations);
- return (m_state.hasSideEffects() || m_state.changedRegisterIndex() != InvalidRegister)
+ return (m_state.hasInternalSideEffects() || m_state.changedRegisterIndex() != InvalidRegister)
? ProcessInstruction
: SkipInstruction;
}
diff --git a/src/qmlcompiler/qqmljstypepropagator.cpp b/src/qmlcompiler/qqmljstypepropagator.cpp
index 06b49d067d..bff83817fe 100644
--- a/src/qmlcompiler/qqmljstypepropagator.cpp
+++ b/src/qmlcompiler/qqmljstypepropagator.cpp
@@ -105,7 +105,7 @@ void QQmlJSTypePropagator::generate_Ret()
addReadAccumulator(m_returnType);
}
- m_state.setHasSideEffects(true);
+ m_state.setHasInternalSideEffects();
m_state.skipInstructionsUntilNextJumpTarget = true;
}
@@ -631,7 +631,7 @@ void QQmlJSTypePropagator::generate_StoreNameCommon(int nameIndex)
m_function->qmlScope, getCurrentSourceLocation());
}
- m_state.setHasSideEffects(true);
+ m_state.setHasExternalSideEffects();
if (m_typeResolver->canHoldUndefined(in) && !m_typeResolver->canHoldUndefined(type)) {
if (type.property().reset().isEmpty())
@@ -725,7 +725,7 @@ void QQmlJSTypePropagator::generate_StoreElement(int base, int index)
// Writing to a JS array can have side effects all over the place since it's
// passed by reference.
- m_state.setHasSideEffects(true);
+ m_state.setHasExternalSideEffects();
return;
}
@@ -742,7 +742,7 @@ void QQmlJSTypePropagator::generate_StoreElement(int base, int index)
// If we're writing to a list retrieved from a property, that _should_ have side effects,
// but currently the QML engine doesn't implement them.
// TODO: Figure out the above and accurately set the flag.
- m_state.setHasSideEffects(true);
+ m_state.setHasExternalSideEffects();
}
void QQmlJSTypePropagator::propagatePropertyLookup(const QString &propertyName)
@@ -963,7 +963,7 @@ void QQmlJSTypePropagator::generate_StoreProperty(int nameIndex, int base)
addReadAccumulator(property);
addReadRegister(base, callBase);
- m_state.setHasSideEffects(true);
+ m_state.setHasExternalSideEffects();
}
void QQmlJSTypePropagator::generate_SetLookup(int index, int base)
@@ -1000,7 +1000,7 @@ void QQmlJSTypePropagator::generate_Resume(int)
void QQmlJSTypePropagator::generate_CallValue(int name, int argc, int argv)
{
- m_state.setHasSideEffects(true);
+ m_state.setHasExternalSideEffects();
Q_UNUSED(name)
Q_UNUSED(argc)
Q_UNUSED(argv)
@@ -1009,7 +1009,7 @@ void QQmlJSTypePropagator::generate_CallValue(int name, int argc, int argv)
void QQmlJSTypePropagator::generate_CallWithReceiver(int name, int thisObject, int argc, int argv)
{
- m_state.setHasSideEffects(true);
+ m_state.setHasExternalSideEffects();
Q_UNUSED(name)
Q_UNUSED(thisObject)
Q_UNUSED(argc)
@@ -1075,7 +1075,7 @@ void QQmlJSTypePropagator::generate_CallProperty(int nameIndex, int base, int ar
for (int i = 1; i < argc; ++i)
addReadRegister(argv + i, stringType);
- m_state.setHasSideEffects(true);
+ m_state.setHasExternalSideEffects();
setAccumulator(voidType);
return;
}
@@ -1087,7 +1087,7 @@ void QQmlJSTypePropagator::generate_CallProperty(int nameIndex, int base, int ar
for (int i = 0; i < argc; ++i)
addReadRegister(argv + i, jsValueType);
setAccumulator(jsValueType);
- m_state.setHasSideEffects(true);
+ m_state.setHasExternalSideEffects();
return;
}
@@ -1238,14 +1238,17 @@ void QQmlJSTypePropagator::setRegister(int index, const QQmlJSRegisterContent &c
}
void QQmlJSTypePropagator::mergeRegister(
- int index, const QQmlJSRegisterContent &a, const QQmlJSRegisterContent &b)
+ int index, const VirtualRegister &a, const VirtualRegister &b)
{
- auto merged = m_typeResolver->merge(a, b);
+ const VirtualRegister merged = {
+ m_typeResolver->merge(a.content, b.content),
+ a.affectedBySideEffects || b.affectedBySideEffects,
+ };
- Q_ASSERT(merged.isValid());
- Q_ASSERT(merged.isConversion());
+ Q_ASSERT(merged.content.isValid());
+ Q_ASSERT(merged.content.isConversion());
- auto tryPrevStateConversion = [this](int index, const QQmlJSRegisterContent &merged) -> bool {
+ auto tryPrevStateConversion = [this](int index, const VirtualRegister &merged) -> bool {
auto it = m_prevStateAnnotations.find(currentInstructionOffset());
if (it == m_prevStateAnnotations.end())
return false;
@@ -1259,22 +1262,31 @@ void QQmlJSTypePropagator::mergeRegister(
Q_ASSERT(lastTry.content.isValid());
Q_ASSERT(lastTry.content.isConversion());
- if (!m_typeResolver->equals(lastTry.content.conversionResult(), merged.conversionResult())
- || lastTry.content.conversionOrigins() != merged.conversionOrigins()) {
+ if (!m_typeResolver->equals(lastTry.content.conversionResult(),
+ merged.content.conversionResult())
+ || lastTry.content.conversionOrigins() != merged.content.conversionOrigins()
+ || lastTry.affectedBySideEffects != merged.affectedBySideEffects) {
return false;
}
// We don't need to track it again if we've come to the same conclusion before.
m_state.annotations[currentInstructionOffset()].typeConversions[index] = lastTry;
+
+ // Do not reset the side effects
+ Q_ASSERT(!m_state.registers[index].affectedBySideEffects || lastTry.affectedBySideEffects);
+
m_state.registers[index] = lastTry;
return true;
};
if (!tryPrevStateConversion(index, merged)) {
- merged = m_typeResolver->tracked(merged);
- Q_ASSERT(merged.isValid());
- m_state.annotations[currentInstructionOffset()].typeConversions[index].content = merged;
- m_state.registers[index].content = merged;
+ const VirtualRegister cloned = {
+ m_typeResolver->tracked(merged.content),
+ merged.affectedBySideEffects,
+ };
+ Q_ASSERT(cloned.content.isValid());
+ m_state.annotations[currentInstructionOffset()].typeConversions[index] = cloned;
+ m_state.registers[index] = cloned;
}
}
@@ -1316,7 +1328,7 @@ void QQmlJSTypePropagator::propagateCall(
if (!m_state.accumulatorOut().isValid())
setError(u"Cannot store return type of method %1()."_s.arg(match.methodName()));
- m_state.setHasSideEffects(true);
+ m_state.setHasExternalSideEffects();
const auto types = match.parameters();
for (int i = 0; i < argc; ++i) {
if (i < types.size()) {
@@ -1478,7 +1490,7 @@ void QQmlJSTypePropagator::generate_CallName(int name, int argc, int argv)
void QQmlJSTypePropagator::generate_CallPossiblyDirectEval(int argc, int argv)
{
- m_state.setHasSideEffects(true);
+ m_state.setHasExternalSideEffects();
Q_UNUSED(argc)
Q_UNUSED(argv)
INSTR_PROLOGUE_NOT_IMPLEMENTED();
@@ -1523,7 +1535,7 @@ void QQmlJSTypePropagator::generate_CallQmlContextPropertyLookup(int index, int
void QQmlJSTypePropagator::generate_CallWithSpread(int func, int thisObject, int argc, int argv)
{
- m_state.setHasSideEffects(true);
+ m_state.setHasExternalSideEffects();
Q_UNUSED(func)
Q_UNUSED(thisObject)
Q_UNUSED(argc)
@@ -1533,7 +1545,7 @@ void QQmlJSTypePropagator::generate_CallWithSpread(int func, int thisObject, int
void QQmlJSTypePropagator::generate_TailCall(int func, int thisObject, int argc, int argv)
{
- m_state.setHasSideEffects(true);
+ m_state.setHasExternalSideEffects();
Q_UNUSED(func)
Q_UNUSED(thisObject)
Q_UNUSED(argc)
@@ -1543,7 +1555,7 @@ void QQmlJSTypePropagator::generate_TailCall(int func, int thisObject, int argc,
void QQmlJSTypePropagator::generate_Construct(int func, int argc, int argv)
{
- m_state.setHasSideEffects(true);
+ m_state.setHasExternalSideEffects();
Q_UNUSED(func)
Q_UNUSED(argv)
@@ -1554,7 +1566,7 @@ void QQmlJSTypePropagator::generate_Construct(int func, int argc, int argv)
void QQmlJSTypePropagator::generate_ConstructWithSpread(int func, int argc, int argv)
{
- m_state.setHasSideEffects(true);
+ m_state.setHasExternalSideEffects();
Q_UNUSED(func)
Q_UNUSED(argc)
Q_UNUSED(argv)
@@ -1563,20 +1575,20 @@ void QQmlJSTypePropagator::generate_ConstructWithSpread(int func, int argc, int
void QQmlJSTypePropagator::generate_SetUnwindHandler(int offset)
{
- m_state.setHasSideEffects(true);
+ m_state.setHasInternalSideEffects();
Q_UNUSED(offset)
INSTR_PROLOGUE_NOT_IMPLEMENTED_IGNORE();
}
void QQmlJSTypePropagator::generate_UnwindDispatch()
{
- m_state.setHasSideEffects(true);
+ m_state.setHasInternalSideEffects();
INSTR_PROLOGUE_NOT_IMPLEMENTED_IGNORE();
}
void QQmlJSTypePropagator::generate_UnwindToLabel(int level, int offset)
{
- m_state.setHasSideEffects(true);
+ m_state.setHasInternalSideEffects();
Q_UNUSED(level)
Q_UNUSED(offset)
INSTR_PROLOGUE_NOT_IMPLEMENTED();
@@ -1591,7 +1603,7 @@ void QQmlJSTypePropagator::generate_DeadTemporalZoneCheck(int name)
void QQmlJSTypePropagator::generate_ThrowException()
{
addReadAccumulator(m_typeResolver->globalType(m_typeResolver->jsValueType()));
- m_state.setHasSideEffects(true);
+ m_state.setHasInternalSideEffects();
m_state.skipInstructionsUntilNextJumpTarget = true;
}
@@ -1602,18 +1614,18 @@ void QQmlJSTypePropagator::generate_GetException()
void QQmlJSTypePropagator::generate_SetException()
{
- m_state.setHasSideEffects(true);
+ m_state.setHasInternalSideEffects();
INSTR_PROLOGUE_NOT_IMPLEMENTED();
}
void QQmlJSTypePropagator::generate_CreateCallContext()
{
- m_state.setHasSideEffects(true);
+ m_state.setHasInternalSideEffects();
}
void QQmlJSTypePropagator::generate_PushCatchContext(int index, int name)
{
- m_state.setHasSideEffects(true);
+ m_state.setHasInternalSideEffects();
Q_UNUSED(index)
Q_UNUSED(name)
INSTR_PROLOGUE_NOT_IMPLEMENTED_IGNORE();
@@ -1621,39 +1633,39 @@ void QQmlJSTypePropagator::generate_PushCatchContext(int index, int name)
void QQmlJSTypePropagator::generate_PushWithContext()
{
- m_state.setHasSideEffects(true);
+ m_state.setHasInternalSideEffects();
INSTR_PROLOGUE_NOT_IMPLEMENTED();
}
void QQmlJSTypePropagator::generate_PushBlockContext(int index)
{
- m_state.setHasSideEffects(true);
+ m_state.setHasInternalSideEffects();
Q_UNUSED(index)
INSTR_PROLOGUE_NOT_IMPLEMENTED();
}
void QQmlJSTypePropagator::generate_CloneBlockContext()
{
- m_state.setHasSideEffects(true);
+ m_state.setHasInternalSideEffects();
INSTR_PROLOGUE_NOT_IMPLEMENTED();
}
void QQmlJSTypePropagator::generate_PushScriptContext(int index)
{
- m_state.setHasSideEffects(true);
+ m_state.setHasInternalSideEffects();
Q_UNUSED(index)
INSTR_PROLOGUE_NOT_IMPLEMENTED();
}
void QQmlJSTypePropagator::generate_PopScriptContext()
{
- m_state.setHasSideEffects(true);
+ m_state.setHasInternalSideEffects();
INSTR_PROLOGUE_NOT_IMPLEMENTED();
}
void QQmlJSTypePropagator::generate_PopContext()
{
- m_state.setHasSideEffects(true);
+ m_state.setHasInternalSideEffects();
}
void QQmlJSTypePropagator::generate_GetIterator(int iterator)
@@ -1784,7 +1796,7 @@ void QQmlJSTypePropagator::generate_Jump(int offset)
{
saveRegisterStateForJump(offset);
m_state.skipInstructionsUntilNextJumpTarget = true;
- m_state.setHasSideEffects(true);
+ m_state.setHasInternalSideEffects();
}
void QQmlJSTypePropagator::generate_JumpTrue(int offset)
@@ -1796,7 +1808,7 @@ void QQmlJSTypePropagator::generate_JumpTrue(int offset)
return;
}
saveRegisterStateForJump(offset);
- m_state.setHasSideEffects(true);
+ m_state.setHasInternalSideEffects();
addReadAccumulator(m_typeResolver->globalType(m_typeResolver->boolType()));
}
@@ -1809,14 +1821,14 @@ void QQmlJSTypePropagator::generate_JumpFalse(int offset)
return;
}
saveRegisterStateForJump(offset);
- m_state.setHasSideEffects(true);
+ m_state.setHasInternalSideEffects();
addReadAccumulator(m_typeResolver->globalType(m_typeResolver->boolType()));
}
void QQmlJSTypePropagator::generate_JumpNoException(int offset)
{
saveRegisterStateForJump(offset);
- m_state.setHasSideEffects(true);
+ m_state.setHasInternalSideEffects();
}
void QQmlJSTypePropagator::generate_JumpNotUndefined(int offset)
@@ -1827,7 +1839,7 @@ void QQmlJSTypePropagator::generate_JumpNotUndefined(int offset)
void QQmlJSTypePropagator::generate_CheckException()
{
- m_state.setHasSideEffects(true);
+ m_state.setHasInternalSideEffects();
}
void QQmlJSTypePropagator::recordEqualsNullType()
@@ -2199,7 +2211,7 @@ void QQmlJSTypePropagator::generate_InitializeBlockDeadTemporalZone(int firstReg
{
Q_UNUSED(firstReg)
Q_UNUSED(count)
- m_state.setHasSideEffects(true);
+ m_state.setHasInternalSideEffects();
// Ignore. We reject uninitialized values anyway.
}
@@ -2254,8 +2266,8 @@ QQmlJSTypePropagator::startInstruction(QV4::Moth::Instr::Type type)
registerIt != end; ++registerIt) {
const int registerIndex = registerIt.key();
- auto newType = registerIt.value().content;
- if (!newType.isValid()) {
+ const VirtualRegister &newType = registerIt.value();
+ if (!newType.content.isValid()) {
setError(u"When reached from offset %1, %2 is undefined"_s
.arg(stateToMerge.originatingOffset)
.arg(registerName(registerIndex)));
@@ -2264,7 +2276,7 @@ QQmlJSTypePropagator::startInstruction(QV4::Moth::Instr::Type type)
auto currentRegister = m_state.registers.find(registerIndex);
if (currentRegister != m_state.registers.end())
- mergeRegister(registerIndex, newType, currentRegister.value().content);
+ mergeRegister(registerIndex, newType, currentRegister.value());
else
mergeRegister(registerIndex, newType, newType);
}
@@ -2279,7 +2291,8 @@ void QQmlJSTypePropagator::endInstruction(QV4::Moth::Instr::Type instr)
currentInstruction.changedRegister = m_state.changedRegister();
currentInstruction.changedRegisterIndex = m_state.changedRegisterIndex();
currentInstruction.readRegisters = m_state.takeReadRegisters();
- currentInstruction.hasSideEffects = m_state.hasSideEffects();
+ currentInstruction.hasExternalSideEffects = m_state.hasExternalSideEffects();
+ currentInstruction.hasInternalSideEffects = m_state.hasInternalSideEffects();
currentInstruction.isRename = m_state.isRename();
switch (instr) {
@@ -2323,7 +2336,7 @@ void QQmlJSTypePropagator::endInstruction(QV4::Moth::Instr::Type instr)
&& instr != QV4::Moth::Instr::Type::DeadTemporalZoneCheck) {
// An instruction needs to have side effects or write to another register otherwise it's a
// noop. DeadTemporalZoneCheck is not needed by the compiler and is ignored.
- Q_ASSERT(m_state.hasSideEffects() || m_state.changedRegisterIndex() != -1);
+ Q_ASSERT(m_state.hasInternalSideEffects() || m_state.changedRegisterIndex() != -1);
}
if (m_state.changedRegisterIndex() != InvalidRegister) {
@@ -2335,7 +2348,7 @@ void QQmlJSTypePropagator::endInstruction(QV4::Moth::Instr::Type instr)
m_state.clearChangedRegister();
}
- m_state.setHasSideEffects(false);
+ m_state.resetSideEffects();
m_state.setIsRename(false);
m_state.setReadRegisters(VirtualRegisters());
}
diff --git a/src/qmlcompiler/qqmljstypepropagator_p.h b/src/qmlcompiler/qqmljstypepropagator_p.h
index dd0c0ec750..99a421a4a1 100644
--- a/src/qmlcompiler/qqmljstypepropagator_p.h
+++ b/src/qmlcompiler/qqmljstypepropagator_p.h
@@ -227,7 +227,7 @@ private:
void setAccumulator(const QQmlJSRegisterContent &content);
void setRegister(int index, const QQmlJSRegisterContent &content);
- void mergeRegister(int index, const QQmlJSRegisterContent &a, const QQmlJSRegisterContent &b);
+ void mergeRegister(int index, const VirtualRegister &a, const VirtualRegister &b);
void addReadRegister(int index, const QQmlJSRegisterContent &convertTo);
void addReadAccumulator(const QQmlJSRegisterContent &convertTo)
diff --git a/src/qmlcompiler/qqmlsa.cpp b/src/qmlcompiler/qqmlsa.cpp
index 7a209f52c1..388a5fe599 100644
--- a/src/qmlcompiler/qqmlsa.cpp
+++ b/src/qmlcompiler/qqmlsa.cpp
@@ -360,6 +360,13 @@ void DebugPropertyPass::onWrite(const QQmlSA::Element &element, const QString &p
+ QString::number(location.startColumn),
qmlPlugin, location);
}
+
+bool isRegularBindingType(QQmlJSMetaPropertyBinding::BindingType type)
+{
+ return type >= QQmlJSMetaPropertyBinding::BindingType::BoolLiteral
+ && type <= QQmlJSMetaPropertyBinding::BindingType::Object;
+}
+
}
QT_END_NAMESPACE
diff --git a/src/qmlcompiler/qqmlsa_p.h b/src/qmlcompiler/qqmlsa_p.h
index 6bbbe9441b..18caee3640 100644
--- a/src/qmlcompiler/qqmlsa_p.h
+++ b/src/qmlcompiler/qqmlsa_p.h
@@ -183,6 +183,9 @@ public:
const QQmlSA::Element &value, const QQmlSA::Element &writeScope,
QQmlJS::SourceLocation location) override;
};
+
+bool isRegularBindingType(QQmlJSMetaPropertyBinding::BindingType type);
+
}
#define QmlLintPluginInterface_iid "org.qt-project.Qt.Qml.SA.LintPlugin/1.0"