diff --git a/src/libs/qmljs/qmljsbind.cpp b/src/libs/qmljs/qmljsbind.cpp
index 5a24ef84e5e0811886e06288b474d7322b7200f9..d1f0847c994fdc97a19777761ec6bc26d6d47528 100644
--- a/src/libs/qmljs/qmljsbind.cpp
+++ b/src/libs/qmljs/qmljsbind.cpp
@@ -29,6 +29,7 @@
 
 #include "parser/qmljsast_p.h"
 #include "qmljsbind.h"
+#include "qmljscheck.h"
 #include "qmljsdocument.h"
 
 #include <QtCore/QDir>
@@ -54,11 +55,12 @@ using namespace QmlJS::Interpreter;
     It allows AST to code model lookup through findQmlObject() and findFunctionScope().
 */
 
-Bind::Bind(Document *doc)
+Bind::Bind(Document *doc, QList<DiagnosticMessage> *messages)
     : _doc(doc),
       _currentObjectValue(0),
       _idEnvironment(0),
-      _rootObjectValue(0)
+      _rootObjectValue(0),
+      _diagnosticMessages(messages)
 {
     if (_doc)
         accept(_doc->ast());
@@ -68,7 +70,7 @@ Bind::~Bind()
 {
 }
 
-QList<Bind::ImportInfo> Bind::imports() const
+QList<ImportInfo> Bind::imports() const
 {
     return _imports;
 }
@@ -185,32 +187,44 @@ bool Bind::visit(AST::Program *)
 
 bool Bind::visit(UiImport *ast)
 {
-    ImportInfo info;
-    info.ast = ast;
+    ComponentVersion version;
+    ImportInfo::Type type = ImportInfo::InvalidImport;
+    QString name;
 
     if (ast->versionToken.isValid()) {
         const QString versionString = _doc->source().mid(ast->versionToken.offset, ast->versionToken.length);
         const int dotIdx = versionString.indexOf(QLatin1Char('.'));
         if (dotIdx != -1) {
-            info.version = ComponentVersion(versionString.left(dotIdx).toInt(),
-                                            versionString.mid(dotIdx + 1).toInt());
+            version = ComponentVersion(versionString.left(dotIdx).toInt(),
+                                       versionString.mid(dotIdx + 1).toInt());
+        } else {
+            _diagnosticMessages->append(
+                        errorMessage(ast->versionToken, tr("expected two numbers separated by a dot")));
         }
     }
 
     if (ast->importUri) {
-        info.type = ImportInfo::LibraryImport;
-        info.name = toString(ast->importUri, QLatin1Char('/'));
+        type = ImportInfo::LibraryImport;
+        name = toString(ast->importUri, QDir::separator());
+
+        if (!version.isValid()) {
+            _diagnosticMessages->append(
+                        errorMessage(ast, tr("package import requires a version number")));
+        }
     } else if (ast->fileName) {
-        const QFileInfo importFileInfo(_doc->path() + QLatin1Char('/') + ast->fileName->asString());
-        info.name = importFileInfo.absoluteFilePath();
+        const QFileInfo importFileInfo(_doc->path() + QDir::separator() + ast->fileName->asString());
+        name = importFileInfo.absoluteFilePath();
         if (importFileInfo.isFile())
-            info.type = ImportInfo::FileImport;
+            type = ImportInfo::FileImport;
         else if (importFileInfo.isDir())
-            info.type = ImportInfo::DirectoryImport;
-        else
-            info.type = ImportInfo::InvalidFileImport;
+            type = ImportInfo::DirectoryImport;
+        else {
+            _diagnosticMessages->append(
+                        errorMessage(ast, tr("file or directory not found")));
+            type = ImportInfo::UnknownFileImport;
+        }
     }
-    _imports += info;
+    _imports += ImportInfo(type, name, version, ast);
 
     return false;
 }
diff --git a/src/libs/qmljs/qmljsbind.h b/src/libs/qmljs/qmljsbind.h
index ddbfa5b1df3697c87febeadf46b8457f0aae3ef1..b5e779616b6b1d51ba834c68e4c823be648b2349 100644
--- a/src/libs/qmljs/qmljsbind.h
+++ b/src/libs/qmljs/qmljsbind.h
@@ -37,6 +37,7 @@
 #include <QtCore/QHash>
 #include <QtCore/QStringList>
 #include <QtCore/QSharedPointer>
+#include <QtCore/QCoreApplication>
 
 namespace QmlJS {
 
@@ -46,28 +47,13 @@ class Document;
 class QMLJS_EXPORT Bind: protected AST::Visitor
 {
     Q_DISABLE_COPY(Bind)
+    Q_DECLARE_TR_FUNCTIONS(QmlJS::Bind)
 
 public:
-    Bind(Document *doc);
+    Bind(Document *doc, QList<DiagnosticMessage> *messages);
     virtual ~Bind();
 
-    struct ImportInfo {
-        enum Type {
-            LibraryImport,
-            FileImport,
-            DirectoryImport,
-            InvalidFileImport // refers a file/directoy that wasn't found
-        };
-
-        Type type;
-        // LibraryImport: uri with '/' separator
-        // Other: absoluteFilePath
-        QString name;
-        ComponentVersion version;
-        AST::UiImport *ast;
-    };
-
-    QList<ImportInfo> imports() const;
+    QList<Interpreter::ImportInfo> imports() const;
 
     Interpreter::ObjectValue *idEnvironment() const;
     Interpreter::ObjectValue *rootObjectValue() const;
@@ -119,7 +105,9 @@ private:
     QHash<AST::FunctionDeclaration *, Interpreter::ObjectValue *> _functionScopes;
     QStringList _includedScripts;
 
-    QList<ImportInfo> _imports;
+    QList<Interpreter::ImportInfo> _imports;
+
+    QList<DiagnosticMessage> *_diagnosticMessages;
 };
 
 } // end of namespace Qml
diff --git a/src/libs/qmljs/qmljscheck.cpp b/src/libs/qmljs/qmljscheck.cpp
index 96d8d5e87cbb9264c9b5b97690a959ef426d2283..bcab73dcb8e1faae6238375b0a5117da65f5b64b 100644
--- a/src/libs/qmljs/qmljscheck.cpp
+++ b/src/libs/qmljs/qmljscheck.cpp
@@ -62,6 +62,20 @@ QColor QmlJS::toQColor(const QString &qmlColorString)
     return color;
 }
 
