Skip to content
This repository was archived by the owner on Apr 14, 2022. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/Analysis/Ast/Impl/Types/ArgumentSet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using Microsoft.Python.Analysis.Analyzer;
using Microsoft.Python.Analysis.Diagnostics;
using Microsoft.Python.Analysis.Extensions;
Expand Down
17 changes: 12 additions & 5 deletions src/Analysis/Ast/Impl/Types/PythonClassType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ namespace Microsoft.Python.Analysis.Types {
[DebuggerDisplay("Class {Name}")]
internal class PythonClassType : PythonType, IPythonClassType, IPythonTemplateType, IEquatable<IPythonClassType> {
private static readonly string[] _classMethods = { "mro", "__dict__", @"__weakref__" };

private Dictionary<string, PythonClassType> _specificTypeCache;
private IPythonClassType _processing;
private List<IPythonType> _bases;
private IReadOnlyList<IPythonType> _mro;
Expand Down Expand Up @@ -350,19 +352,20 @@ public IPythonType CreateSpecificType(IArgumentSet args) {
}

// For still undefined parameters try matching passed types in order
for (var i = 0; i < args.Arguments.Count; i++) {
for (int i = 0, gtIndex = 0; i < args.Arguments.Count; i++) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parameter index does not always equal generic parameter index (consider self)

var arg = args.Arguments[i];
if (Equals(arg.Type)) {
continue;
continue; // Typically 'self'.
}

if (arg.Value is IMember member) {
var type = member.GetPythonType();
if (!type.IsUnknown()) {
var gtd = i < genericTypeDefinitions.Count ? genericTypeDefinitions[i] : null;
var gtd = gtIndex < genericTypeDefinitions.Count ? genericTypeDefinitions[gtIndex] : null;
if (gtd != null && !specificClassTypeParameters.ContainsKey(gtd.Name)) {
specificClassTypeParameters[gtd.Name] = type;
}
gtIndex++;
}
}
}
Expand All @@ -374,7 +377,11 @@ public IPythonType CreateSpecificType(IArgumentSet args) {
.ToArray();

var specificName = CodeFormatter.FormatSequence(Name, '[', specificTypes);
var classType = new PythonClassType(specificName, new Location(DeclaringModule));
_specificTypeCache = _specificTypeCache ?? new Dictionary<string, PythonClassType>();
if (_specificTypeCache.TryGetValue(specificName, out var classType)) {
return classType;
}
_specificTypeCache[specificName] = classType = new PythonClassType(specificName, new Location(DeclaringModule));

// Methods returning generic types need to know how to match generic
// parameter name to the actual supplied type.
Expand Down Expand Up @@ -487,7 +494,7 @@ private void SetClassMembers(PythonClassType classType, IArgumentSet args) {
// Functions handle generics internally upon the call to Call.
foreach (var m in members) {
switch (m.Value) {
case IPythonTemplateType tt: {
case IPythonTemplateType tt when tt.IsGeneric(): {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing when, see similar care below

var specificType = tt.CreateSpecificType(args);
classType.AddMember(m.Key, specificType, true);
break;
Expand Down
39 changes: 39 additions & 0 deletions src/Analysis/Ast/Test/ClassesTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
// See the Apache Version 2.0 License for specific language governing
// permissions and limitations under the License.

using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
Expand Down Expand Up @@ -595,5 +596,43 @@ def __init__(self):
.And.HaveVariable("e").OfType(BuiltinTypeId.Unknown)
.And.HaveVariable("f").OfType(BuiltinTypeId.Unknown);
}

[TestMethod, Priority(0)]
public async Task ProxyBase() {
const string code = @"
from weakref import proxy

class C0(): pass
class C1(C0): pass
class C2(C1): pass
class C3(C2): pass
class C4(C3): pass
class C5(C4): pass
class C6(C5): pass
class C7(C6): pass
class C8(C7): pass

class Test():
def __init__(self):
p = proxy(self)

F1 = C1
F2 = C2
F3 = C3
F4 = C4
F5 = C5
F6 = C6
F7 = C7
F8 = C8
";
// Verifies that analysis of the fragment completes in reasonable time.
// see https://github.com/microsoft/python-language-server/issues/1291.
var sw = Stopwatch.StartNew();
await GetAnalysisAsync(code);
sw.Stop();
// Desktop: product time is typically less few seconds second.
// Test run time: typically ~ 20 sec.
sw.ElapsedMilliseconds.Should().BeLessThan(60000);
}
}
}