Skip to content
This repository was archived by the owner on Apr 14, 2022. It is now read-only.

Commit b2c9afb

Browse files
author
Mikhail Arkhipov
authored
Merge master into database branch (#1312)
* Remove old qualified name * Node storage * Class and scope to use AST map * Library analysis * Fix SO * Keep small AST with imports * AST reduction * Final field * Initial * Reload * Ignore post-final requests * Drop AST * Remove local variables * Test fixes * Fix overload match * Tests * Add locks * Remove local variables * Drop file content to save memory * Cache PEP hints * Recreate AST * Fix specialization * Fix locations * usings * Test fixes * Add options to keep data in memory * Fix test * Fix lambda parameters * Fix argument set Fix global scope node * Fix overload doc * Fix stub merge errors * Fix async issues * Undo some changes * Fix test * Fix race condition * Partial * Models and views * Restore log null checks * Fix merge conflict * Fix merge issue * Null check * Partial * Partial * Partial * Fix test * Partial * Partial * First test * Baseline comparison * Builtins * Partial * Type fixes * Fix type names, part I * Qualified name * Properly write variables * Partial * Construct module from model * Test * Variable creations * Factories * Factories * Split construction * Restore * Save builtins * Test passes * Qualified name * Better export detection * Test fixes * More consistent qualified names * Sys test * Demo * Complete sys write/read * Partial * Partial * Test staility * Perf bug * Baseline, remove debug code, deactivate db * Test fixes * Test fix * Simplify a bit * Baselines and use : separator * Baselines * PR feedback * Merge master * Remove registry reference * PR feedback * Avoid empty node in empty global scope (#1226) * Add null checks * Avoid null node in empty global scope * Remove unrelated change * Lock content since it is locked in other cases (#1227) * Fix addBrackets setting (#1241) * Fix addBrackets * Remove unrelated change * Usings * Handle library analysis better (#1246) * Trying to augment argument set with Evaluator and Expression context (#1259) * Moving anyStr to its own method to prevent FromTypeVar from being called with an ArgumentSet that has no context * Trying to augment argument set with context wherever possible * Setting expression in argument set, removing null * Renaming to WithoutContext and updating comment * Check for null args in PythonFunctionOverload * When returning in init method, report a diagnostic error (#1261) * When returning in init method, report a diagnostic error * Adding check and tests for returning None before adding error for a return statement in the init function * Cleaning up tests * Give Diagnostic messages on improper usage of Generic (#1248) * Adding diagnostic message for improper use Generic. * Adding tests to make sure no diagnostics on valid uses of Generic * Adding diagnostic error on binary operations with incompatible types (#1254) * Adding diagnostic error for binary operations with incompatible types - e.g 5 + 'str' * When NewType is called and the first argument is not a string, make a diagnostic message (#1260) * Adding diagnostic error if the user calls NewType with the first arg not of string type * Fix typo in TROUBLESHOOTING.md (#1285) * Multiple analysis fixes (#1297) Multiple analysis fixes. - Fixes #1151: Reliable way to determine final analysis of a module - Fixes #1201: NRE in SymbolCollector.AddProperty - Fixes #1228: NRE in TryFindMissingDependencies - Fixes #1294: Handle valid case for reloading AST - Fixes #1295: FindReferences doesn't work on package init members - Fixes #1296: DependencyResolver graph misses intermediate imports - Part of the fix for #1174: All references are not listed when using ms language server (fixes in analysis itself are also required for this one) * Rework search path resolution (#1289) * first working path classfier, breaks existing path code for now * inherit Comparer instead of implementing both * don't do path depth comparison, preserve user ordering as before * switch to using new path classification code in main module resolution * fix typo * clean up comment about paths in Server.cs * use String.Split instead of regex when parsing script output * test ordering of user provided paths * add new normalize and trim helper, check preconditions as debug asserts rather than commenting on them * use Split extension, don't MaybeEnumerate paths * No diagnostic message when Generic is called with no args (#1305) * No diagnostic message when Generic is called with no args * When a class inherits from something that is not a class, give a diagnostic error (#1277) * When analyzing class definitions, give diagnostic if bases are not all class types * PR feedback
1 parent 61d60c4 commit b2c9afb

File tree

89 files changed

+2429
-1006
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

89 files changed

+2429
-1006
lines changed

TROUBLESHOOTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ Python is a requirement for the language server to run. In VS Code, an interpret
2121
_must_ be selected in order for the language server to properly initialize. If your
2222
language server fails to start, be sure that you have selected an interpreter.
2323

24-
The language server can only run on platforms where the .NET Core can run. This rougly means:
24+
The language server can only run on platforms where the .NET Core can run. This roughly means:
2525

2626
- Windows, 32/64 bit
2727
- macOS, 64 bit

src/Analysis/Ast/Impl/Analyzer/ActivityTracker.cs

Lines changed: 4 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -19,48 +19,21 @@
1919

2020
namespace Microsoft.Python.Analysis.Analyzer {
2121
internal static class ActivityTracker {
22-
private static readonly Dictionary<string, AnalysisState> _modules = new Dictionary<string, AnalysisState>();
22+
private static readonly HashSet<string> _modules = new HashSet<string>();
2323
private static readonly object _lock = new object();
2424
private static bool _tracking;
2525
private static Stopwatch _sw;
2626

27-
private struct AnalysisState {
28-
public int Count;
29-
public bool IsComplete;
30-
}
31-
3227
public static void OnEnqueueModule(string path) {
3328
if (string.IsNullOrEmpty(path)) {
3429
return;
3530
}
3631

3732
lock (_lock) {
38-
if (!_modules.TryGetValue(path, out var st)) {
39-
_modules[path] = default;
40-
} else {
41-
st.IsComplete = false;
42-
}
43-
}
44-
}
45-
46-
public static void OnModuleAnalysisComplete(string path) {
47-
lock (_lock) {
48-
if (_modules.TryGetValue(path, out var st)) {
49-
st.Count++;
50-
st.IsComplete = true;
51-
}
33+
_modules.Add(path);
5234
}
5335
}
5436

55-
public static bool IsAnalysisComplete {
56-
get {
57-
lock (_lock) {
58-
return _modules.All(m => m.Value.IsComplete);
59-
}
60-
}
61-
}
62-
63-
6437
public static void StartTracking() {
6538
lock (_lock) {
6639
if (!_tracking) {
@@ -71,22 +44,15 @@ public static void StartTracking() {
7144
}
7245
}
7346

74-
public static void EndTracking() {
47+
public static (int modulesCount, double totalMilliseconds) EndTracking() {
7548
lock (_lock) {
7649
if (_tracking) {
7750
_sw?.Stop();
7851
_tracking = false;
7952
}
80-
}
81-
}
8253

83-
public static int ModuleCount {
84-
get {
85-
lock (_lock) {
86-
return _modules.Count;
87-
}
54+
return (_modules.Count, _sw?.Elapsed.TotalMilliseconds ?? 0);
8855
}
8956
}
90-
public static double MillisecondsElapsed => _sw?.Elapsed.TotalMilliseconds ?? 0;
9157
}
9258
}

src/Analysis/Ast/Impl/Analyzer/AnalysisModuleKey.cs

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,39 +15,56 @@
1515

1616
using System;
1717
using System.Diagnostics;
18+
using Microsoft.Python.Analysis.Documents;
1819
using Microsoft.Python.Analysis.Modules;
1920
using Microsoft.Python.Analysis.Types;
2021
using Microsoft.Python.Core;
2122

2223
namespace Microsoft.Python.Analysis.Analyzer {
2324
[DebuggerDisplay("{Name} : {FilePath}")]
24-
internal struct AnalysisModuleKey : IEquatable<AnalysisModuleKey> {
25+
internal readonly struct AnalysisModuleKey : IEquatable<AnalysisModuleKey> {
26+
private enum KeyType { Default, Typeshed, LibraryAsDocument }
27+
28+
private readonly KeyType _type;
2529
public string Name { get; }
2630
public string FilePath { get; }
27-
public bool IsTypeshed { get; }
31+
public bool IsTypeshed => _type == KeyType.Typeshed;
32+
public bool IsLibraryAsDocument => _type == KeyType.LibraryAsDocument;
2833

2934
public AnalysisModuleKey(IPythonModule module) {
3035
Name = module.Name;
3136
FilePath = module.ModuleType == ModuleType.CompiledBuiltin ? null : module.FilePath;
32-
IsTypeshed = module is StubPythonModule stub && stub.IsTypeshed;
37+
_type = module is StubPythonModule stub && stub.IsTypeshed
38+
? KeyType.Typeshed
39+
: module.ModuleType == ModuleType.Library && module is IDocument document && document.IsOpen
40+
? KeyType.LibraryAsDocument
41+
: KeyType.Default;
3342
}
3443

3544
public AnalysisModuleKey(string name, string filePath, bool isTypeshed) {
3645
Name = name;
3746
FilePath = filePath;
38-
IsTypeshed = isTypeshed;
47+
_type = isTypeshed ? KeyType.Typeshed : KeyType.Default;
48+
}
49+
50+
private AnalysisModuleKey(string name, string filePath, KeyType type) {
51+
Name = name;
52+
FilePath = filePath;
53+
_type = type;
3954
}
4055

56+
public AnalysisModuleKey GetLibraryAsDocumentKey() => new AnalysisModuleKey(Name, FilePath, KeyType.LibraryAsDocument);
57+
4158
public bool Equals(AnalysisModuleKey other)
42-
=> Name.EqualsOrdinal(other.Name) && FilePath.PathEquals(other.FilePath) && IsTypeshed == other.IsTypeshed;
59+
=> Name.EqualsOrdinal(other.Name) && FilePath.PathEquals(other.FilePath) && _type == other._type;
4360

4461
public override bool Equals(object obj) => obj is AnalysisModuleKey other && Equals(other);
4562

4663
public override int GetHashCode() {
4764
unchecked {
4865
var hashCode = (Name != null ? Name.GetHashCode() : 0);
4966
hashCode = (hashCode * 397) ^ (FilePath != null ? FilePath.GetPathHashCode() : 0);
50-
hashCode = (hashCode * 397) ^ IsTypeshed.GetHashCode();
67+
hashCode = (hashCode * 397) ^ _type.GetHashCode();
5168
return hashCode;
5269
}
5370
}

src/Analysis/Ast/Impl/Analyzer/Definitions/IAnalyzable.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ internal interface IAnalyzable {
2626
/// <summary>
2727
/// Notifies document that its analysis is now complete.
2828
/// </summary>
29-
void NotifyAnalysisComplete(int version, ModuleWalker walker, bool isFinalPass);
29+
/// <param name="analysis">Document analysis</param>
30+
void NotifyAnalysisComplete(IDocumentAnalysis analysis);
3031
}
3132
}

src/Analysis/Ast/Impl/Analyzer/Definitions/IPythonAnalyzer.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,15 @@
2020
using Microsoft.Python.Analysis.Diagnostics;
2121
using Microsoft.Python.Analysis.Types;
2222
using Microsoft.Python.Core.Collections;
23+
using Microsoft.Python.Parsing.Ast;
2324

2425
namespace Microsoft.Python.Analysis.Analyzer {
2526
public interface IPythonAnalyzer {
2627
Task WaitForCompleteAnalysisAsync(CancellationToken cancellationToken = default);
2728
/// <summary>
2829
/// Schedules module for analysis. Module will be scheduled if version of AST is greater than the one used to get previous analysis
2930
/// </summary>
30-
void EnqueueDocumentForAnalysis(IPythonModule module, int version);
31+
void EnqueueDocumentForAnalysis(IPythonModule module, PythonAst ast, int version);
3132

3233
/// <summary>
3334
/// Schedules module for analysis for its existing AST, but with new dependencies.

src/Analysis/Ast/Impl/Analyzer/EmptyAnalysis.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public EmptyAnalysis(IServiceContainer services, IDocument document) {
3030
Document = document ?? throw new ArgumentNullException(nameof(document));
3131
GlobalScope = new EmptyGlobalScope(document);
3232
Ast = AstUtilities.MakeEmptyAst(document.Uri);
33-
ExpressionEvaluator = new ExpressionEval(services, document);
33+
ExpressionEvaluator = new ExpressionEval(services, document, Ast);
3434
}
3535

3636
public IDocument Document { get; }

src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.Callables.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,11 @@ public IMember GetValueFromLambda(LambdaExpression expr) {
8989
public IMember GetValueFromClassCtor(IPythonClassType cls, CallExpression expr) {
9090
SymbolTable.Evaluate(cls.ClassDefinition);
9191
// Determine argument types
92-
var args = ArgumentSet.Empty;
92+
var args = ArgumentSet.Empty(expr, this);
9393
var init = cls.GetMember<IPythonFunctionType>(@"__init__");
9494
if (init != null) {
9595
using (OpenScope(cls.DeclaringModule, cls.ClassDefinition, out _)) {
96-
var a = new ArgumentSet(init, 0, new PythonInstance(cls), expr, Module, this);
96+
var a = new ArgumentSet(init, 0, new PythonInstance(cls), expr, this);
9797
if (a.Errors.Count > 0) {
9898
// AddDiagnostics(Module.Uri, a.Errors);
9999
}
@@ -108,7 +108,7 @@ private IMember GetValueFromBound(IPythonBoundType t, CallExpression expr) {
108108
case IPythonFunctionType fn:
109109
return GetValueFromFunctionType(fn, t.Self, expr);
110110
case IPythonPropertyType p:
111-
return GetValueFromProperty(p, t.Self);
111+
return GetValueFromProperty(p, t.Self, expr);
112112
case IPythonIteratorType _ when t.Self is IPythonCollection seq:
113113
return seq.GetIterator();
114114
}
@@ -201,10 +201,10 @@ public IMember GetValueFromFunctionType(IPythonFunctionType fn, IPythonInstance
201201
return UnknownType;
202202
}
203203

204-
private IMember GetValueFromProperty(IPythonPropertyType p, IPythonInstance instance) {
204+
private IMember GetValueFromProperty(IPythonPropertyType p, IPythonInstance instance, CallExpression expr) {
205205
// Function may not have been walked yet. Do it now.
206206
SymbolTable.Evaluate(p.FunctionDefinition);
207-
return instance.Call(p.Name, ArgumentSet.Empty);
207+
return instance.Call(p.Name, ArgumentSet.Empty(expr, this));
208208
}
209209

210210

src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.Generics.cs

Lines changed: 49 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,15 @@
1616
using System;
1717
using System.Collections.Generic;
1818
using System.Linq;
19+
using Microsoft.Python.Analysis.Diagnostics;
1920
using Microsoft.Python.Analysis.Specializations.Typing;
2021
using Microsoft.Python.Analysis.Specializations.Typing.Types;
2122
using Microsoft.Python.Analysis.Types;
2223
using Microsoft.Python.Analysis.Values;
2324
using Microsoft.Python.Core;
25+
using Microsoft.Python.Parsing;
2426
using Microsoft.Python.Parsing.Ast;
27+
using ErrorCodes = Microsoft.Python.Analysis.Diagnostics.ErrorCodes;
2528

2629
namespace Microsoft.Python.Analysis.Analyzer.Evaluation {
2730
internal sealed partial class ExpressionEval {
@@ -59,40 +62,58 @@ private IMember GetValueFromGeneric(IMember target, Expression expr) {
5962
}
6063

6164
/// <summary>
62-
/// Given generic type and list of indices in the expression like
63-
/// Generic[T1, T2, ...] or List[str] creates generic class base
64-
/// (if the former) on specific type (if the latter).
65+
/// Returns whether the arguments to Generic are valid
6566
/// </summary>
66-
private IMember CreateSpecificTypeFromIndex(IGenericType gt, IReadOnlyList<IMember> indices, Expression expr) {
67-
// See which ones are generic parameters as defined by TypeVar()
68-
// and which are specific types. Normally there should not be a mix.
69-
var genericTypeArgs = indices.OfType<IGenericTypeDefinition>().ToArray();
70-
var specificTypes = indices.Where(i => !(i is IGenericTypeDefinition)).OfType<IPythonType>().ToArray();
71-
72-
if (genericTypeArgs.Length > 0 && genericTypeArgs.Length != indices.Count) {
73-
// TODO: report that some type arguments are not declared with TypeVar.
67+
private bool GenericClassParameterValid(IReadOnlyList<IGenericTypeDefinition> genericTypeArgs, IReadOnlyList<IMember> args, Expression expr) {
68+
// All arguments to Generic must be type parameters
69+
// e.g. Generic[T, str] throws a runtime error
70+
if (genericTypeArgs.Count != args.Count) {
71+
ReportDiagnostics(Module.Uri, new DiagnosticsEntry(
72+
Resources.GenericNotAllTypeParameters,
73+
GetLocation(expr).Span,
74+
ErrorCodes.TypingGenericArguments,
75+
Severity.Error,
76+
DiagnosticSource.Analysis));
77+
return false;
7478
}
75-
if (specificTypes.Length > 0 && specificTypes.Length != indices.Count) {
76-
// TODO: report that arguments are not specific types or are not declared.
79+
80+
// All arguments to Generic must be distinct
81+
if (genericTypeArgs.Distinct().Count() != genericTypeArgs.Count) {
82+
ReportDiagnostics(Module.Uri, new DiagnosticsEntry(
83+
Resources.GenericNotAllUnique,
84+
GetLocation(expr).Span,
85+
ErrorCodes.TypingGenericArguments,
86+
Severity.Error,
87+
DiagnosticSource.Analysis));
88+
return false;
7789
}
7890

91+
return true;
92+
}
93+
94+
/// <summary>
95+
/// Given generic type and list of arguments in the expression like
96+
/// Generic[T1, T2, ...] or List[str] creates generic class base
97+
/// (if the former) on specific type (if the latter).
98+
/// </summary>
99+
private IMember CreateSpecificTypeFromIndex(IGenericType gt, IReadOnlyList<IMember> args, Expression expr) {
100+
var genericTypeArgs = args.OfType<IGenericTypeDefinition>().ToArray();
101+
79102
if (gt.Name.EqualsOrdinal("Generic")) {
80-
// Generic[T1, T2, ...] expression. Create generic base for the class.
81-
if (genericTypeArgs.Length > 0) {
82-
return new GenericClassParameter(genericTypeArgs, Module);
83-
} else {
84-
// TODO: report too few type arguments for Generic[].
103+
if (!GenericClassParameterValid(genericTypeArgs, args, expr)) {
85104
return UnknownType;
86105
}
106+
107+
// Generic[T1, T2, ...] expression. Create generic base for the class.
108+
return new GenericClassParameter(genericTypeArgs, Module);
87109
}
88110

89111
// For other types just use supplied arguments
90-
if (indices.Count > 0) {
91-
return gt.CreateSpecificType(new ArgumentSet(indices));
112+
if (args.Count > 0) {
113+
return gt.CreateSpecificType(new ArgumentSet(args, expr, this));
92114
}
93-
// TODO: report too few type arguments for the generic expression.
94-
return UnknownType;
95115

116+
return UnknownType;
96117
}
97118

98119
private IReadOnlyList<IMember> EvaluateIndex(IndexExpression expr) {
@@ -104,7 +125,10 @@ private IReadOnlyList<IMember> EvaluateIndex(IndexExpression expr) {
104125
}
105126
} else {
106127
var index = GetValueFromExpression(expr.Index);
107-
indices.Add(index ?? UnknownType);
128+
// Don't count null indexes as arguments
129+
if (index != null) {
130+
indices.Add(index);
131+
}
108132
}
109133
return indices;
110134
}
@@ -132,7 +156,7 @@ private IMember CreateClassInstance(PythonClassType cls, IReadOnlyList<IMember>
132156

133157
var argSet = initOverload != null
134158
? new ArgumentSet(initFunc, 0, null, callExpr, this)
135-
: new ArgumentSet(constructorArguments);
159+
: new ArgumentSet(constructorArguments, callExpr, this);
136160

137161
argSet.Evaluate();
138162
var specificType = cls.CreateSpecificType(argSet);
@@ -194,7 +218,7 @@ private static IReadOnlyList<IPythonType> GetSpecificTypeFromArgumentValue(objec
194218
var itemType = iter.GetIterator().Next.GetPythonType();
195219
if (!itemType.IsUnknown()) {
196220
specificTypes.Add(itemType);
197-
} else if(argumentValue is IPythonInstance inst) {
221+
} else if (argumentValue is IPythonInstance inst) {
198222
specificTypes.Add(inst.GetPythonType());
199223
}
200224
break;

0 commit comments

Comments
 (0)