From 8bca56b1fa4ab8b282ae6491de25525c90aa9efe Mon Sep 17 00:00:00 2001
From: MikhailArkhipov <mikhaila@microsoft.com>
Date: Fri, 1 Mar 2019 09:51:05 -0800
Subject: [PATCH 01/11] Fix #668 (partial)

---
 .../Analyzer/Handlers/ConditionalHandler.cs    | 18 ------------------
 1 file changed, 18 deletions(-)

diff --git a/src/Analysis/Ast/Impl/Analyzer/Handlers/ConditionalHandler.cs b/src/Analysis/Ast/Impl/Analyzer/Handlers/ConditionalHandler.cs
index cb41801b9..b104acb94 100644
--- a/src/Analysis/Ast/Impl/Analyzer/Handlers/ConditionalHandler.cs
+++ b/src/Analysis/Ast/Impl/Analyzer/Handlers/ConditionalHandler.cs
@@ -66,24 +66,6 @@ public bool HandleIf(IfStatement node) {
                     someRecognized = true;
                 }
             }
-
-            // Handle basic check such as
-            // if isinstance(value, type):
-            //    return value
-            // by assigning type to the value unless clause is raising exception.
-            var ce = node.Tests.FirstOrDefault()?.Test as CallExpression;
-            if (ce?.Target is NameExpression ne && ne.Name == @"isinstance" && ce.Args.Count == 2) {
-                var nex = ce.Args[0].Expression as NameExpression;
-                var name = nex?.Name;
-                var typeName = (ce.Args[1].Expression as NameExpression)?.Name;
-                if (name != null && typeName != null) {
-                    var typeId = typeName.GetTypeId();
-                    if (typeId != BuiltinTypeId.Unknown) {
-                        var t = new PythonType(typeName, Module, string.Empty, LocationInfo.Empty, typeId);
-                        Eval.DeclareVariable(name, t, VariableSource.Declaration, nex);
-                    }
-                }
-            }
             return !someRecognized;
         }
 

From 7ffc9db4f0807314d4d36a8540380b988c26ee2e Mon Sep 17 00:00:00 2001
From: MikhailArkhipov <mikhaila@microsoft.com>
Date: Mon, 4 Mar 2019 16:43:30 -0800
Subject: [PATCH 02/11] Tests

---
 src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs | 10 ++++++++--
 src/Analysis/Ast/Impl/Modules/PythonModule.cs    | 12 ++++--------
 src/Analysis/Ast/Test/BasicTests.cs              | 14 ++++++++------
 3 files changed, 20 insertions(+), 16 deletions(-)

diff --git a/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs b/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs
index 205e64d01..a30c5a97b 100644
--- a/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs
+++ b/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs
@@ -227,8 +227,14 @@ private async Task AnalyzeAffectedEntriesAsync(IDependencyChainWalker<ModuleKey,
                     StartAnalysis(node, walker.Version, stopWatch, cancellationToken);
                 }
             }
-            
-            if (walker.MissingKeys.Where(k => !k.IsTypeshed).Count == 0) {
+
+            var count = walker.MissingKeys.Where(k => !k.IsTypeshed).Count;
+            _log?.Log(TraceEventType.Verbose, $"Walker count is {count}, missing keys:");
+            foreach (var key in walker.MissingKeys) {
+                _log?.Log(TraceEventType.Verbose, $"    Name: {key.Name}, Path: {key.FilePath}");
+            }
+
+            if (count == 0) {
                 Interlocked.Exchange(ref _runningTasks, 0);
                 _analysisCompleteEvent.Set();
             }
diff --git a/src/Analysis/Ast/Impl/Modules/PythonModule.cs b/src/Analysis/Ast/Impl/Modules/PythonModule.cs
index 7be31275e..ce6949fc5 100644
--- a/src/Analysis/Ast/Impl/Modules/PythonModule.cs
+++ b/src/Analysis/Ast/Impl/Modules/PythonModule.cs
@@ -111,6 +111,7 @@ internal PythonModule(ModuleCreationOptions creationOptions, IServiceContainer s
                 ContentState = State.Analyzed;
             }
             InitializeContent(creationOptions.Content);
+            Log?.Log(TraceEventType.Verbose, $"Created module: {Name} {FilePath}");
         }
 
         #region IPythonType