+SourceLocation QmlJS::locationFromRange(const SourceLocation &start,
+                                        const SourceLocation &end)
+{
+    return SourceLocation(start.offset,
+                          end.end() - start.begin(),
+                          start.startLine,
+                          start.startColumn);
+}
+
+DiagnosticMessage QmlJS::errorMessage(const AST::SourceLocation &loc, const QString &message)
+{
+    return DiagnosticMessage(DiagnosticMessage::Error, loc, message);
+}
+
 namespace {
 
 class AssignmentCheck : public ValueVisitor
@@ -371,12 +385,3 @@ void Check::warning(const AST::SourceLocation &loc, const QString &message)
 {
     _messages.append(DiagnosticMessage(DiagnosticMessage::Warning, loc, message));
 }
-
-SourceLocation Check::locationFromRange(const SourceLocation &start,
-                                        const SourceLocation &end)
-{
-    return SourceLocation(start.offset,
-                          end.end() - start.begin(),
-                          start.startLine,
-                          start.startColumn);
-}
diff --git a/src/libs/qmljs/qmljscheck.h b/src/libs/qmljs/qmljscheck.h
index 3015987dc73e4087dbe9ce055a3a25d01cd0edef..049b197e5f9b53a239b0990752bd7c57f4055e29 100644
--- a/src/libs/qmljs/qmljscheck.h
+++ b/src/libs/qmljs/qmljscheck.h
@@ -64,8 +64,6 @@ private:
 
     void warning(const AST::SourceLocation &loc, const QString &message);
     void error(const AST::SourceLocation &loc, const QString &message);
-    static AST::SourceLocation locationFromRange(const AST::SourceLocation &start,
-                                                 const AST::SourceLocation &end);
 
     Document::Ptr _doc;
     Snapshot _snapshot;
@@ -80,6 +78,20 @@ private:
 
 QMLJS_EXPORT QColor toQColor(const QString &qmlColorString);
 
+QMLJS_EXPORT AST::SourceLocation locationFromRange(const AST::SourceLocation &start,
+                                                   const AST::SourceLocation &end);
+QMLJS_EXPORT DiagnosticMessage errorMessage(const AST::SourceLocation &loc,
+                                            const QString &message);
+
+template <class T>
+DiagnosticMessage errorMessage(const T *node, const QString &message)
+{
+    return DiagnosticMessage(DiagnosticMessage::Error,
+                             locationFromRange(node->firstSourceLocation(),
+                                               node->lastSourceLocation()),
+                             message);
+}
+
 } // namespace QmlJS
 
 #endif // QMLJSCHECK_H
diff --git a/src/libs/qmljs/qmljsdocument.cpp b/src/libs/qmljs/qmljsdocument.cpp
index c1d9d7f3cbe0546217e9476a785ade807e48eee5..75379474f2efa2f758dc8a74033f3b164b94b0e0 100644
--- a/src/libs/qmljs/qmljsdocument.cpp
+++ b/src/libs/qmljs/qmljsdocument.cpp
@@ -236,7 +236,7 @@ bool Document::parse_helper(int startToken)
     _ast = parser.rootNode();
     _diagnosticMessages = parser.diagnosticMessages();
 
-    _bind = new Bind(this);
+    _bind = new Bind(this, &_diagnosticMessages);
 
     return _parsedCorrectly;
 }
diff --git a/src/libs/qmljs/qmljsinterpreter.cpp b/src/libs/qmljs/qmljsinterpreter.cpp
index ddf0ed993bceb3ff59731672c4563b2f92f042c1..ff32bb517bfb84a02316562d44afc67e5cffb3e1 100644
--- a/src/libs/qmljs/qmljsinterpreter.cpp
+++ b/src/libs/qmljs/qmljsinterpreter.cpp
@@ -32,7 +32,6 @@
 #include "qmljslink.h"
 #include "qmljsbind.h"
 #include "qmljsscopebuilder.h"
-#include "qmljscomponentversion.h"
 #include "parser/qmljsast_p.h"
 
 #include <QtCore/QFile>
@@ -1448,14 +1447,14 @@ ScopeChain &Context::scopeChain()
     return _scopeChain;
 }
 
-const ObjectValue *Context::typeEnvironment(const QmlJS::Document *doc) const
+const TypeEnvironment *Context::typeEnvironment(const QmlJS::Document *doc) const
 {
     if (!doc)
         return 0;
     return _typeEnvironments.value(doc->fileName(), 0);
 }
 
