Skip to content

Commit

Permalink
Fixes microsoft#3218 Use return annotation for AST analysis
Browse files Browse the repository at this point in the history
Adds basic (builtin/global) return annotation parsing
  • Loading branch information
zooba committed Oct 25, 2017
1 parent a42a613 commit 30c3e49
Show file tree
Hide file tree
Showing 8 changed files with 549 additions and 2 deletions.
2 changes: 2 additions & 0 deletions Python/Product/Analysis/Analysis.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
<Compile Include="Interpreter\Ast\AstPythonParameterInfo.cs" />
<Compile Include="Interpreter\Ast\AstPythonInterpreterFactory.cs" />
<Compile Include="Interpreter\Ast\AstScrapedPythonModule.cs" />
<Compile Include="Interpreter\Ast\AstTypeAnnotationConverter.cs" />
<Compile Include="Interpreter\Ast\NameLookupContext.cs" />
<Compile Include="Interpreter\ILazyMember.cs" />
<Compile Include="Interpreter\IPythonInterpreterWithLog.cs" />
Expand All @@ -94,6 +95,7 @@
<Compile Include="Interpreter\NoPackageManager.cs" />
<Compile Include="Interpreter\PackageSpec.cs" />
<Compile Include="Interpreter\PackageVersion.cs" />
<Compile Include="Parsing\Ast\TypeAnnotation.cs" />
<Compile Include="Parsing\Ast\ExpressionWithAnnotation.cs" />
<Compile Include="Projects\AnalysisExtensionNameAttribute.cs" />
<Compile Include="AnalysisExtensions.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,16 @@ public void Walk() {
}
}

if (_target.ReturnAnnotation != null) {
var retAnn = new TypeAnnotation(_scope.Ast.LanguageVersion, _target.ReturnAnnotation);
var m = retAnn.GetValue(new AstTypeAnnotationConverter(_scope));
if (m is IPythonMultipleMembers mm) {
_returnTypes.AddRange(mm.Members.OfType<IPythonType>());
} else if (m is IPythonType type) {
_returnTypes.Add(type);
}
}

_scope.PushScope();
if (self != null) {
var p0 = _target.Parameters?.FirstOrDefault();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// Python Tools for Visual Studio
// Copyright(c) Microsoft Corporation
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the License); you may not use
// this file except in compliance with the License. You may obtain a copy of the
// License at http://www.apache.org/licenses/LICENSE-2.0
//
// THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS
// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY
// IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
// MERCHANTABLITY OR NON-INFRINGEMENT.
//
// See the Apache Version 2.0 License for specific language governing
// permissions and limitations under the License.

using System.Collections.Generic;
using System.Linq;
using Microsoft.PythonTools.Parsing.Ast;

namespace Microsoft.PythonTools.Interpreter.Ast {
class AstTypeAnnotationConverter : TypeAnnotationConverter<IPythonType> {
private readonly NameLookupContext _scope;

public AstTypeAnnotationConverter(NameLookupContext scope) {
_scope = scope;
}

public override IPythonType LookupName(string name) {
var m = _scope.LookupNameInScopes(name, NameLookupContext.LookupOptions.Global | NameLookupContext.LookupOptions.Builtins);
if (m is IPythonMultipleMembers mm) {
m = mm.Members.OfType<IPythonType>().FirstOrDefault<IMember>() ??
mm.Members.OfType<IPythonModule>().FirstOrDefault();
}
if (m is IPythonModule mod) {
// Wrap the module in an IPythonType interface
return new ModuleType(mod);
}
return m as IPythonType;
}

public override IPythonType GetTypeMember(IPythonType baseType, string member) {
return baseType.GetMember(_scope.Context, member) as IPythonType;
}

public override IPythonType MakeUnion(IReadOnlyList<IPythonType> types) {
return new UnionType(types);
}

public override IReadOnlyList<IPythonType> GetUnionTypes(IPythonType unionType) {
return (unionType as UnionType)?.Types ??
(unionType as IPythonMultipleMembers)?.Members.OfType<IPythonType>().ToArray();
}

private class ModuleType : IPythonType {
public ModuleType(IPythonModule module) {
DeclaringModule = module;
}

public IPythonModule DeclaringModule { get; }

public string Name => DeclaringModule.Name;
public string Documentation => DeclaringModule.Documentation;
public BuiltinTypeId TypeId => BuiltinTypeId.Module;
public IList<IPythonType> Mro => new[] { this };
public bool IsBuiltin => true;
public PythonMemberType MemberType => PythonMemberType.Module;
public IPythonFunction GetConstructors() => null;

public IMember GetMember(IModuleContext context, string name) => DeclaringModule.GetMember(context, name);
public IEnumerable<string> GetMemberNames(IModuleContext moduleContext) => DeclaringModule.GetMemberNames(moduleContext);
}

private class UnionType : IPythonMultipleMembers, IPythonType {
public UnionType(IReadOnlyList<IPythonType> types) {
Types = types;
}

public IReadOnlyList<IPythonType> Types { get; }

public IList<IMember> Members => Types.OfType<IMember>().ToArray();

public PythonMemberType MemberType => PythonMemberType.Unknown;
public string Name => "Any";
public string Documentation => null;
public BuiltinTypeId TypeId => BuiltinTypeId.Unknown;
public IPythonModule DeclaringModule => null;
public IList<IPythonType> Mro => null;
public bool IsBuiltin => false;
public IPythonFunction GetConstructors() => null;

public IMember GetMember(IModuleContext context, string name) => new UnionType(
Types.Select(t => t.GetMember(context, name)).OfType<IPythonType>().ToArray()
);

public IEnumerable<string> GetMemberNames(IModuleContext moduleContext) => Types.SelectMany(t => t.GetMemberNames(moduleContext));
}
}
}
Loading

0 comments on commit 30c3e49

Please sign in to comment.