From a022e3b2928f87bede157fa8785416a000588a6d Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Mon, 29 Oct 2018 13:12:59 -0700 Subject: [PATCH 1/8] Test --- src/Analysis/Engine/Test/AnalysisTest.cs | 59 +++++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/src/Analysis/Engine/Test/AnalysisTest.cs b/src/Analysis/Engine/Test/AnalysisTest.cs index 6e3f89bc9..ae5f98c72 100644 --- a/src/Analysis/Engine/Test/AnalysisTest.cs +++ b/src/Analysis/Engine/Test/AnalysisTest.cs @@ -4182,7 +4182,64 @@ public async Task PackageRelativeImportAliasedMember() { analysisPackage.Should().HaveVariable("y").OfTypes(BuiltinTypeId.Module, BuiltinTypeId.Function); } } - + + [TestMethod, Priority(0)] + public async Task GenericListBase() { + var code = @" +from typing import List + +def func(a: List[str]): + pass +"; + + using (var server = await CreateServerAsync(PythonVersions.LatestAvailable3X)) { + var analysis = await server.OpenDefaultDocumentAndGetAnalysisAsync(code); + analysis.Scope.Children + .OfType() + .First() + .Should().HaveVariable("a") + .OfTypes(BuiltinTypeId.List, BuiltinTypeId.Unknown); // list and 'function argument' + } + } + + [TestMethod, Priority(0)] + public async Task GenericDictBase() { + var code = @" +from typing import Dict + +def func(a: Dict[int, str]): + pass +"; + + using (var server = await CreateServerAsync(PythonVersions.LatestAvailable3X)) { + var analysis = await server.OpenDefaultDocumentAndGetAnalysisAsync(code); + analysis.Scope.Children + .OfType() + .First() + .Should().HaveVariable("a") + .OfTypes(BuiltinTypeId.Dict, BuiltinTypeId.Unknown); // dict and 'function argument' + } + } + + [TestMethod, Priority(0)] + public async Task NewType() { + var code = @" +from typing import NewType + +Foo = NewType('Foo', dict) +foo: Foo = Foo({ }) +"; + + using (var server = await CreateServerAsync(PythonVersions.LatestAvailable3X)) { + var analysis = await server.OpenDefaultDocumentAndGetAnalysisAsync(code); + analysis + .Should().HaveVariable("Foo") + .OfType(BuiltinTypeId.Type).WithDescription("Foo") + .And.HaveVariable("foo") + .OfType(BuiltinTypeId.Type).WithDescription("Foo"); + } + } + [TestMethod, Priority(0)] public async Task Defaults() { var text = @" From 711cbda99cb49e53ebb42eb29f3db1c3dfc738dc Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Mon, 29 Oct 2018 13:20:36 -0700 Subject: [PATCH 2/8] Add test --- src/Analysis/Engine/Test/CompletionTests.cs | 65 +++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/src/Analysis/Engine/Test/CompletionTests.cs b/src/Analysis/Engine/Test/CompletionTests.cs index b841af40e..c05e55630 100644 --- a/src/Analysis/Engine/Test/CompletionTests.cs +++ b/src/Analysis/Engine/Test/CompletionTests.cs @@ -1029,6 +1029,71 @@ public async Task MarkupKindValid() { } } + [TestMethod, Priority(0)] + public async Task NewType() { + var code = @" +from typing import NewType + +Foo = NewType('Foo', dict) +foo: Foo = Foo({ }) +foo. +"; + using (var server = await CreateServerAsync(PythonVersions.LatestAvailable3X)) { + var uri = await server.OpenDefaultDocumentAndGetUriAsync(code); + await server.GetAnalysisAsync(uri); + + var completions = await server.SendCompletion(uri, 5, 4); + completions.Should().HaveLabels("clear", "copy", "items", "keys", "update", "values"); + } + } + + [TestMethod, Priority(0)] + public async Task GenericListBase() { + var code = @" +from typing import List + +def func(a: List[str]): + a. + a[0]. + pass +"; + using (var server = await CreateServerAsync(PythonVersions.LatestAvailable3X)) { + var uri = await server.OpenDefaultDocumentAndGetUriAsync(code); + await server.GetAnalysisAsync(uri); + + var completions = await server.SendCompletion(uri, 4, 6); + completions.Should().HaveLabels("clear", "copy", "count", "index", "remove", "reverse"); + + completions = await server.SendCompletion(uri, 5, 9); + completions.Should().HaveLabels("capitalize"); + } + } + + [TestMethod, Priority(0)] + public async Task GenericDictBase() { + var code = @" +from typing import Dict + +def func(a: Dict[int, str]): + a. + a.keys[0]. + a.values[0]. + pass +"; + using (var server = await CreateServerAsync(PythonVersions.LatestAvailable3X)) { + var uri = await server.OpenDefaultDocumentAndGetUriAsync(code); + await server.GetAnalysisAsync(uri); + + var completions = await server.SendCompletion(uri, 4, 6); + completions.Should().HaveLabels("keys", "values"); + + completions = await server.SendCompletion(uri, 5, 14); + completions.Should().HaveLabels("bit_length"); + + completions = await server.SendCompletion(uri, 6, 17); + completions.Should().HaveLabels("capitalize"); + } + } private static async Task AssertCompletion(Server s, Uri uri, IReadOnlyCollection contains, IReadOnlyCollection excludes, Position? position = null, CompletionContext? context = null, Func cmpKey = null, string expr = null, Range? applicableSpan = null) { await s.WaitForCompleteAnalysisAsync(CancellationToken.None); var res = await s.Completion(new CompletionParams { From 4b29673b14963c17272245fc72b37b4d1ce4dfb5 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Mon, 29 Oct 2018 13:27:54 -0700 Subject: [PATCH 3/8] NewType fix --- src/Analysis/Engine/Impl/Values/Protocols.cs | 80 +++++++++++++++++++ .../Engine/Impl/Values/TypingModuleInfo.cs | 17 ++-- 2 files changed, 92 insertions(+), 5 deletions(-) diff --git a/src/Analysis/Engine/Impl/Values/Protocols.cs b/src/Analysis/Engine/Impl/Values/Protocols.cs index 7808f11b4..c3104b331 100644 --- a/src/Analysis/Engine/Impl/Values/Protocols.cs +++ b/src/Analysis/Engine/Impl/Values/Protocols.cs @@ -731,4 +731,84 @@ public InstanceProtocol(ProtocolInfo self, IReadOnlyList arguments internal override int UnionHashCode(int strength) => GetHashCode(); protected override Protocol UnionMergeTypes(Protocol p) => this; } + + /// + /// Generic protocol that delegates work to its inner class such as + /// List[T] has list as its base. Typically used in NewType and TypeVar + /// scenarios delegating calls to the actual class serving as new type. + /// + class GenericProtocol : Protocol { + protected readonly AnalysisValue _baseType; + + /// + /// Creates protocol that delegates to base type, such as generic list + /// provides methods from the plain list. + /// + /// Protocol info + /// Base type to delegate to, such as 'list'. + public GenericProtocol(ProtocolInfo self, AnalysisValue baseType) : base(self) { + _baseType = baseType; + } + + protected override bool Equals(Protocol other) => _baseType.Equals((other as GenericProtocol)._baseType); + + public override string Name => _baseType.Name; + public override string Documentation => _baseType.Documentation; + public override string Description => _baseType.Description; + public override string ShortDescription => _baseType.ShortDescription; + public override BuiltinTypeId TypeId => _baseType.TypeId; + public override PythonMemberType MemberType => _baseType.MemberType; + public override IEnumerable> GetRichDescription() + => _baseType is IHasRichDescription rd + ? rd.GetRichDescription() + : Enumerable.Empty>(); + + public override IPythonProjectEntry DeclaringModule => _baseType.DeclaringModule; + public override int DeclaringVersion => _baseType.DeclaringVersion; + public override IPythonType PythonType => _baseType.PythonType; + public override bool IsOfType(IAnalysisSet klass) => _baseType.IsOfType(klass); + public override bool IsAlive => _baseType.IsAlive; + + public override IDictionary GetAllMembers(IModuleContext moduleContext, GetMemberOptions options = GetMemberOptions.None) + => _baseType.GetAllMembers(moduleContext, options); + public override IAnalysisSet GetMember(Node node, AnalysisUnit unit, string name) => _baseType.GetMember(node, unit, name); + public override IAnalysisSet GetTypeMember(Node node, AnalysisUnit unit, string name) => _baseType.GetTypeMember(node, unit, name); + public override IAnalysisSet GetInstanceType() => _baseType.GetInstanceType(); + + public override AnalysisUnit AnalysisUnit => _baseType.AnalysisUnit; + internal override void AddReference(Node node, AnalysisUnit analysisUnit) => _baseType.AddReference(node, analysisUnit); + public override void AugmentAssign(AugmentedAssignStatement node, AnalysisUnit unit, IAnalysisSet value) + => _baseType.AugmentAssign(node, unit, value); + public override IAnalysisSet Await(Node node, AnalysisUnit unit) => _baseType.Await(node, unit); + public override IAnalysisSet BinaryOperation(Node node, AnalysisUnit unit, PythonOperator operation, IAnalysisSet rhs) + => _baseType.BinaryOperation(node, unit, operation, rhs); + public override IAnalysisSet Call(Node node, AnalysisUnit unit, IAnalysisSet[] args, NameExpression[] keywordArgNames) + => _baseType.Call(node, unit, args, keywordArgNames); + public override void DeleteMember(Node node, AnalysisUnit unit, string name) => _baseType.DeleteMember(node, unit, name); + public override IAnalysisSet GetAsyncEnumeratorTypes(Node node, AnalysisUnit unit) => _baseType.GetAsyncEnumeratorTypes(node, unit); + public override IAnalysisSet GetAsyncIterator(Node node, AnalysisUnit unit) => _baseType.GetAsyncIterator(node, unit); + public override object GetConstantValue() => _baseType.GetConstantValue(); + public override IAnalysisSet GetDescriptor(Node node, AnalysisValue instance, AnalysisValue context, AnalysisUnit unit) + => _baseType.GetDescriptor(node, instance, context, unit); + + public override IAnalysisSet GetDescriptor(PythonAnalyzer projectState, AnalysisValue instance, AnalysisValue context) + => _baseType.GetDescriptor(projectState, instance, context); + public override IAnalysisSet GetEnumeratorTypes(Node node, AnalysisUnit unit) => _baseType.GetEnumeratorTypes(node, unit); + public override IAnalysisSet GetIndex(Node node, AnalysisUnit unit, IAnalysisSet index) => _baseType.GetIndex(node, unit, index); + public override IEnumerable> GetItems() => _baseType.GetItems(); + public override IAnalysisSet GetIterator(Node node, AnalysisUnit unit) => _baseType.GetIterator(node, unit); + public override IAnalysisSet GetReturnForYieldFrom(Node node, AnalysisUnit unit) => _baseType.GetReturnForYieldFrom(node, unit); + public override IEnumerable Locations => _baseType.Locations; + public override IMro Mro => _baseType.Mro; + public override IEnumerable Overloads => _baseType.Overloads; + public override int? GetLength() => _baseType.GetLength(); + internal override IAnalysisSet Resolve(AnalysisUnit unit, ResolutionContext context) => _baseType.Resolve(unit, context); + internal override IEnumerable References => _baseType.References; + public override IAnalysisSet ReverseBinaryOperation(Node node, AnalysisUnit unit, PythonOperator operation, IAnalysisSet rhs) + => _baseType.ReverseBinaryOperation(node, unit, operation, rhs); + + public override void SetIndex(Node node, AnalysisUnit unit, IAnalysisSet index, IAnalysisSet value) => _baseType.SetIndex(node, unit, index, value); + public override IAnalysisSet UnaryOperation(Node node, AnalysisUnit unit, PythonOperator operation) => _baseType.UnaryOperation(node, unit, operation); + public override void SetMember(Node node, AnalysisUnit unit, string name, IAnalysisSet value) => _baseType.SetMember(node, unit, name, value); + } } diff --git a/src/Analysis/Engine/Impl/Values/TypingModuleInfo.cs b/src/Analysis/Engine/Impl/Values/TypingModuleInfo.cs index 2b17a39c0..9e85605bd 100644 --- a/src/Analysis/Engine/Impl/Values/TypingModuleInfo.cs +++ b/src/Analysis/Engine/Impl/Values/TypingModuleInfo.cs @@ -57,18 +57,25 @@ private IAnalysisSet GetFunction(Node node, AnalysisUnit unit, string name, Call private IAnalysisSet NewType_Call(Node node, AnalysisUnit unit, IAnalysisSet[] args, NameExpression[] keywordArgNames) { return unit.InterpreterScope.GetOrMakeNodeValue(node, Analyzer.NodeValueKind.TypeAnnotation, n => { var name = PythonAnalyzer.GetArg(args, keywordArgNames, null, 0).GetConstantValueAsString().FirstOrDefault(x => !string.IsNullOrEmpty(x)); - var baseType = PythonAnalyzer.GetArg(args, keywordArgNames, null, 1) ?? unit.State.ClassInfos[BuiltinTypeId.Object].Instance; + var baseTypeSet = PythonAnalyzer.GetArg(args, keywordArgNames, null, 1) ?? unit.State.ClassInfos[BuiltinTypeId.Object].Instance; if (string.IsNullOrEmpty(name)) { - return baseType; + return baseTypeSet; } var instPi = new ProtocolInfo(unit.ProjectEntry, unit.State); - var np = new NameProtocol(instPi, name, memberType: PythonMemberType.Instance); - var cls = new NamespaceProtocol(instPi, "__class__"); + var np = new NameProtocol(instPi, name, memberType: PythonMemberType.Instance, typeId: BuiltinTypeId.Type); + var cls = new NamespaceProtocol(instPi, "__class__"); // Declares class type instPi.AddProtocol(np); instPi.AddProtocol(cls); + // Add base delegate so we can see actual type members + var baseType = baseTypeSet.FirstOrDefault(); + if (baseType != null) { + var bt = new GenericProtocol(instPi, baseType); + instPi.AddProtocol(bt); + } + var pi = new ProtocolInfo(unit.ProjectEntry, unit.State); - pi.AddProtocol(new NameProtocol(pi, name)); + pi.AddProtocol(new NameProtocol(pi, name, memberType: PythonMemberType.Instance, typeId: BuiltinTypeId.Type)); pi.AddProtocol(new InstanceProtocol(pi, Array.Empty(), instPi)); pi.AddReference(n, unit); From f29cb64f5ab0dcb0324eebf5b9f383bb61a72f32 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Mon, 29 Oct 2018 15:03:43 -0700 Subject: [PATCH 4/8] New protocols and tests --- .../Engine/Impl/Values/IterableInfo.cs | 1 + src/Analysis/Engine/Impl/Values/Protocols.cs | 135 +++++++++++------- .../Engine/Impl/Values/TypingModuleInfo.cs | 2 +- .../Engine/Impl/Values/TypingTypeInfo.cs | 10 +- src/Analysis/Engine/Test/CompletionTests.cs | 8 +- 5 files changed, 96 insertions(+), 60 deletions(-) diff --git a/src/Analysis/Engine/Impl/Values/IterableInfo.cs b/src/Analysis/Engine/Impl/Values/IterableInfo.cs index 2ae05c3ad..5d7fea41d 100644 --- a/src/Analysis/Engine/Impl/Values/IterableInfo.cs +++ b/src/Analysis/Engine/Impl/Values/IterableInfo.cs @@ -255,6 +255,7 @@ internal override IAnalysisSet Resolve(AnalysisUnit unit, ResolutionContext cont } var pi = new ProtocolInfo(DeclaringModule, ProjectState); + var actualType = unit.State.GetAnalysisValueFromObjects(ClassInfo.TypeId); pi.AddProtocol(new IterableProtocol(pi, union)); if (ClassInfo.TypeId == BuiltinTypeId.Tuple) { newTypes = VariableDef.Generator.Take(IndexTypes.Length).ToArray(); diff --git a/src/Analysis/Engine/Impl/Values/Protocols.cs b/src/Analysis/Engine/Impl/Values/Protocols.cs index c3104b331..76819f30a 100644 --- a/src/Analysis/Engine/Impl/Values/Protocols.cs +++ b/src/Analysis/Engine/Impl/Values/Protocols.cs @@ -733,12 +733,45 @@ public InstanceProtocol(ProtocolInfo self, IReadOnlyList arguments } /// - /// Generic protocol that delegates work to its inner class such as - /// List[T] has list as its base. Typically used in NewType and TypeVar - /// scenarios delegating calls to the actual class serving as new type. + /// List protocol that delegates work to its inner class: List[T] has list methods. /// - class GenericProtocol : Protocol { - protected readonly AnalysisValue _baseType; + class ListProtocol : IterableProtocol { + protected readonly AnalysisValue _actualType; + + public ListProtocol(ProtocolInfo self, AnalysisValue actualType, IAnalysisSet valueTypes) : base(self, valueTypes) { + _actualType = actualType; + } + + public override IDictionary GetAllMembers(IModuleContext moduleContext, GetMemberOptions options = GetMemberOptions.None) + => _actualType.GetAllMembers(moduleContext, options); + public override IAnalysisSet GetMember(Node node, AnalysisUnit unit, string name) => _actualType.GetMember(node, unit, name); + public override IAnalysisSet GetTypeMember(Node node, AnalysisUnit unit, string name) => _actualType.GetTypeMember(node, unit, name); + } + + /// + /// Dict protocol that delegates work to its inner class: Dict[T1, T2] has dict methods. + /// + class DictProtocol : MappingProtocol { + protected readonly AnalysisValue _actualType; + + public DictProtocol(ProtocolInfo self, AnalysisValue actualType, IAnalysisSet keyTypes, IAnalysisSet valueTypes, IAnalysisSet items) + : base(self, keyTypes, valueTypes, items) { + _actualType = actualType; + } + + public override IDictionary GetAllMembers(IModuleContext moduleContext, GetMemberOptions options = GetMemberOptions.None) + => _actualType.GetAllMembers(moduleContext, options); + public override IAnalysisSet GetMember(Node node, AnalysisUnit unit, string name) => _actualType.GetMember(node, unit, name); + public override IAnalysisSet GetTypeMember(Node node, AnalysisUnit unit, string name) => _actualType.GetTypeMember(node, unit, name); + } + + /// + /// Generic protocol that delegates work to its inner class. + /// Typically used in NewType and TypeVar scenarios delegating + /// calls to the actual class serving as new type. + /// + class TypeDelegateProtocol : Protocol { + protected readonly AnalysisValue _actualType; /// /// Creates protocol that delegates to base type, such as generic list @@ -746,69 +779,69 @@ class GenericProtocol : Protocol { /// /// Protocol info /// Base type to delegate to, such as 'list'. - public GenericProtocol(ProtocolInfo self, AnalysisValue baseType) : base(self) { - _baseType = baseType; + public TypeDelegateProtocol(ProtocolInfo self, AnalysisValue actualType) : base(self) { + _actualType = actualType; } - protected override bool Equals(Protocol other) => _baseType.Equals((other as GenericProtocol)._baseType); + protected override bool Equals(Protocol other) => _actualType.Equals((other as TypeDelegateProtocol)._actualType); - public override string Name => _baseType.Name; - public override string Documentation => _baseType.Documentation; - public override string Description => _baseType.Description; - public override string ShortDescription => _baseType.ShortDescription; - public override BuiltinTypeId TypeId => _baseType.TypeId; - public override PythonMemberType MemberType => _baseType.MemberType; + public override string Name => _actualType.Name; + public override string Documentation => _actualType.Documentation; + public override string Description => _actualType.Description; + public override string ShortDescription => _actualType.ShortDescription; + public override BuiltinTypeId TypeId => _actualType.TypeId; + public override PythonMemberType MemberType => _actualType.MemberType; public override IEnumerable> GetRichDescription() - => _baseType is IHasRichDescription rd + => _actualType is IHasRichDescription rd ? rd.GetRichDescription() : Enumerable.Empty>(); - public override IPythonProjectEntry DeclaringModule => _baseType.DeclaringModule; - public override int DeclaringVersion => _baseType.DeclaringVersion; - public override IPythonType PythonType => _baseType.PythonType; - public override bool IsOfType(IAnalysisSet klass) => _baseType.IsOfType(klass); - public override bool IsAlive => _baseType.IsAlive; + public override IPythonProjectEntry DeclaringModule => _actualType.DeclaringModule; + public override int DeclaringVersion => _actualType.DeclaringVersion; + public override IPythonType PythonType => _actualType.PythonType; + public override bool IsOfType(IAnalysisSet klass) => _actualType.IsOfType(klass); + public override bool IsAlive => _actualType.IsAlive; public override IDictionary GetAllMembers(IModuleContext moduleContext, GetMemberOptions options = GetMemberOptions.None) - => _baseType.GetAllMembers(moduleContext, options); - public override IAnalysisSet GetMember(Node node, AnalysisUnit unit, string name) => _baseType.GetMember(node, unit, name); - public override IAnalysisSet GetTypeMember(Node node, AnalysisUnit unit, string name) => _baseType.GetTypeMember(node, unit, name); - public override IAnalysisSet GetInstanceType() => _baseType.GetInstanceType(); + => _actualType.GetAllMembers(moduleContext, options); + public override IAnalysisSet GetMember(Node node, AnalysisUnit unit, string name) => _actualType.GetMember(node, unit, name); + public override IAnalysisSet GetTypeMember(Node node, AnalysisUnit unit, string name) => _actualType.GetTypeMember(node, unit, name); + public override IAnalysisSet GetInstanceType() => _actualType.GetInstanceType(); - public override AnalysisUnit AnalysisUnit => _baseType.AnalysisUnit; - internal override void AddReference(Node node, AnalysisUnit analysisUnit) => _baseType.AddReference(node, analysisUnit); + public override AnalysisUnit AnalysisUnit => _actualType.AnalysisUnit; + internal override void AddReference(Node node, AnalysisUnit analysisUnit) => _actualType.AddReference(node, analysisUnit); public override void AugmentAssign(AugmentedAssignStatement node, AnalysisUnit unit, IAnalysisSet value) - => _baseType.AugmentAssign(node, unit, value); - public override IAnalysisSet Await(Node node, AnalysisUnit unit) => _baseType.Await(node, unit); + => _actualType.AugmentAssign(node, unit, value); + public override IAnalysisSet Await(Node node, AnalysisUnit unit) => _actualType.Await(node, unit); public override IAnalysisSet BinaryOperation(Node node, AnalysisUnit unit, PythonOperator operation, IAnalysisSet rhs) - => _baseType.BinaryOperation(node, unit, operation, rhs); + => _actualType.BinaryOperation(node, unit, operation, rhs); public override IAnalysisSet Call(Node node, AnalysisUnit unit, IAnalysisSet[] args, NameExpression[] keywordArgNames) - => _baseType.Call(node, unit, args, keywordArgNames); - public override void DeleteMember(Node node, AnalysisUnit unit, string name) => _baseType.DeleteMember(node, unit, name); - public override IAnalysisSet GetAsyncEnumeratorTypes(Node node, AnalysisUnit unit) => _baseType.GetAsyncEnumeratorTypes(node, unit); - public override IAnalysisSet GetAsyncIterator(Node node, AnalysisUnit unit) => _baseType.GetAsyncIterator(node, unit); - public override object GetConstantValue() => _baseType.GetConstantValue(); + => _actualType.Call(node, unit, args, keywordArgNames); + public override void DeleteMember(Node node, AnalysisUnit unit, string name) => _actualType.DeleteMember(node, unit, name); + public override IAnalysisSet GetAsyncEnumeratorTypes(Node node, AnalysisUnit unit) => _actualType.GetAsyncEnumeratorTypes(node, unit); + public override IAnalysisSet GetAsyncIterator(Node node, AnalysisUnit unit) => _actualType.GetAsyncIterator(node, unit); + public override object GetConstantValue() => _actualType.GetConstantValue(); public override IAnalysisSet GetDescriptor(Node node, AnalysisValue instance, AnalysisValue context, AnalysisUnit unit) - => _baseType.GetDescriptor(node, instance, context, unit); + => _actualType.GetDescriptor(node, instance, context, unit); public override IAnalysisSet GetDescriptor(PythonAnalyzer projectState, AnalysisValue instance, AnalysisValue context) - => _baseType.GetDescriptor(projectState, instance, context); - public override IAnalysisSet GetEnumeratorTypes(Node node, AnalysisUnit unit) => _baseType.GetEnumeratorTypes(node, unit); - public override IAnalysisSet GetIndex(Node node, AnalysisUnit unit, IAnalysisSet index) => _baseType.GetIndex(node, unit, index); - public override IEnumerable> GetItems() => _baseType.GetItems(); - public override IAnalysisSet GetIterator(Node node, AnalysisUnit unit) => _baseType.GetIterator(node, unit); - public override IAnalysisSet GetReturnForYieldFrom(Node node, AnalysisUnit unit) => _baseType.GetReturnForYieldFrom(node, unit); - public override IEnumerable Locations => _baseType.Locations; - public override IMro Mro => _baseType.Mro; - public override IEnumerable Overloads => _baseType.Overloads; - public override int? GetLength() => _baseType.GetLength(); - internal override IAnalysisSet Resolve(AnalysisUnit unit, ResolutionContext context) => _baseType.Resolve(unit, context); - internal override IEnumerable References => _baseType.References; + => _actualType.GetDescriptor(projectState, instance, context); + public override IAnalysisSet GetEnumeratorTypes(Node node, AnalysisUnit unit) => _actualType.GetEnumeratorTypes(node, unit); + public override IAnalysisSet GetIndex(Node node, AnalysisUnit unit, IAnalysisSet index) => _actualType.GetIndex(node, unit, index); + public override IEnumerable> GetItems() => _actualType.GetItems(); + public override IAnalysisSet GetIterator(Node node, AnalysisUnit unit) => _actualType.GetIterator(node, unit); + public override IAnalysisSet GetReturnForYieldFrom(Node node, AnalysisUnit unit) => _actualType.GetReturnForYieldFrom(node, unit); + public override IEnumerable Locations => _actualType.Locations; + public override IMro Mro => _actualType.Mro; + public override IEnumerable Overloads => _actualType.Overloads; + public override int? GetLength() => _actualType.GetLength(); + internal override IAnalysisSet Resolve(AnalysisUnit unit, ResolutionContext context) => _actualType.Resolve(unit, context); + internal override IEnumerable References => _actualType.References; public override IAnalysisSet ReverseBinaryOperation(Node node, AnalysisUnit unit, PythonOperator operation, IAnalysisSet rhs) - => _baseType.ReverseBinaryOperation(node, unit, operation, rhs); + => _actualType.ReverseBinaryOperation(node, unit, operation, rhs); - public override void SetIndex(Node node, AnalysisUnit unit, IAnalysisSet index, IAnalysisSet value) => _baseType.SetIndex(node, unit, index, value); - public override IAnalysisSet UnaryOperation(Node node, AnalysisUnit unit, PythonOperator operation) => _baseType.UnaryOperation(node, unit, operation); - public override void SetMember(Node node, AnalysisUnit unit, string name, IAnalysisSet value) => _baseType.SetMember(node, unit, name, value); + public override void SetIndex(Node node, AnalysisUnit unit, IAnalysisSet index, IAnalysisSet value) => _actualType.SetIndex(node, unit, index, value); + public override IAnalysisSet UnaryOperation(Node node, AnalysisUnit unit, PythonOperator operation) => _actualType.UnaryOperation(node, unit, operation); + public override void SetMember(Node node, AnalysisUnit unit, string name, IAnalysisSet value) => _actualType.SetMember(node, unit, name, value); } } diff --git a/src/Analysis/Engine/Impl/Values/TypingModuleInfo.cs b/src/Analysis/Engine/Impl/Values/TypingModuleInfo.cs index 9e85605bd..c6d561cb4 100644 --- a/src/Analysis/Engine/Impl/Values/TypingModuleInfo.cs +++ b/src/Analysis/Engine/Impl/Values/TypingModuleInfo.cs @@ -70,7 +70,7 @@ private IAnalysisSet NewType_Call(Node node, AnalysisUnit unit, IAnalysisSet[] a // Add base delegate so we can see actual type members var baseType = baseTypeSet.FirstOrDefault(); if (baseType != null) { - var bt = new GenericProtocol(instPi, baseType); + var bt = new TypeDelegateProtocol(instPi, baseType); instPi.AddProtocol(bt); } diff --git a/src/Analysis/Engine/Impl/Values/TypingTypeInfo.cs b/src/Analysis/Engine/Impl/Values/TypingTypeInfo.cs index b61f95a0f..d92409de3 100644 --- a/src/Analysis/Engine/Impl/Values/TypingTypeInfo.cs +++ b/src/Analysis/Engine/Impl/Values/TypingTypeInfo.cs @@ -341,10 +341,13 @@ public IAnalysisSet Finalize(string name, IReadOnlyList args) { if (GetSequenceTypes(name, args, out realType, out keyTypes, out valueTypes)) { var p = new ProtocolInfo(Entry, State); p.AddReference(_node, _unit); + np = realType == null ? new NameProtocol(p, name) : new NameProtocol(p, realType); np.ExtendDescription(valueTypes.GetRichDescriptions(unionPrefix: "[", unionSuffix: "]", alwaysUsePrefixSuffix: true)); p.AddProtocol(np); - p.AddProtocol(new IterableProtocol(p, valueTypes)); + + var actualType = State.GetAnalysisValueFromObjects(realType); + p.AddProtocol(new ListProtocol(p, actualType, valueTypes)); if (keyTypes != null) { p.AddProtocol(new GetItemProtocol(p, keyTypes, valueTypes)); } @@ -359,6 +362,7 @@ public IAnalysisSet Finalize(string name, IReadOnlyList args) { if (GetSequenceTypes(name, args, out realType, out keyTypes, out valueTypes)) { var p = new ProtocolInfo(Entry, State); p.AddReference(_node, _unit); + np = realType == null ? new NameProtocol(p, name) : new NameProtocol(p, realType); np.ExtendDescription(new KeyValuePair(WellKnownRichDescriptionKinds.Misc, "[")); np.ExtendDescription(keyTypes.GetRichDescriptions(unionPrefix: "[", unionSuffix: "]", defaultIfEmpty: "Any")); @@ -366,7 +370,9 @@ public IAnalysisSet Finalize(string name, IReadOnlyList args) { np.ExtendDescription(valueTypes.GetRichDescriptions(unionPrefix: "[", unionSuffix: "]", defaultIfEmpty: "Any")); np.ExtendDescription(new KeyValuePair(WellKnownRichDescriptionKinds.Misc, "]")); p.AddProtocol(np); - p.AddProtocol(new MappingProtocol(p, keyTypes, valueTypes, MakeTuple(keyTypes, valueTypes))); + + var actualType = State.GetAnalysisValueFromObjects(realType); + p.AddProtocol(new DictProtocol(p, actualType, keyTypes, valueTypes, MakeTuple(keyTypes, valueTypes))); return p; } break; diff --git a/src/Analysis/Engine/Test/CompletionTests.cs b/src/Analysis/Engine/Test/CompletionTests.cs index c05e55630..cfa89fff5 100644 --- a/src/Analysis/Engine/Test/CompletionTests.cs +++ b/src/Analysis/Engine/Test/CompletionTests.cs @@ -1076,8 +1076,7 @@ from typing import Dict def func(a: Dict[int, str]): a. - a.keys[0]. - a.values[0]. + a[0]. pass "; using (var server = await CreateServerAsync(PythonVersions.LatestAvailable3X)) { @@ -1087,10 +1086,7 @@ def func(a: Dict[int, str]): var completions = await server.SendCompletion(uri, 4, 6); completions.Should().HaveLabels("keys", "values"); - completions = await server.SendCompletion(uri, 5, 14); - completions.Should().HaveLabels("bit_length"); - - completions = await server.SendCompletion(uri, 6, 17); + completions = await server.SendCompletion(uri, 5, 9); completions.Should().HaveLabels("capitalize"); } } From e47e6370364fe0dea7af4027bb81d3304a6b5b95 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Mon, 29 Oct 2018 15:37:33 -0700 Subject: [PATCH 5/8] Test --- src/Analysis/Engine/Impl/Values/Protocols.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Analysis/Engine/Impl/Values/Protocols.cs b/src/Analysis/Engine/Impl/Values/Protocols.cs index 76819f30a..66b7ec89a 100644 --- a/src/Analysis/Engine/Impl/Values/Protocols.cs +++ b/src/Analysis/Engine/Impl/Values/Protocols.cs @@ -744,8 +744,6 @@ public ListProtocol(ProtocolInfo self, AnalysisValue actualType, IAnalysisSet va public override IDictionary GetAllMembers(IModuleContext moduleContext, GetMemberOptions options = GetMemberOptions.None) => _actualType.GetAllMembers(moduleContext, options); - public override IAnalysisSet GetMember(Node node, AnalysisUnit unit, string name) => _actualType.GetMember(node, unit, name); - public override IAnalysisSet GetTypeMember(Node node, AnalysisUnit unit, string name) => _actualType.GetTypeMember(node, unit, name); } /// @@ -761,8 +759,6 @@ public DictProtocol(ProtocolInfo self, AnalysisValue actualType, IAnalysisSet ke public override IDictionary GetAllMembers(IModuleContext moduleContext, GetMemberOptions options = GetMemberOptions.None) => _actualType.GetAllMembers(moduleContext, options); - public override IAnalysisSet GetMember(Node node, AnalysisUnit unit, string name) => _actualType.GetMember(node, unit, name); - public override IAnalysisSet GetTypeMember(Node node, AnalysisUnit unit, string name) => _actualType.GetTypeMember(node, unit, name); } /// From cc952a812b440be90502ca184bca64a132f97c56 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Tue, 30 Oct 2018 09:24:12 -0700 Subject: [PATCH 6/8] PR feedback --- src/Analysis/Engine/Test/AnalysisTest.cs | 32 +++++++++++++++++++----- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/src/Analysis/Engine/Test/AnalysisTest.cs b/src/Analysis/Engine/Test/AnalysisTest.cs index ae5f98c72..e5deaa38e 100644 --- a/src/Analysis/Engine/Test/AnalysisTest.cs +++ b/src/Analysis/Engine/Test/AnalysisTest.cs @@ -4194,9 +4194,8 @@ def func(a: List[str]): using (var server = await CreateServerAsync(PythonVersions.LatestAvailable3X)) { var analysis = await server.OpenDefaultDocumentAndGetAnalysisAsync(code); - analysis.Scope.Children - .OfType() - .First() + analysis + .Should().HaveFunction("func").Which .Should().HaveVariable("a") .OfTypes(BuiltinTypeId.List, BuiltinTypeId.Unknown); // list and 'function argument' } @@ -4213,9 +4212,8 @@ def func(a: Dict[int, str]): using (var server = await CreateServerAsync(PythonVersions.LatestAvailable3X)) { var analysis = await server.OpenDefaultDocumentAndGetAnalysisAsync(code); - analysis.Scope.Children - .OfType() - .First() + analysis + .Should().HaveFunction("func").Which .Should().HaveVariable("a") .OfTypes(BuiltinTypeId.Dict, BuiltinTypeId.Unknown); // dict and 'function argument' } @@ -4240,6 +4238,28 @@ from typing import NewType } } + [TestMethod, Priority(0)] + public async Task TypeVar() { + var code = @" +from typing import Sequence, TypeVar + +T = TypeVar('T') # Declare type variable + +def first(l: Sequence[T]) -> T: # Generic function + return l[0] + +arr = [1, 2, 3] +x = first(arr) # should be int +"; + + using (var server = await CreateServerAsync(PythonVersions.LatestAvailable3X)) { + var analysis = await server.OpenDefaultDocumentAndGetAnalysisAsync(code); + analysis + .Should().HaveVariable("x") + .OfTypes(BuiltinTypeId.Int, BuiltinTypeId.Type); // int and T + } + } + [TestMethod, Priority(0)] public async Task Defaults() { var text = @" From 1649255d55d3d02ec319ec388f2854a58c76bfe8 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Mon, 5 Nov 2018 12:33:59 -0800 Subject: [PATCH 7/8] Fix merge issue --- src/Analysis/Engine/Test/CompletionTests.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Analysis/Engine/Test/CompletionTests.cs b/src/Analysis/Engine/Test/CompletionTests.cs index 44a01a1d5..41cccb124 100644 --- a/src/Analysis/Engine/Test/CompletionTests.cs +++ b/src/Analysis/Engine/Test/CompletionTests.cs @@ -1115,7 +1115,17 @@ def func(a: Dict[int, str]): completions.Should().HaveLabels("capitalize"); } } - private static async Task AssertCompletion(Server s, Uri uri, IReadOnlyCollection contains, IReadOnlyCollection excludes, Position? position = null, CompletionContext? context = null, Func cmpKey = null, string expr = null, Range? applicableSpan = null) { + private static async Task AssertCompletion( + Server s, + Uri uri, + IReadOnlyCollection contains, + IReadOnlyCollection excludes, + Position? position = null, + CompletionContext? context = null, + Func cmpKey = null, + string expr = null, + Range? applicableSpan = null, + InsertTextFormat? allFormat = InsertTextFormat.PlainText) { await s.WaitForCompleteAnalysisAsync(CancellationToken.None); var res = await s.Completion(new CompletionParams { textDocument = new TextDocumentIdentifier { uri = uri }, From 61f057e0c94f9c6f33cd64747542bd4b86a95e42 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Tue, 6 Nov 2018 09:50:03 -0800 Subject: [PATCH 8/8] Fix comment and remove unused variable. --- src/Analysis/Engine/Impl/Values/IterableInfo.cs | 1 - src/Analysis/Engine/Impl/Values/Protocols.cs | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Analysis/Engine/Impl/Values/IterableInfo.cs b/src/Analysis/Engine/Impl/Values/IterableInfo.cs index 5d7fea41d..2ae05c3ad 100644 --- a/src/Analysis/Engine/Impl/Values/IterableInfo.cs +++ b/src/Analysis/Engine/Impl/Values/IterableInfo.cs @@ -255,7 +255,6 @@ internal override IAnalysisSet Resolve(AnalysisUnit unit, ResolutionContext cont } var pi = new ProtocolInfo(DeclaringModule, ProjectState); - var actualType = unit.State.GetAnalysisValueFromObjects(ClassInfo.TypeId); pi.AddProtocol(new IterableProtocol(pi, union)); if (ClassInfo.TypeId == BuiltinTypeId.Tuple) { newTypes = VariableDef.Generator.Take(IndexTypes.Length).ToArray(); diff --git a/src/Analysis/Engine/Impl/Values/Protocols.cs b/src/Analysis/Engine/Impl/Values/Protocols.cs index 66b7ec89a..18920aca2 100644 --- a/src/Analysis/Engine/Impl/Values/Protocols.cs +++ b/src/Analysis/Engine/Impl/Values/Protocols.cs @@ -770,8 +770,8 @@ class TypeDelegateProtocol : Protocol { protected readonly AnalysisValue _actualType; /// - /// Creates protocol that delegates to base type, such as generic list - /// provides methods from the plain list. + /// Creates protocol that delegates to real type, such as TypeVar or NewType + /// to the actual underlying type. /// /// Protocol info /// Base type to delegate to, such as 'list'.