-void Context::setTypeEnvironment(const QmlJS::Document *doc, const ObjectValue *typeEnvironment)
+void Context::setTypeEnvironment(const QmlJS::Document *doc, const TypeEnvironment *typeEnvironment)
 {
     if (!doc)
         return;
@@ -3097,3 +3096,134 @@ const Value *ASTSignalReference::value(const Context *) const
 {
     return engine()->undefinedValue();
 }
+
+ImportInfo::ImportInfo()
+    : _type(InvalidImport)
+    , _ast(0)
+{
+}
+
+ImportInfo::ImportInfo(Type type, const QString &name,
+                       QmlJS::ComponentVersion version, UiImport *ast)
+    : _type(type)
+    , _name(name)
+    , _version(version)
+    , _ast(ast)
+{
+}
+
+bool ImportInfo::isValid() const
+{
+    return _type != InvalidImport;
+}
+
+ImportInfo::Type ImportInfo::type() const
+{
+    return _type;
+}
+
+QString ImportInfo::name() const
+{
+    return _name;
+}
+
+QString ImportInfo::id() const
+{
+    if (_ast && _ast->importId)
+        return _ast->importId->asString();
+    return QString();
+}
+
+QmlJS::ComponentVersion ImportInfo::version() const
+{
+    return _version;
+}
+
+UiImport *ImportInfo::ast() const
+{
+    return _ast;
+}
+
+TypeEnvironment::TypeEnvironment(Engine *engine)
+    : ObjectValue(engine)
+{
+}
+
+const Value *TypeEnvironment::lookupMember(const QString &name, const Context *context, bool) const
+{
+    QHashIterator<const ObjectValue *, ImportInfo> it(_imports);
+    while (it.hasNext()) {
+        it.next();
+        const ObjectValue *import = it.key();
+        const ImportInfo &info = it.value();
+
+        if (!info.id().isEmpty()) {
+            if (info.id() == name)
+                return import;
+            continue;
+        }
+
+        if (info.type() == ImportInfo::FileImport) {
+            if (import->className() == name)
+                return import;
+        } else {
+            if (const Value *v = import->property(name, context))
+                return v;
+        }
+    }
+    return 0;
+}
+
+void TypeEnvironment::processMembers(MemberProcessor *processor) const
+{
+    QHashIterator<const ObjectValue *, ImportInfo> it(_imports);
+    while (it.hasNext()) {
+        it.next();
+        const ObjectValue *import = it.key();
+        const ImportInfo &info = it.value();
+
+        if (!info.id().isEmpty()) {
+            processor->processProperty(info.id(), import);
+        } else {
+            if (info.type() == ImportInfo::FileImport)
+                processor->processProperty(import->className(), import);
+            else
+                import->processMembers(processor);
+        }
+    }
+}
+
+void TypeEnvironment::addImport(const ObjectValue *import, const ImportInfo &info)
+{
+    _imports.insert(import, info);
+}
+
+ImportInfo TypeEnvironment::importInfo(const QString &name, const Context *context) const
+{
+    QString firstId = name;
+    int dotIdx = firstId.indexOf(QLatin1Char('.'));
+    if (dotIdx != -1)
+        firstId = firstId.left(dotIdx);
+
+    QHashIterator<const ObjectValue *, ImportInfo> it(_imports);
+    while (it.hasNext()) {
+        it.next();
+        const ObjectValue *import = it.key();
+        const ImportInfo &info = it.value();
+
+        if (!info.id().isEmpty()) {
+            if (info.id() == firstId)
+                return info;
+            continue;
+        }
+
+        if (info.type() == ImportInfo::FileImport) {
+            if (import->className() == firstId)
+                return info;
+        } else {
+            if (import->property(firstId, context))
+                return info;
+        }
+    }
+    return ImportInfo();
+}
diff --git a/src/libs/qmljs/qmljsinterpreter.h b/src/libs/qmljs/qmljsinterpreter.h
index 208ed034e00ad0cd0574feffc0f39cf8506e1dd3..f6c7086fb181ee3f3d5a7ce5db8177da40a370bf 100644
--- a/src/libs/qmljs/qmljsinterpreter.h
+++ b/src/libs/qmljs/qmljsinterpreter.h
@@ -63,6 +63,7 @@ class FunctionValue;
 class Reference;
 class ColorValue;
 class AnchorLineValue;
+class TypeEnvironment;
 
 typedef QList<const Value *> ValueList;
 
@@ -259,7 +260,7 @@ public:
     const ObjectValue *globalScope;
     QSharedPointer<const QmlComponentChain> qmlComponentScope;
     QList<const ObjectValue *> qmlScopeObjects;
-    const ObjectValue *qmlTypes;
+    const TypeEnvironment *qmlTypes;
     QList<const ObjectValue *> jsScopes;
 
     // rebuilds the flat list of all scopes
@@ -280,8 +281,8 @@ public:
     const ScopeChain &scopeChain() const;
     ScopeChain &scopeChain();
 
-    const ObjectValue *typeEnvironment(const Document *doc) const;
-    void setTypeEnvironment(const Document *doc, const ObjectValue *typeEnvironment);
+    const TypeEnvironment *typeEnvironment(const Document *doc) const;
+    void setTypeEnvironment(const Document *doc, const TypeEnvironment *typeEnvironment);
 
     const Value *lookup(const QString &name) const;
     const ObjectValue *lookupType(const Document *doc, AST::UiQualifiedId *qmlTypeName) const;
@@ -298,7 +299,7 @@ private:
 
     QSharedPointer<Engine> _engine;
     QHash<const ObjectValue *, Properties> _properties;
-    QHash<QString, const ObjectValue *> _typeEnvironments;
+    QHash<QString, const TypeEnvironment *> _typeEnvironments;
     ScopeChain _scopeChain;
     int _qmlScopeObjectIndex;
     bool _qmlScopeObjectSet;
@@ -846,6 +847,57 @@ public:
     QString defaultPropertyName() const;
 };
 
