summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@qt.io>2019-01-21 16:55:26 +0100
committerSimon Hausmann <simon.hausmann@qt.io>2019-01-21 16:55:26 +0100
commit1e5851a1044ca609572789acbd6564b580351173 (patch)
tree1169fd61c995248f158e929417ae6cdf007f7663
parentff52723122935a6ff778994ec6d185432ae137e9 (diff)
downloadqtdeclarative-personal/shausman/type-inference.tar.gz
WIP: propagate types inferred from the ASTpersonal/shausman/type-inference
Change-Id: I9831f55d953c897f3df43efe2c7ee08e27a1eed8
-rw-r--r--src/qml/compiler/qv4codegen.cpp19
-rw-r--r--src/qml/compiler/qv4codegen_p.h9
-rw-r--r--tests/auto/qml/v4misc/tst_v4misc.cpp66
3 files changed, 86 insertions, 8 deletions
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index 31303b0fec..5d9148044b 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -630,7 +630,7 @@ void Codegen::initializeAndDestructureBindingElement(AST::PatternElement *e, con
if (hasError)
return;
expr.loadInAccumulator();
- varToStore.storeConsumeAccumulator();
+ varToStore.storeConsumeAccumulator(expr.inferredType);
} else if (baseRef == varToStore) {
baseRef.loadInAccumulator();
BytecodeGenerator::Jump jump = bytecodeGenerator->jumpNotUndefined();
@@ -2300,7 +2300,10 @@ bool Codegen::visit(FieldMemberExpression *ast)
_expr.setResult(Reference::fromSuperProperty(property));
return false;
}
- _expr.setResult(Reference::fromMember(base, ast->name.toString()));
+ auto member = Reference::fromMember(base, ast->name.toString());
+ if (m_typeResolver && base.type)
+ member.inferredType = m_typeResolver(base.inferredType, ast->name.toString());
+ _expr.setResult(member);
return false;
}
@@ -2417,6 +2420,10 @@ Codegen::Reference Codegen::referenceForName(const QString &name, bool isLhs, co
r.global = useFastLookups && (resolved.type == Context::ResolvedName::Global);
if (!r.global && m_globalNames.contains(name))
r.global = true;
+
+ if (m_typeResolver)
+ r.inferredType = m_typeResolver(nullptr, name);
+
return r;
}
@@ -4118,9 +4125,9 @@ Codegen::Reference Codegen::Reference::asLValue() const
}
}
-Codegen::Reference Codegen::Reference::storeConsumeAccumulator() const
+Codegen::Reference Codegen::Reference::storeConsumeAccumulator(Type *type) const
{
- storeAccumulator(); // it doesn't matter what happens here, just do it.
+ storeAccumulator(type); // it doesn't matter what happens here, just do it.
return Reference();
}
@@ -4219,7 +4226,7 @@ bool Codegen::Reference::storeWipesAccumulator() const
}
}
-void Codegen::Reference::storeAccumulator() const
+void Codegen::Reference::storeAccumulator(AST::Type *sourceType) const
{
if (isReferenceToConst) {
// throw a type error
@@ -4235,7 +4242,7 @@ void Codegen::Reference::storeAccumulator() const
codegen->bytecodeGenerator->addInstruction(throwException);
return;
}
- switch (type) {
+ switch (sourceType) {
case Super:
Q_UNREACHABLE();
return;
diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h
index 245448f6a1..be1c96077a 100644
--- a/src/qml/compiler/qv4codegen_p.h
+++ b/src/qml/compiler/qv4codegen_p.h
@@ -79,6 +79,8 @@ struct ControlFlow;
struct ControlFlowCatch;
struct ControlFlowFinally;
+using TypeResolver = std::function<QQmlJS::AST::Type *(QQmlJS::AST::Type *type, const QString &property)>;
+
class Q_QML_PRIVATE_EXPORT Codegen: protected QQmlJS::AST::Visitor
{
protected:
@@ -353,7 +355,7 @@ public:
Q_REQUIRED_RESULT Reference storeOnStack() const;
void storeOnStack(int tempIndex) const;
Q_REQUIRED_RESULT Reference storeRetainAccumulator() const;
- Reference storeConsumeAccumulator() const;
+ Reference storeConsumeAccumulator(AST::Type *type = nullptr) const;
Q_REQUIRED_RESULT Reference baseObject() const;
@@ -403,10 +405,11 @@ public:
bool stackSlotIsLocalOrArgument = false;
bool isVolatile = false;
bool global = false;
+ AST::Type *inferredType = nullptr;
Codegen *codegen = nullptr;
private:
- void storeAccumulator() const;
+ void storeAccumulator(AST::Type *sourceType = nullptr) const;
Reference doStoreOnStack(int tempIndex) const;
};
@@ -714,6 +717,7 @@ public:
m_globalNames = globalNames;
}
+ void setTypeResolver(TypeResolver resolver) { permitTypeAnnotations = true; m_typeResolver = resolver; }
protected:
friend class ScanFunctions;
@@ -738,6 +742,7 @@ protected:
bool functionEndsWithReturn = false;
bool _tailCallsAreAllowed = true;
bool permitTypeAnnotations = false;
+ TypeResolver m_typeResolver;
QSet<QString> m_globalNames;
ControlFlow *controlFlow = nullptr;
diff --git a/tests/auto/qml/v4misc/tst_v4misc.cpp b/tests/auto/qml/v4misc/tst_v4misc.cpp
index 2412ca7f92..c7ff30a541 100644
--- a/tests/auto/qml/v4misc/tst_v4misc.cpp
+++ b/tests/auto/qml/v4misc/tst_v4misc.cpp
@@ -29,6 +29,11 @@
#include <qtest.h>
#include <private/qv4instr_moth_p.h>
#include <private/qv4script_p.h>
+#include <private/qqmljslexer_p.h>
+#include <private/qqmljsparser_p.h>
+#include <private/qv4compiler_p.h>
+#include <private/qv4codegen_p.h>
+#include <private/qqmlirbuilder_p.h>
class tst_v4misc: public QObject
{
@@ -45,6 +50,8 @@ private slots:
void subClassing();
void nestingDepth();
+
+ void typePropagation();
};
void tst_v4misc::tdzOptimizations_data()
@@ -197,6 +204,65 @@ void tst_v4misc::nestingDepth()
}
}
+void tst_v4misc::typePropagation()
+{
+ using namespace QV4::Compiler;
+ using namespace QQmlJS;
+
+ const QString sourceCode = QStringLiteral("var x = globalValue.subObject.num");
+
+ Module module(/*debug*/false);
+ Engine ee, *engine = &ee;
+ Lexer lexer(engine);
+ lexer.setCode(sourceCode, /*line*/1, /*parseAsBinding*/false);
+ Parser parser(engine);
+
+ const bool parsed = parser.parseProgram();
+ QVERIFY(parsed);
+ using namespace AST;
+ Program *program = AST::cast<Program *>(parser.rootNode());
+ QV4::Compiler::JSUnitGenerator jsGenerator(&module);
+ Codegen cg(&jsGenerator, /*strictMode*/false);
+
+ auto *pool = ee.pool();
+
+ auto resolver = [pool](const Type *baseType, const QString &name) -> Type* {
+ if (baseType == nullptr) {
+ if (name == "globalValue") {
+ auto type = new (pool) UiQualifiedId(pool->newString("GlobalType"));
+ return new (pool) Type(type->finish());
+ }
+ return nullptr;
+ }
+
+ QString simpleBaseTypeName = baseType->typeId ? QmlIR::IRBuilder::asString(baseType->typeId) : QString();
+
+ if (simpleBaseTypeName == "GlobalType") {
+ if (name == "subObject") {
+ auto type = new (pool) UiQualifiedId(pool->newString("SubObjectType"));
+ return new (pool) Type(type->finish());
+ }
+ return nullptr;
+ }
+
+ if (simpleBaseTypeName == "SubObjectType") {
+ if (name == "num") {
+ auto type = new (pool) UiQualifiedId(pool->newString("Number"));
+ return new (pool) Type(type->finish());
+ }
+ }
+
+ return nullptr;
+ };
+
+ cg.setTypeResolver(resolver);
+
+ qputenv("QV4_SHOW_BYTECODE", "1");
+
+ cg.generateFromProgram("test.js", "test.js", sourceCode, program, &module);
+ QVERIFY(cg.errors().isEmpty());
+}
+
QTEST_MAIN(tst_v4misc);
#include "tst_v4misc.moc"