@@ -385,21 +386,16 @@ private void Parse(CancellationToken cancellationToken) {
                     _diagnosticsService?.Replace(Uri, _parseErrors);
                 }
 
-                ContentState = State.Parsed;
-            }
-
-            NewAst?.Invoke(this, EventArgs.Empty);
-
-            if (ContentState < State.Analyzing) {
                 ContentState = State.Analyzing;
 
+                Log?.Log(TraceEventType.Verbose, $"Enqueue: {Name} {FilePath}");
                 var analyzer = Services.GetService<IPythonAnalyzer>();
                 analyzer.EnqueueDocumentForAnalysis(this, ast, version, _allProcessingCts.Token);
-            }
 
-            lock (AnalysisLock) {
                 _parsingTask = null;
             }
+
+            NewAst?.Invoke(this, EventArgs.Empty);
         }
 
         private class CollectingErrorSink : ErrorSink {
diff --git a/src/Analysis/Ast/Test/BasicTests.cs b/src/Analysis/Ast/Test/BasicTests.cs
index 47d47b8cd..c8b64e2f2 100644
--- a/src/Analysis/Ast/Test/BasicTests.cs
+++ b/src/Analysis/Ast/Test/BasicTests.cs
@@ -75,12 +75,14 @@ public async Task ImportTest() {
 import sys
 x = sys.path
 ";
-            var analysis = await GetAnalysisAsync(code);
-            analysis.GlobalScope.Variables.Count.Should().Be(2);
-
-            analysis.Should()
-                .HaveVariable("sys").OfType(BuiltinTypeId.Module)
-                .And.HaveVariable("x").OfType(BuiltinTypeId.List);
+            for (var i = 0; i < 20; i++) {
+                var analysis = await GetAnalysisAsync(code);
+                analysis.GlobalScope.Variables.Count.Should().Be(2);
+
+                analysis.Should()
+                    .HaveVariable("sys").OfType(BuiltinTypeId.Module)
+                    .And.HaveVariable("x").OfType(BuiltinTypeId.List);
+            }
         }
 
         [TestMethod, Priority(0)]

From 6303c45f234ba1c40058520c8700f6815c303035 Mon Sep 17 00:00:00 2001
From: Mikhail Arkhipov <mikhaila@microsoft.com>
Date: Mon, 4 Mar 2019 18:11:48 -0800
Subject: [PATCH 03/11] Revert "Tests"

This reverts commit 7ffc9db4f0807314d4d36a8540380b988c26ee2e.
---
 src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs | 10 ++--------
 src/Analysis/Ast/Impl/Modules/PythonModule.cs    | 12 ++++++++----
 src/Analysis/Ast/Test/BasicTests.cs              | 14 ++++++--------
 3 files changed, 16 insertions(+), 20 deletions(-)

diff --git a/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs b/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs
index a30c5a97b..205e64d01 100644
--- a/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs
+++ b/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs
@@ -227,14 +227,8 @@ private async Task AnalyzeAffectedEntriesAsync(IDependencyChainWalker<ModuleKey,
                     StartAnalysis(node, walker.Version, stopWatch, cancellationToken);
                 }
             }
-
-            var count = walker.MissingKeys.Where(k => !k.IsTypeshed).Count;
-            _log?.Log(TraceEventType.Verbose, $"Walker count is {count}, missing keys:");
-            foreach (var key in walker.MissingKeys) {
-                _log?.Log(TraceEventType.Verbose, $"    Name: {key.Name}, Path: {key.FilePath}");
-            }
-
-            if (count == 0) {
+            
+            if (walker.MissingKeys.Where(k => !k.IsTypeshed).Count == 0) {
                 Interlocked.Exchange(ref _runningTasks, 0);
                 _analysisCompleteEvent.Set();
             }
diff --git a/src/Analysis/Ast/Impl/Modules/PythonModule.cs b/src/Analysis/Ast/Impl/Modules/PythonModule.cs
index ce6949fc5..7be31275e 100644
--- a/src/Analysis/Ast/Impl/Modules/PythonModule.cs
+++ b/src/Analysis/Ast/Impl/Modules/PythonModule.cs
@@ -111,7 +111,6 @@ internal PythonModule(ModuleCreationOptions creationOptions, IServiceContainer s
                 ContentState = State.Analyzed;
             }
             InitializeContent(creationOptions.Content);
-            Log?.Log(TraceEventType.Verbose, $"Created module: {Name} {FilePath}");
         }
 
         #region IPythonType