+class QMLJS_EXPORT ImportInfo
+{
+public:
+    enum Type {
+        InvalidImport,
+        ImplicitDirectoryImport,
+        LibraryImport,
+        FileImport,
+        DirectoryImport,
+        UnknownFileImport // refers a file/directoy that wasn't found
+    };
+
+    ImportInfo();
+    ImportInfo(Type type, const QString &name,
+               ComponentVersion version = ComponentVersion(),
+               AST::UiImport *ast = 0);
+
+    bool isValid() const;
+    Type type() const;
+
+    // LibraryImport: uri with '/' separator
+    // Other: absoluteFilePath
+    QString name() const;
+
+    // null if the import has no 'as', otherwise the target id
+    QString id() const;
+
+    ComponentVersion version() const;
+    AST::UiImport *ast() const;
+
+private:
+    Type _type;
+    QString _name;
+    ComponentVersion _version;
+    AST::UiImport *_ast;
+};
+
+class QMLJS_EXPORT TypeEnvironment: public ObjectValue
+{
+    QHash<const ObjectValue *, ImportInfo> _imports;
+
+public:
+    TypeEnvironment(Engine *engine);
+
+    virtual const Value *lookupMember(const QString &name, const Context *context, bool examinePrototypes) const;
+    virtual void processMembers(MemberProcessor *processor) const;
+
+    void addImport(const ObjectValue *import, const ImportInfo &info);
+    ImportInfo importInfo(const QString &name, const Context *context) const;
+};
+
 } } // end of namespace QmlJS::Interpreter
 
 #endif // QMLJS_INTERPRETER_H
diff --git a/src/libs/qmljs/qmljslink.cpp b/src/libs/qmljs/qmljslink.cpp
index 583a884f78fa356655de2e4fddfe520554d48f53..a8a971308dde728bccdd3b443765ccfc302af339 100644
--- a/src/libs/qmljs/qmljslink.cpp
+++ b/src/libs/qmljs/qmljslink.cpp
@@ -32,6 +32,7 @@
 #include "parser/qmljsast_p.h"
 #include "qmljsdocument.h"
 #include "qmljsbind.h"
+#include "qmljscheck.h"
 #include "qmljsscopebuilder.h"
 #include "qmljsmodelmanagerinterface.h"
 
@@ -43,6 +44,52 @@ using namespace QmlJS;
 using namespace QmlJS::Interpreter;
 using namespace QmlJS::AST;
 
