diff options
author | Simon Hausmann <simon.hausmann@qt.io> | 2019-01-21 16:55:26 +0100 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@qt.io> | 2019-01-21 16:55:26 +0100 |
commit | 1e5851a1044ca609572789acbd6564b580351173 (patch) | |
tree | 1169fd61c995248f158e929417ae6cdf007f7663 | |
parent | ff52723122935a6ff778994ec6d185432ae137e9 (diff) | |
download | qtdeclarative-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.cpp | 19 | ||||
-rw-r--r-- | src/qml/compiler/qv4codegen_p.h | 9 | ||||
-rw-r--r-- | tests/auto/qml/v4misc/tst_v4misc.cpp | 66 |
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 = ⅇ + 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" |