@@ -386,16 +385,21 @@ private void Parse(CancellationToken cancellationToken) {
                     _diagnosticsService?.Replace(Uri, _parseErrors);
                 }
 
+                ContentState = State.Parsed;
+            }
+
+            NewAst?.Invoke(this, EventArgs.Empty);
+
+            if (ContentState < State.Analyzing) {
                 ContentState = State.Analyzing;
 
-                Log?.Log(TraceEventType.Verbose, $"Enqueue: {Name} {FilePath}");
                 var analyzer = Services.GetService<IPythonAnalyzer>();
                 analyzer.EnqueueDocumentForAnalysis(this, ast, version, _allProcessingCts.Token);
+            }
 
+            lock (AnalysisLock) {
                 _parsingTask = null;
             }
-
-            NewAst?.Invoke(this, EventArgs.Empty);
         }
 
         private class CollectingErrorSink : ErrorSink {
diff --git a/src/Analysis/Ast/Test/BasicTests.cs b/src/Analysis/Ast/Test/BasicTests.cs
index c8b64e2f2..47d47b8cd 100644
--- a/src/Analysis/Ast/Test/BasicTests.cs
+++ b/src/Analysis/Ast/Test/BasicTests.cs
@@ -75,14 +75,12 @@ public async Task ImportTest() {
 import sys
 x = sys.path
 ";
-            for (var i = 0; i < 20; i++) {
-                var analysis = await GetAnalysisAsync(code);
-                analysis.GlobalScope.Variables.Count.Should().Be(2);
-
-                analysis.Should()
-                    .HaveVariable("sys").OfType(BuiltinTypeId.Module)
-                    .And.HaveVariable("x").OfType(BuiltinTypeId.List);
-            }
+            var analysis = await GetAnalysisAsync(code);
+            analysis.GlobalScope.Variables.Count.Should().Be(2);
+
+            analysis.Should()
+                .HaveVariable("sys").OfType(BuiltinTypeId.Module)
+                .And.HaveVariable("x").OfType(BuiltinTypeId.List);
         }
 
         [TestMethod, Priority(0)]

From 01781c0417b836768708eebaad825330d0b8c987 Mon Sep 17 00:00:00 2001
From: MikhailArkhipov <mikhaila@microsoft.com>
Date: Wed, 27 Mar 2019 16:03:02 -0700
Subject: [PATCH 04/11] Exp

---
 .../Ast/Impl/Analyzer/PythonAnalyzer.cs       | 48 +++++++++++++++++--
 .../Ast/Impl/Documents/DocumentBuffer.cs      | 16 +++----
 src/LanguageServer/Impl/Program.cs            |  2 +-
 3 files changed, 51 insertions(+), 15 deletions(-)

diff --git a/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs b/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs
index b627aa4f7..674dbe877 100644
--- a/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs
+++ b/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs
@@ -14,6 +14,7 @@
 // permissions and limitations under the License.
 
 using System;
+using System.Collections.Concurrent;
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.Linq;
@@ -55,6 +56,7 @@ public PythonAnalyzer(IServiceManager services) {
             _analysisRunningEvent.Set();
 
             _progress = new ProgressReporter(services.GetService<IProgressService>());
+            Task.Run(() => Worker()).DoNotWait();
         }
 
         public void Dispose() {
@@ -137,7 +139,7 @@ public void EnqueueDocumentForAnalysis(IPythonModule module, ImmutableArray<IPyt
             }
 
             if (entry.Invalidate(analysisDependencies, version, out var dependencies)) {
-                AnalyzeDocumentAsync(key, entry, dependencies, default).DoNotWait();
+                AnalyzeDocument(key, entry, dependencies, default);
             }
         }
 
@@ -159,7 +161,7 @@ public void EnqueueDocumentForAnalysis(IPythonModule module, PythonAst ast, int
             }
 
             if (entry.Invalidate(module, ast, bufferVersion, version, out var dependencies)) {
-                AnalyzeDocumentAsync(key, entry, dependencies, cancellationToken).DoNotWait();
+                AnalyzeDocument(key, entry, dependencies, cancellationToken);
             }
         }
 