+namespace {
+class ImportCacheKey
+{
+public:
+    explicit ImportCacheKey(const Interpreter::ImportInfo &info)
+        : type(info.type())
+        , name(info.name())
+        , majorVersion(info.version().majorVersion())
+        , minorVersion(info.version().minorVersion())
+    {}
+
+    int type;
+    QString name;
+    int majorVersion;
+    int minorVersion;
+};
+
+uint qHash(const ImportCacheKey &info)
+{
+    return ::qHash(info.type) ^ ::qHash(info.name) ^
+            ::qHash(info.majorVersion) ^ ::qHash(info.minorVersion);
+}
+
+bool operator==(const ImportCacheKey &i1, const ImportCacheKey &i2)
+{
+    return i1.type == i2.type
+            && i1.name == i2.name
+            && i1.majorVersion == i2.majorVersion
+            && i1.minorVersion == i2.minorVersion;
+}
+}
+
+
+class QmlJS::LinkPrivate
+{
+public:
+    Document::Ptr doc;
+    Snapshot snapshot;
+    Interpreter::Context *context;
+    QStringList importPaths;
+
+    QHash<ImportCacheKey, Interpreter::ObjectValue *> importCache;
+
+    QList<DiagnosticMessage> diagnosticMessages;
+};
+
 /*!
     \class QmlJS::Link
     \brief Initializes the Context for a Document.
@@ -58,11 +105,14 @@ using namespace QmlJS::AST;
 
 Link::Link(Context *context, const Document::Ptr &doc, const Snapshot &snapshot,
            const QStringList &importPaths)
-    : _doc(doc)
-    , _snapshot(snapshot)
-    , _context(context)
-    , _importPaths(importPaths)
+    : d_ptr(new LinkPrivate)
 {
+    Q_D(Link);
+    d->context = context;
+    d->doc = doc;
+    d->snapshot = snapshot;
+    d->importPaths = importPaths;
+
     linkImports();
     initializeScopeChain();
 }
@@ -73,42 +123,46 @@ Link::~Link()
 
 Interpreter::Engine *Link::engine()
 {
-    return _context->engine();
+    Q_D(Link);
+    return d->context->engine();
 }
 
 QList<DiagnosticMessage> Link::diagnosticMessages() const
 {
-    return _diagnosticMessages;
+    Q_D(const Link);
+    return d->diagnosticMessages;
 }
 
 void Link::initializeScopeChain()
 {
-    ScopeChain &scopeChain = _context->scopeChain();
+    Q_D(Link);
+
+    ScopeChain &scopeChain = d->context->scopeChain();
 
     // ### TODO: This object ought to contain the global namespace additions by QML.
     scopeChain.globalScope = engine()->globalObject();
 
-    if (! _doc) {
+    if (! d->doc) {
         scopeChain.update();
         return;
     }
 
-    Bind *bind = _doc->bind();
+    Bind *bind = d->doc->bind();
     QHash<Document *, ScopeChain::QmlComponentChain *> componentScopes;
 
     ScopeChain::QmlComponentChain *chain = new ScopeChain::QmlComponentChain;
     scopeChain.qmlComponentScope = QSharedPointer<const ScopeChain::QmlComponentChain>(chain);
-    if (_doc->qmlProgram()) {
-        componentScopes.insert(_doc.data(), chain);
-        makeComponentChain(_doc, chain, &componentScopes);
+    if (d->doc->qmlProgram()) {
+        componentScopes.insert(d->doc.data(), chain);
+        makeComponentChain(d->doc, chain, &componentScopes);
 
-        if (const ObjectValue *typeEnvironment = _context->typeEnvironment(_doc.data()))
+        if (const TypeEnvironment *typeEnvironment = d->context->typeEnvironment(d->doc.data()))
             scopeChain.qmlTypes = typeEnvironment;
     } else {
         // add scope chains for all components that import this file
-        foreach (Document::Ptr otherDoc, _snapshot) {
-            foreach (const Bind::ImportInfo &fileImport, otherDoc->bind()->fileImports()) {
-                if (_doc->fileName() == fileImport.name) {
+        foreach (Document::Ptr otherDoc, d->snapshot) {
+            foreach (const ImportInfo &import, otherDoc->bind()->imports()) {
+                if (import.type() == ImportInfo::FileImport && d->doc->fileName() == import.name()) {
                     ScopeChain::QmlComponentChain *component = new ScopeChain::QmlComponentChain;
                     componentScopes.insert(otherDoc.data(), component);
                     chain->instantiatingComponents += component;
@@ -131,16 +185,18 @@ void Link::makeComponentChain(
         ScopeChain::QmlComponentChain *target,
         QHash<Document *, ScopeChain::QmlComponentChain *> *components)
 {
+    Q_D(Link);
+
     if (!doc->qmlProgram())
         return;
 
     Bind *bind = doc->bind();
 
     // add scopes for all components instantiating this one
-    foreach (Document::Ptr otherDoc, _snapshot) {
+    foreach (Document::Ptr otherDoc, d->snapshot) {
         if (otherDoc == doc)
             continue;
-        if (otherDoc->bind()->usesQmlPrototype(bind->rootObjectValue(), _context)) {
+        if (otherDoc->bind()->usesQmlPrototype(bind->rootObjectValue(), d->context)) {
             if (components->contains(otherDoc.data())) {
 //                target->instantiatingComponents += components->value(otherDoc.data());
             } else {
@@ -159,41 +215,62 @@ void Link::makeComponentChain(
 
 void Link::linkImports()
 {
-    foreach (Document::Ptr doc, _snapshot) {
-        ObjectValue *typeEnv = engine()->newObject(/*prototype =*/0); // ### FIXME
+    Q_D(Link);
 
-        // Populate the _typeEnvironment with imports.
-        populateImportedTypes(typeEnv, doc);
+    // do it on d->doc first, to make sure import errors are shown
+    TypeEnvironment *typeEnv = new TypeEnvironment(engine());
+    populateImportedTypes(typeEnv, d->doc);
+    d->context->setTypeEnvironment(d->doc.data(), typeEnv);
 
-        _context->setTypeEnvironment(doc.data(), typeEnv);
+    foreach (Document::Ptr doc, d->snapshot) {
+        if (doc == d->doc)
+            continue;
+
+        TypeEnvironment *typeEnv = new TypeEnvironment(engine());
+        populateImportedTypes(typeEnv, doc);
+        d->context->setTypeEnvironment(doc.data(), typeEnv);
     }
 }
 
-void Link::populateImportedTypes(Interpreter::ObjectValue *typeEnv, Document::Ptr doc)
+void Link::populateImportedTypes(TypeEnvironment *typeEnv, Document::Ptr doc)
 {
+    Q_D(Link);
+
     if (! (doc->qmlProgram() && doc->qmlProgram()->imports))
         return;
 
     // implicit imports:
     // qml files in the same directory are available without explicit imports
-    foreach (Document::Ptr otherDoc, _snapshot.documentsInDirectory(doc->path())) {
-        if (otherDoc == doc || !otherDoc->bind()->rootObjectValue())
-            continue;
-
-        typeEnv->setProperty(otherDoc->componentName(),
-                             otherDoc->bind()->rootObjectValue());
+    ImportInfo implcitImportInfo(ImportInfo::ImplicitDirectoryImport, doc->path());
+    ObjectValue *directoryImport = d->importCache.value(ImportCacheKey(implcitImportInfo));
+    if (!directoryImport) {
+        directoryImport = importFile(doc, implcitImportInfo);
+        if (directoryImport)
+            d->importCache.insert(ImportCacheKey(implcitImportInfo), directoryImport);
     }
-
-    // explicit imports, whether directories or files
-    for (UiImportList *it = doc->qmlProgram()->imports; it; it = it->next) {
-        if (! it->import)
-            continue;
-
-        if (it->import->fileName) {
-            importFile(typeEnv, doc, it->import);
-        } else if (it->import->importUri) {
-            importNonFile(typeEnv, doc, it->import);
+    if (directoryImport)
+        typeEnv->addImport(directoryImport, implcitImportInfo);
+
+    // explicit imports, whether directories, files or libraries
+    foreach (const ImportInfo &info, doc->bind()->imports()) {
+        ObjectValue *import = d->importCache.value(ImportCacheKey(info));
+        if (!import) {
+            switch (info.type()) {
+            case ImportInfo::FileImport:
+            case ImportInfo::DirectoryImport:
+                import = importFile(doc, info);
+                break;
+            case ImportInfo::LibraryImport:
+                import = importNonFile(doc, info);
+                break;
+            default:
+                break;
+            }
+            if (import)
+                d->importCache.insert(ImportCacheKey(info), import);
         }
+        if (import)
+            typeEnv->addImport(import, info);
     }
 }
 
@@ -205,61 +282,29 @@ void Link::populateImportedTypes(Interpreter::ObjectValue *typeEnv, Document::Pt
 
     import "http://www.ovi.com/" as Ovi
 */
-void Link::importFile(Interpreter::ObjectValue *typeEnv, Document::Ptr doc,
-                      AST::UiImport *import)
+ObjectValue *Link::importFile(Document::Ptr, const ImportInfo &importInfo)
 {
-    Q_UNUSED(doc)
-
-    if (!import->fileName)
-        return;
-
-    QString path = doc->path();
-    path += QLatin1Char('/');
-    path += import->fileName->asString();
-    path = QDir::cleanPath(path);
+    Q_D(Link);
 
-    ObjectValue *importNamespace = typeEnv;
-
-    // directory import
-    QList<Document::Ptr> documentsInDirectory = _snapshot.documentsInDirectory(path);
-    if (! documentsInDirectory.isEmpty()) {
-        if (import->importId) {
-            importNamespace = engine()->newObject(/*prototype =*/0);
-            typeEnv->setProperty(import->importId->asString(), importNamespace);
-        }
+    ObjectValue *import = 0;
+    const QString &path = importInfo.name();
 
+    if (importInfo.type() == ImportInfo::DirectoryImport
+            || importInfo.type() == ImportInfo::ImplicitDirectoryImport) {
+        import = new ObjectValue(engine());
+        const QList<Document::Ptr> &documentsInDirectory = d->snapshot.documentsInDirectory(path);
         foreach (Document::Ptr importedDoc, documentsInDirectory) {
             if (importedDoc->bind()->rootObjectValue()) {
                 const QString targetName = importedDoc->componentName();
-                importNamespace->setProperty(targetName, importedDoc->bind()->rootObjectValue());
+                import->setProperty(targetName, importedDoc->bind()->rootObjectValue());
             }
         }
+    } else if (importInfo.type() == ImportInfo::FileImport) {
+        Document::Ptr importedDoc = d->snapshot.document(path);
+        import = importedDoc->bind()->rootObjectValue();
     }
-    // file import
-    else if (Document::Ptr importedDoc = _snapshot.document(path)) {
-        if (importedDoc->bind()->rootObjectValue()) {
-            QString targetName;
-            if (import->importId) {
-                targetName = import->importId->asString();
-            } else {
-                targetName = importedDoc->componentName();
-            }
 
-            importNamespace->setProperty(targetName, importedDoc->bind()->rootObjectValue());
-        }
-    } else {
-        error(doc, import->fileNameToken,
-              tr("could not find file or directory"));
-    }
-}
-
-static SourceLocation locationFromRange(const SourceLocation &start,
-                                        const SourceLocation &end)
-{
-    return SourceLocation(start.offset,
-                          end.end() - start.begin(),
-                          start.startLine,
-                          start.startColumn);
+    return import;
 }
 
 /*
@@ -267,52 +312,24 @@ static SourceLocation locationFromRange(const SourceLocation &start,
   import Qt 4.6 as Xxx
   (import com.nokia.qt is the same as the ones above)
 */
-void Link::importNonFile(Interpreter::ObjectValue *typeEnv, Document::Ptr doc, AST::UiImport *import)
+ObjectValue *Link::importNonFile(Document::Ptr doc, const ImportInfo &importInfo)
 {
-    if (! import->importUri)
-        return;
-
-    ObjectValue *namespaceObject = 0;
-
-    if (import->importId) { // with namespace we insert an object in the type env. to hold the imported types
-        namespaceObject = engine()->newObject(/*prototype */ 0);
-        typeEnv->setProperty(import->importId->asString(), namespaceObject);
-
-    } else { // without namespace we insert all types directly into the type env.
-        namespaceObject = typeEnv;
-    }
+    Q_D(Link);
 
-    const QString packageName = Bind::toString(import->importUri, '.');
-    ComponentVersion version;
-
-    if (import->versionToken.isValid()) {
-        const QString versionString = doc->source().mid(import->versionToken.offset, import->versionToken.length);
-        const int dotIdx = versionString.indexOf(QLatin1Char('.'));
-        if (dotIdx == -1) {
-            error(doc, import->versionToken,
-                  tr("expected two numbers separated by a dot"));
-            return;
-        } else {
-            const int majorVersion = versionString.left(dotIdx).toInt();
-            const int minorVersion = versionString.mid(dotIdx + 1).toInt();
-            version = ComponentVersion(majorVersion, minorVersion);
-        }
-    } else {
-        error(doc, locationFromRange(import->firstSourceLocation(), import->lastSourceLocation()),
-              tr("package import requires a version number"));
-        return;
-    }
+    ObjectValue *import = new ObjectValue(engine());
+    const QString packageName = Bind::toString(importInfo.ast()->importUri, '.');
+    const ComponentVersion version = importInfo.version();
 
     bool importFound = false;
 
     // check the filesystem
-    const QString packagePath = Bind::toString(import->importUri, QDir::separator());
-    foreach (const QString &importPath, _importPaths) {
+    const QString &packagePath = importInfo.name();
+    foreach (const QString &importPath, d->importPaths) {
         QString libraryPath = importPath;
         libraryPath += QDir::separator();
         libraryPath += packagePath;
 
-        const LibraryInfo libraryInfo = _snapshot.libraryInfo(libraryPath);
+        const LibraryInfo libraryInfo = d->snapshot.libraryInfo(libraryPath);
         if (!libraryInfo.isValid())
             continue;
 
@@ -322,7 +339,7 @@ void Link::importNonFile(Interpreter::ObjectValue *typeEnv, Document::Ptr doc, A
             if (libraryInfo.metaObjects().isEmpty()) {
                 ModelManagerInterface *modelManager = ModelManagerInterface::instance();
                 if (modelManager)
-                    modelManager->loadPluginTypes(libraryPath, importPath, Bind::toString(import->importUri, QLatin1Char('.')));
+                    modelManager->loadPluginTypes(libraryPath, importPath, packageName);
             } else {
                 engine()->cppQmlTypes().load(engine(), libraryInfo.metaObjects());
             }
@@ -333,14 +350,16 @@ void Link::importNonFile(Interpreter::ObjectValue *typeEnv, Document::Ptr doc, A
             if (importedTypes.contains(component.typeName))
                 continue;
 
-            ComponentVersion componentVersion(component.majorVersion, component.minorVersion);
+            ComponentVersion componentVersion(component.majorVersion,
+                                              component.minorVersion);
             if (version < componentVersion)
                 continue;
 
             importedTypes.insert(component.typeName);
-            if (Document::Ptr importedDoc = _snapshot.document(libraryPath + QDir::separator() + component.fileName)) {
-                if (importedDoc->bind()->rootObjectValue())
-                    namespaceObject->setProperty(component.typeName, importedDoc->bind()->rootObjectValue());
+            if (Document::Ptr importedDoc = d->snapshot.document(
+                        libraryPath + QDir::separator() + component.fileName)) {
+                if (ObjectValue *v = importedDoc->bind()->rootObjectValue())
+                    import->setProperty(component.typeName, v);
             }
         }
 
@@ -350,15 +369,19 @@ void Link::importNonFile(Interpreter::ObjectValue *typeEnv, Document::Ptr doc, A
     // if there are cpp-based types for this package, use them too
     if (engine()->cppQmlTypes().hasPackage(packageName)) {
         importFound = true;
-        foreach (QmlObjectValue *object, engine()->cppQmlTypes().typesForImport(packageName, version)) {
-            namespaceObject->setProperty(object->className(), object);
+        foreach (QmlObjectValue *object,
+                 engine()->cppQmlTypes().typesForImport(packageName, version)) {
+            import->setProperty(object->className(), object);
         }
     }
 
     if (!importFound) {
-        error(doc, locationFromRange(import->firstSourceLocation(), import->lastSourceLocation()),
+        error(doc, locationFromRange(importInfo.ast()->firstSourceLocation(),
+                                     importInfo.ast()->lastSourceLocation()),
               tr("package not found"));
     }
+
+    return import;
 }
 
 UiQualifiedId *Link::qualifiedTypeNameId(Node *node)
@@ -373,6 +396,8 @@ UiQualifiedId *Link::qualifiedTypeNameId(Node *node)
 
 void Link::error(const Document::Ptr &doc, const AST::SourceLocation &loc, const QString &message)
 {
-    if (doc->fileName() == _doc->fileName())
-        _diagnosticMessages.append(DiagnosticMessage(DiagnosticMessage::Error, loc, message));
+    Q_D(Link);
+
+    if (doc->fileName() == d->doc->fileName())
+        d->diagnosticMessages.append(DiagnosticMessage(DiagnosticMessage::Error, loc, message));
 }
diff --git a/src/libs/qmljs/qmljslink.h b/src/libs/qmljs/qmljslink.h
index 54e85446aae6a414f313f0be71ba1198847af2f0..d81fcc509a61c8c3fa51e9cc1a7f9fb48ba4ea1a 100644
--- a/src/libs/qmljs/qmljslink.h
+++ b/src/libs/qmljs/qmljslink.h
@@ -42,12 +42,14 @@
 namespace QmlJS {
 
 class NameId;
+class LinkPrivate;
 
 /*
     Helper for building a context.
 */
 class QMLJS_EXPORT Link
 {
+    Q_DECLARE_PRIVATE(Link)
     Q_DECLARE_TR_FUNCTIONS(QmlJS::Link)
 
 public:
@@ -73,22 +75,15 @@ private:
     void linkImports();
     void initializeScopeChain();
 
-    void populateImportedTypes(Interpreter::ObjectValue *typeEnv, Document::Ptr doc);
-    void importFile(Interpreter::ObjectValue *typeEnv, Document::Ptr doc,
-                    AST::UiImport *import);
-    void importNonFile(Interpreter::ObjectValue *typeEnv, Document::Ptr doc,
-                       AST::UiImport *import);
+    void populateImportedTypes(Interpreter::TypeEnvironment *typeEnv, Document::Ptr doc);
+    Interpreter::ObjectValue *importFile(Document::Ptr doc, const Interpreter::ImportInfo &importInfo);
+    Interpreter::ObjectValue *importNonFile(Document::Ptr doc, const Interpreter::ImportInfo &importInfo);
     void importObject(Bind *bind, const QString &name, Interpreter::ObjectValue *object, NameId *targetNamespace);
 
     void error(const Document::Ptr &doc, const AST::SourceLocation &loc, const QString &message);
 
 private:
-    Document::Ptr _doc;
-    Snapshot _snapshot;
-    Interpreter::Context *_context;
-    const QStringList _importPaths;
-
-    QList<DiagnosticMessage> _diagnosticMessages;
+    QScopedPointer<LinkPrivate> d_ptr;
 };
 
 } // namespace QmlJS
diff --git a/src/plugins/qmljseditor/qmljseditor.cpp b/src/plugins/qmljseditor/qmljseditor.cpp
index ddfd9cfa5ac9e257f9d7b675a426c158988b77d7..de0f29823b4decc7523428be3c0739e6953dac6a 100644
--- a/src/plugins/qmljseditor/qmljseditor.cpp
+++ b/src/plugins/qmljseditor/qmljseditor.cpp
@@ -579,9 +579,9 @@ AST::Node *SemanticInfo::nodeUnderCursor(int pos) const
 
     const unsigned cursorPosition = pos;
 
-    foreach (const Bind::ImportInfo &import, document->bind()->imports()) {
-        if (importContainsCursor(import.ast, cursorPosition))
-            return import.ast;
+    foreach (const Interpreter::ImportInfo &import, document->bind()->imports()) {
+        if (importContainsCursor(import.ast(), cursorPosition))
+            return import.ast();
     }
 
     CollectASTNodes nodes;
@@ -1381,9 +1381,9 @@ TextEditor::BaseTextEditor::Link QmlJSTextEditor::findLinkAt(const QTextCursor &
 
     if (AST::UiImport *importAst = cast<AST::UiImport *>(node)) {
         // if it's a file import, link to the file
-        foreach (const Bind::ImportInfo &import, semanticInfo.document->bind()->imports()) {
-            if (import.ast == importAst && import.type == Bind::ImportInfo::FileImport) {
-                BaseTextEditor::Link link(import.name);
+        foreach (const Interpreter::ImportInfo &import, semanticInfo.document->bind()->imports()) {
+            if (import.ast() == importAst && import.type() == Interpreter::ImportInfo::FileImport) {
+                BaseTextEditor::Link link(import.name());
                 link.begin = importAst->firstSourceLocation().begin();
                 link.end = importAst->lastSourceLocation().end();
                 return link;
diff --git a/src/plugins/qmljseditor/qmljsmodelmanager.cpp b/src/plugins/qmljseditor/qmljsmodelmanager.cpp
index ae8e9752416d5e170e1487365e380db79f14f1e1..2dd2b256c2bc2a2d27abb4a84c03078e54842365 100644
--- a/src/plugins/qmljseditor/qmljsmodelmanager.cpp
+++ b/src/plugins/qmljseditor/qmljsmodelmanager.cpp
@@ -276,15 +276,16 @@ static void findNewFileImports(const Document::Ptr &doc, const Snapshot &snapsho
                         QStringList *importedFiles, QSet<QString> *scannedPaths)
 {
     // scan files and directories that are explicitly imported
-    foreach (const Bind::ImportInfo &import, doc->bind()->imports()) {
-        if (import.type == Bind::ImportInfo::FileImport) {
-            if (! snapshot.document(import.name))
-                *importedFiles += import.name;
-        } else if (import.type == Bind::ImportInfo::DirectoryImport) {
-            if (snapshot.documentsInDirectory(import.name).isEmpty()) {
-                if (! scannedPaths->contains(import.name)) {
-                    *importedFiles += qmlFilesInDirectory(import.name);
-                    scannedPaths->insert(import.name);
+    foreach (const Interpreter::ImportInfo &import, doc->bind()->imports()) {
+        const QString &importName = import.name();
+        if (import.type() == Interpreter::ImportInfo::FileImport) {
+            if (! snapshot.document(importName))
+                *importedFiles += importName;
+        } else if (import.type() == Interpreter::ImportInfo::DirectoryImport) {
+            if (snapshot.documentsInDirectory(importName).isEmpty()) {
+                if (! scannedPaths->contains(importName)) {
+                    *importedFiles += qmlFilesInDirectory(importName);
+                    scannedPaths->insert(importName);
                 }
             }
         }
@@ -297,12 +298,12 @@ static void findNewLibraryImports(const Document::Ptr &doc, const Snapshot &snap
 {
     // scan library imports
     const QStringList importPaths = modelManager->importPaths();
-    foreach (const Bind::ImportInfo &import, doc->bind()->imports()) {
-        if (import.type != Bind::ImportInfo::LibraryImport)
+    foreach (const Interpreter::ImportInfo &import, doc->bind()->imports()) {
+        if (import.type() != Interpreter::ImportInfo::LibraryImport)
             continue;
         foreach (const QString &importPath, importPaths) {
             QDir dir(importPath);
-            dir.cd(import.name);
+            dir.cd(import.name());
             const QString targetPath = dir.absolutePath();
 
             // if we know there is a library, done