@@ -177,8 +179,44 @@ public IReadOnlyList<DiagnosticsEntry> LintModule(IPythonModule module) {
             return linter.Lint(module.Analysis, _services);
         }
 
+        private readonly ConcurrentQueue<Action> _queue = new ConcurrentQueue<Action>();
+        private readonly ManualResetEventSlim _workAvailable = new ManualResetEventSlim(false);
+        private readonly ManualResetEventSlim _workerAvailable = new ManualResetEventSlim(true);
+        private readonly object _lock = new object();
+        private int _workerCount;
 
-        private async Task AnalyzeDocumentAsync(AnalysisModuleKey key, PythonAnalyzerEntry entry, ImmutableArray<AnalysisModuleKey> dependencies, CancellationToken cancellationToken) {
+        private void AnalyzeDocument(AnalysisModuleKey key, PythonAnalyzerEntry entry, ImmutableArray<AnalysisModuleKey> dependencies, CancellationToken cancellationToken) {
+            lock (_lock) {
+                _queue.Enqueue(() => DoAnalyzeDocument(key, entry, dependencies, cancellationToken));
+                _workAvailable.Set();
+            }
+        }
+
+        private void Worker() {
+            while(true) {
+                _workAvailable.Wait();
+                if (_queue.TryDequeue(out var action)) {
+                    _workerAvailable.Wait();
+                    lock (_lock) {
+                        _workerCount++;
+                        if (_workerCount > 4) {
+                            _workerAvailable.Reset();
+                        }
+                    }
+
+                    Task.Run(action).ContinueWith(t => {
+                        lock (_lock) {
+                            _workerCount--;
+                            _workerAvailable.Set();
+                        }
+                    });
+                } else {
+                    _workAvailable.Reset();
+                }
+            }
+        }
+
+        private void DoAnalyzeDocument(AnalysisModuleKey key, PythonAnalyzerEntry entry, ImmutableArray<AnalysisModuleKey> dependencies, CancellationToken cancellationToken) {
             _analysisCompleteEvent.Reset();
             _log?.Log(TraceEventType.Verbose, $"Analysis of {entry.Module.Name}({entry.Module.ModuleType}) queued");
 
@@ -213,7 +251,7 @@ private async Task AnalyzeDocumentAsync(AnalysisModuleKey key, PythonAnalyzerEnt
                         StartAnalysis(entry, walker.Version, cancellationToken);
                     }
 
-                    await waitForAnalysisTask;
+                    waitForAnalysisTask.Wait(cancellationToken);
                 }
 
                 int version;
@@ -239,7 +277,7 @@ private async Task AnalyzeDocumentAsync(AnalysisModuleKey key, PythonAnalyzerEnt
                 var remaining = originalRemaining;
                 try {
                     _log?.Log(TraceEventType.Verbose, $"Analysis version {walker.Version} of {originalRemaining} entries has started.");
-                    remaining = await AnalyzeAffectedEntriesAsync(walker, stopWatch, analysisToken);
+                    remaining = AnalyzeAffectedEntriesAsync(walker, stopWatch, analysisToken).GetAwaiter().GetResult();
                 } finally {
                     _analysisRunningEvent.Set();
                     stopWatch.Stop();
diff --git a/src/Analysis/Ast/Impl/Documents/DocumentBuffer.cs b/src/Analysis/Ast/Impl/Documents/DocumentBuffer.cs
index 7e042c1a3..4a386d6ba 100644
--- a/src/Analysis/Ast/Impl/Documents/DocumentBuffer.cs
+++ b/src/Analysis/Ast/Impl/Documents/DocumentBuffer.cs
@@ -21,22 +21,21 @@
 
 namespace Microsoft.Python.Analysis.Documents {
     internal sealed class DocumentBuffer {
-        private readonly StringBuilder _sb = new StringBuilder();
-        private string _cachedText;
+        private StringBuilder _sb;
+        private string _content;
 
         public int Version { get; private set; }
-        public string Text => _cachedText ?? (_cachedText = _sb.ToString());
+        public string Text => _content ?? (_content = _sb.ToString());
 
         public void Reset(int version, string content) {
             Version = version;
-            _sb.Clear();
-            if (!string.IsNullOrEmpty(content)) {
-                _sb.Append(content);
-            }
-            _cachedText = null;
+            _sb = null;
+            _content = content;
         }
 
         public void Update(IEnumerable<DocumentChange> changes) {
+            _sb = _sb ?? new StringBuilder(_content);
+            _content = null;
 
             var lastStart = int.MaxValue;
             var lineLoc = SplitLines(_sb).ToArray();
@@ -57,7 +56,6 @@ public void Update(IEnumerable<DocumentChange> changes) {
                 }
             }
             Version++;
-            _cachedText = null;
         }
 
         private static IEnumerable<NewLineLocation> SplitLines(StringBuilder text) {
diff --git a/src/LanguageServer/Impl/Program.cs b/src/LanguageServer/Impl/Program.cs
index 11348f518..2fefa03ba 100644
--- a/src/LanguageServer/Impl/Program.cs
+++ b/src/LanguageServer/Impl/Program.cs
@@ -13,7 +13,7 @@
 // See the Apache Version 2.0 License for specific language governing
 // permissions and limitations under the License.
 
-// #define WAIT_FOR_DEBUGGER
+#define WAIT_FOR_DEBUGGER
 
 using System;
 using System.Diagnostics;

From f544f8a19eeee582bd13c46e90f9b5f3985f88b8 Mon Sep 17 00:00:00 2001
From: Mikhail Arkhipov <mikhaila@microsoft.com>
Date: Wed, 27 Mar 2019 19:30:18 -0700
Subject: [PATCH 05/11] Limit concurrency

---
 src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs | 5 +++--
 src/LanguageServer/Impl/Program.cs               | 2 +-
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs b/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs
index 674dbe877..14d4c9a4d 100644
--- a/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs
+++ b/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs
@@ -193,13 +193,14 @@ private void AnalyzeDocument(AnalysisModuleKey key, PythonAnalyzerEntry entry, I
         }
 
         private void Worker() {
-            while(true) {
+            ThreadPool.GetMaxThreads(out var max, out _);
+            while (true) {
                 _workAvailable.Wait();
                 if (_queue.TryDequeue(out var action)) {
                     _workerAvailable.Wait();
                     lock (_lock) {
                         _workerCount++;
-                        if (_workerCount > 4) {
+                        if (_workerCount >= Environment.ProcessorCount) {
                             _workerAvailable.Reset();
                         }
                     }
diff --git a/src/LanguageServer/Impl/Program.cs b/src/LanguageServer/Impl/Program.cs
index 2fefa03ba..11348f518 100644
--- a/src/LanguageServer/Impl/Program.cs
+++ b/src/LanguageServer/Impl/Program.cs
@@ -13,7 +13,7 @@
 // See the Apache Version 2.0 License for specific language governing
 // permissions and limitations under the License.
 
-#define WAIT_FOR_DEBUGGER
+// #define WAIT_FOR_DEBUGGER
 
 using System;
 using System.Diagnostics;

From 01bd7196838a7a614bf59cbec0709c8cf300bdb5 Mon Sep 17 00:00:00 2001
From: Mikhail Arkhipov <mikhaila@microsoft.com>
Date: Wed, 27 Mar 2019 19:56:57 -0700
Subject: [PATCH 06/11] Concurrency limit

---
 src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs b/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs
index 14d4c9a4d..0671135ca 100644
--- a/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs
+++ b/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs
@@ -193,14 +193,14 @@ private void AnalyzeDocument(AnalysisModuleKey key, PythonAnalyzerEntry entry, I
         }
 
         private void Worker() {
-            ThreadPool.GetMaxThreads(out var max, out _);
+            var maxConcurrent = Math.Max(Environment.ProcessorCount / 2, 4);
             while (true) {
                 _workAvailable.Wait();
                 if (_queue.TryDequeue(out var action)) {
                     _workerAvailable.Wait();
                     lock (_lock) {
                         _workerCount++;
-                        if (_workerCount >= Environment.ProcessorCount) {
+                        if (_workerCount >= maxConcurrent) {
                             _workerAvailable.Reset();
                         }
                     }
@@ -377,7 +377,7 @@ private void Analyze(IDependencyChainNode<PythonAnalyzerEntry> node, IDependency
                 node.Commit();
                 _log?.Log(TraceEventType.Verbose, $"Analysis of {module.Name}({module.ModuleType}) failed.");
             } finally {
-                if(_version == walker.Version) {
+                if (_version == walker.Version) {
                     _progress.ReportRemaining(walker.Remaining);
                 }
                 Interlocked.Decrement(ref _runningTasks);

From 2f8e564e3bb1529c0349f88e37483e5e25e3f189 Mon Sep 17 00:00:00 2001
From: Mikhail Arkhipov <mikhaila@microsoft.com>
Date: Thu, 28 Mar 2019 07:20:20 -0700
Subject: [PATCH 07/11] Drop cache after analysis

---
 src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.cs | 2 ++
 src/Analysis/Ast/Impl/Analyzer/ModuleWalker.cs              | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.cs b/src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.cs
index 123afc63f..c1e7a455f 100644
--- a/src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.cs
+++ b/src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.cs
@@ -164,6 +164,8 @@ public IMember GetValueFromExpression(Expression expr, LookupOptions options) {
             return m;
         }
 
+        internal void ClearCache() => _scopeLookupCache.Clear();
+
         private IMember GetValueFromFormatSpecifier(FormatSpecifier formatSpecifier) {
             return new PythonFString(formatSpecifier.Unparsed, Interpreter, GetLoc(formatSpecifier));
         }
diff --git a/src/Analysis/Ast/Impl/Analyzer/ModuleWalker.cs b/src/Analysis/Ast/Impl/Analyzer/ModuleWalker.cs
index b8aa5144c..83b91e9eb 100644
--- a/src/Analysis/Ast/Impl/Analyzer/ModuleWalker.cs
+++ b/src/Analysis/Ast/Impl/Analyzer/ModuleWalker.cs
@@ -105,6 +105,8 @@ public void Complete() {
                     .Where(s => !string.IsNullOrEmpty(s))
                     .ToImmutableArray();
             }
+
+            Eval.ClearCache();
         }
 
         public IGlobalScope GlobalScope => Eval.GlobalScope;

From 4ad56bbdf1cf3cbe78a8b0b888b5cf2a976cbe03 Mon Sep 17 00:00:00 2001
From: MikhailArkhipov <mikhaila@microsoft.com>
Date: Thu, 28 Mar 2019 16:47:16 -0700
Subject: [PATCH 08/11] Fix regression

---
 src/Analysis/Ast/Impl/Documents/RunningDocumentTable.cs | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/Analysis/Ast/Impl/Documents/RunningDocumentTable.cs b/src/Analysis/Ast/Impl/Documents/RunningDocumentTable.cs
index 536075e0d..34d7b85c3 100644
--- a/src/Analysis/Ast/Impl/Documents/RunningDocumentTable.cs
+++ b/src/Analysis/Ast/Impl/Documents/RunningDocumentTable.cs
@@ -212,6 +212,9 @@ private DocumentEntry CreateDocument(ModuleCreationOptions mco) {
                     document = new CompiledBuiltinPythonModule(mco.ModuleName, mco.Stub, _services);
                     break;
                 case ModuleType.User:
+                    TryAddModulePath(mco);
+                    document = new PythonModule(mco, _services);
+                    break;
                 case ModuleType.Library when TryAddModulePath(mco):
                     document = new PythonModule(mco, _services);
                     break;

From 2a50eb9c158342810cca7a20755d3bc297130106 Mon Sep 17 00:00:00 2001
From: MikhailArkhipov <mikhaila@microsoft.com>
Date: Wed, 10 Apr 2019 11:00:35 -0700
Subject: [PATCH 09/11] Fix test

---
 src/Analysis/Ast/Impl/Analyzer/ModuleWalker.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/Analysis/Ast/Impl/Analyzer/ModuleWalker.cs b/src/Analysis/Ast/Impl/Analyzer/ModuleWalker.cs
index cda525e89..e04c4192f 100644
--- a/src/Analysis/Ast/Impl/Analyzer/ModuleWalker.cs
+++ b/src/Analysis/Ast/Impl/Analyzer/ModuleWalker.cs
@@ -120,7 +120,7 @@ private void HandleAllAppendExtend(CallExpression node) {
                 return;
             }
 
-            ExtendAll(node, values);
+            ExtendAll(me.Target, values);
         }
 
         private void ExtendAll(Node location, IPythonCollection values) {

From c94d37555c25849e67f789566c797236f2255105 Mon Sep 17 00:00:00 2001
From: MikhailArkhipov <mikhaila@microsoft.com>
Date: Wed, 1 May 2019 09:50:54 -0700
Subject: [PATCH 10/11] Add null check

---
 src/Analysis/Ast/Impl/Types/Location.cs | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/src/Analysis/Ast/Impl/Types/Location.cs b/src/Analysis/Ast/Impl/Types/Location.cs
index d875216ca..db4d0d442 100644
--- a/src/Analysis/Ast/Impl/Types/Location.cs
+++ b/src/Analysis/Ast/Impl/Types/Location.cs
@@ -28,9 +28,15 @@ public Location(IPythonModule module, IndexSpan indexSpan) {
         public IPythonModule Module { get; }
         public IndexSpan IndexSpan { get; }
 
-        public LocationInfo LocationInfo => Module?.Analysis?.Ast != null
-            ? new LocationInfo(Module.FilePath, Module.Uri, IndexSpan.ToSourceSpan(Module.Analysis?.Ast))
-            : LocationInfo.Empty;
+        public LocationInfo LocationInfo {
+            get {
+                var ast = Module?.Analysis.Ast;
+                if (ast != null && !string.IsNullOrEmpty(Module.FilePath) && Module.Uri != null) {
+                    return new LocationInfo(Module.FilePath, Module.Uri, IndexSpan.ToSourceSpan(ast));
+                }
+                return LocationInfo.Empty;
+            }
+        }
 
         public bool IsValid => Module != null;
 

From 0607ab40bc7b998c3d4058ac254c60bc6984957d Mon Sep 17 00:00:00 2001
From: MikhailArkhipov <mikhaila@microsoft.com>
Date: Wed, 1 May 2019 09:52:50 -0700
Subject: [PATCH 11/11] Null check

---
 src/Analysis/Ast/Impl/Types/Location.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/Analysis/Ast/Impl/Types/Location.cs b/src/Analysis/Ast/Impl/Types/Location.cs
index db4d0d442..8cc2540bf 100644
--- a/src/Analysis/Ast/Impl/Types/Location.cs
+++ b/src/Analysis/Ast/Impl/Types/Location.cs
@@ -31,7 +31,7 @@ public Location(IPythonModule module, IndexSpan indexSpan) {
         public LocationInfo LocationInfo {
             get {
                 var ast = Module?.Analysis.Ast;
-                if (ast != null && !string.IsNullOrEmpty(Module.FilePath) && Module.Uri != null) {
+                if (ast != null && !string.IsNullOrEmpty(Module?.FilePath) && Module?.Uri != null) {
                     return new LocationInfo(Module.FilePath, Module.Uri, IndexSpan.ToSourceSpan(ast));
                 }
                 return LocationInfo.Empty;