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

Commit 4c5a349

Browse files
author
Mikhail Arkhipov
committed
Revert due to test failure
1 parent d4e2799 commit 4c5a349

File tree

12 files changed

+98
-124
lines changed

12 files changed

+98
-124
lines changed

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

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -196,9 +196,6 @@ private static IReadOnlyList<IPythonType> GetSpecificTypeFromArgumentValue(objec
196196
specificTypes.Add(itemType);
197197
}
198198
break;
199-
case IPythonInstance inst:
200-
specificTypes.Add(inst.GetPythonType());
201-
break;
202199
case IMember m:
203200
if (!m.IsUnknown()) {
204201
specificTypes.Add(m.GetPythonType());

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
using Microsoft.Python.Analysis.Values;
2222
using Microsoft.Python.Core;
2323
using Microsoft.Python.Core.Disposables;
24+
using Microsoft.Python.Core.Text;
2425
using Microsoft.Python.Parsing.Ast;
2526

2627
namespace Microsoft.Python.Analysis.Analyzer.Evaluation {
@@ -116,7 +117,11 @@ public IMember LookupNameInScopes(string name, out IScope scope, out IVariable v
116117
return value;
117118
}
118119

119-
public IPythonType GetTypeFromAnnotation(Expression expr, LookupOptions options = LookupOptions.Global | LookupOptions.Builtins) {
120+
public IPythonType GetTypeFromAnnotation(Expression expr, LookupOptions options = LookupOptions.Global | LookupOptions.Builtins)
121+
=> GetTypeFromAnnotation(expr, out _, options);
122+
123+
public IPythonType GetTypeFromAnnotation(Expression expr, out bool isGeneric, LookupOptions options = LookupOptions.Global | LookupOptions.Builtins) {
124+
isGeneric = false;
120125
switch (expr) {
121126
case null:
122127
return null;
@@ -128,6 +133,7 @@ public IPythonType GetTypeFromAnnotation(Expression expr, LookupOptions options
128133
var target = GetValueFromExpression(indexExpr.Target);
129134
var result = GetValueFromGeneric(target, indexExpr);
130135
if (result != null) {
136+
isGeneric = true;
131137
return result.GetPythonType();
132138
}
133139
break;

src/Analysis/Ast/Impl/Analyzer/Symbols/FunctionEvaluator.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -158,23 +158,24 @@ private void DeclareParameters(bool declareVariables) {
158158
// Declare parameters in scope
159159
IMember defaultValue = null;
160160
for (var i = skip; i < FunctionDefinition.Parameters.Length; i++) {
161+
var isGeneric = false;
161162
var p = FunctionDefinition.Parameters[i];
162163
if (!string.IsNullOrEmpty(p.Name)) {
163164
var paramType = Eval.GetTypeFromAnnotation(p.Annotation);
164165
if (paramType.IsUnknown() && p.DefaultValue != null) {
165166
defaultValue = Eval.GetValueFromExpression(p.DefaultValue);
166167
// If parameter has default value, look for the annotation locally first
167168
// since outer type may be getting redefined. Consider 's = None; def f(s: s = 123): ...
168-
paramType = Eval.GetTypeFromAnnotation(p.Annotation, LookupOptions.Local | LookupOptions.Builtins);
169+
paramType = Eval.GetTypeFromAnnotation(p.Annotation, out isGeneric, LookupOptions.Local | LookupOptions.Builtins);
169170
// Default value of None does not mean the parameter is None, just says it can be missing.
170171
defaultValue = defaultValue.IsUnknown() || defaultValue.IsOfType(BuiltinTypeId.NoneType) ? null : defaultValue;
171172
if (paramType == null && defaultValue != null) {
172173
paramType = defaultValue.GetPythonType();
173174
}
174175
}
175176
// If all else fails, look up globally.
176-
paramType = paramType ?? Eval.GetTypeFromAnnotation(p.Annotation) ?? Eval.UnknownType;
177-
var pi = new ParameterInfo(Ast, p, paramType, defaultValue, paramType.IsGeneric());
177+
paramType = paramType ?? Eval.GetTypeFromAnnotation(p.Annotation, out isGeneric) ?? Eval.UnknownType;
178+
var pi = new ParameterInfo(Ast, p, paramType, defaultValue, isGeneric);
178179
if (declareVariables) {
179180
DeclareParameter(p, pi);
180181
}

src/Analysis/Ast/Impl/Types/Definitions/IPythonPropertyType.cs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,5 @@ public interface IPythonPropertyType : IPythonClassMember {
3434
/// True if the property is read-only.
3535
/// </summary>
3636
bool IsReadOnly { get; }
37-
38-
/// <summary>
39-
/// Property return type.
40-
/// </summary>
41-
IPythonType Type { get; }
4237
}
4338
}

src/Analysis/Ast/Impl/Types/ParameterInfo.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
// permissions and limitations under the License.
1515

1616
using System;
17+
using Microsoft.Python.Core.Text;
1718
using Microsoft.Python.Parsing.Ast;
1819

1920
namespace Microsoft.Python.Analysis.Types {
@@ -25,7 +26,7 @@ public ParameterInfo(PythonAst ast, Parameter p, IPythonType type, IMember defau
2526
if (DefaultValueString == "...") {
2627
DefaultValueString = null;
2728
}
28-
IsGeneric = isGeneric || type.IsGeneric();
29+
IsGeneric = isGeneric;
2930
}
3031

3132
public ParameterInfo(string name, IPythonType type, ParameterKind? kind, IMember defaultValue) {
@@ -35,7 +36,6 @@ public ParameterInfo(string name, IPythonType type, ParameterKind? kind, IMember
3536
Type = type;
3637
IsParamArray = kind == ParameterKind.List;
3738
IsKeywordDict = kind == ParameterKind.Dictionary;
38-
IsGeneric = Type.IsGeneric();
3939
}
4040

4141
public string Name { get; }

src/Analysis/Ast/Impl/Types/PythonFunctionOverload.cs

Lines changed: 80 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,7 @@ public PythonFunctionOverload(string name, Location location) : base(location) {
6363
}
6464

6565
#region ILocatedMember
66-
6766
public override PythonMemberType MemberType => PythonMemberType.Function;
68-
6967
#endregion
7068

7169
internal void SetParameters(IReadOnlyList<IParameterInfo> parameters) => Parameters = parameters;
@@ -77,12 +75,10 @@ internal void AddReturnValue(IMember value) {
7775
if (value.IsUnknown()) {
7876
return; // Don't add useless values.
7977
}
80-
8178
if (StaticReturnValue.IsUnknown()) {
8279
SetReturnValue(value, false);
8380
return;
8481
}
85-
8682
// If return value is set from annotation, it should not be changing.
8783
var currentType = StaticReturnValue.GetPythonType();
8884
var valueType = value.GetPythonType();
@@ -102,7 +98,6 @@ internal void SetReturnValueProvider(ReturnValueProvider provider)
10298
=> _returnValueProvider = provider;
10399

104100
#region IPythonFunctionOverload
105-
106101
public FunctionDefinition FunctionDefinition { get; }
107102
public IPythonClassMember ClassMember { get; }
108103
public string Name { get; }
@@ -113,19 +108,44 @@ public string Documentation {
113108
if (string.IsNullOrEmpty(s)) {
114109
s = FunctionDefinition.GetDocumentation();
115110
}
116-
117111
return s ?? string.Empty;
118112
}
119113
}
120114

121115
public string GetReturnDocumentation(IPythonType self = null) {
122-
if (self != null) {
123-
var returnType = GetSpecificReturnType(self as IPythonClassType, null);
124-
if (!returnType.IsUnknown()) {
125-
return returnType.GetPythonType().Name;
126-
}
116+
if (self == null) {
117+
return _returnDocumentation;
118+
}
119+
var returnType = StaticReturnValue.GetPythonType();
120+
switch (returnType) {
121+
case PythonClassType cls when cls.IsGeneric(): {
122+
// -> A[_T1, _T2, ...]
123+
// Match arguments
124+
var typeArgs = cls.GenericParameters.Keys
125+
.Select(n => cls.GenericParameters.TryGetValue(n, out var t) ? t : null)
126+
.ExcludeDefault()
127+
.ToArray();
128+
var specificReturnValue = cls.CreateSpecificType(new ArgumentSet(typeArgs));
129+
return specificReturnValue.Name;
130+
}
131+
case IGenericTypeDefinition gtp1 when self is IPythonClassType cls: {
132+
// -> _T
133+
if (cls.GenericParameters.TryGetValue(gtp1.Name, out var specificType)) {
134+
return specificType.Name;
135+
}
136+
// Try returning the constraint
137+
// TODO: improve this, the heuristic is pretty basic and tailored to simple func(_T) -> _T
138+
var name = StaticReturnValue.GetPythonType()?.Name;
139+
var typeDefVar = DeclaringModule.Analysis.GlobalScope.Variables[name];
140+
if (typeDefVar?.Value is IGenericTypeDefinition gtp2) {
141+
var t = gtp2.Constraints.FirstOrDefault();
142+
if (t != null) {
143+
return t.Name;
144+
}
145+
}
146+
break;
147+
}
127148
}
128-
129149
return _returnDocumentation;
130150
}
131151

@@ -141,71 +161,59 @@ public IMember Call(IArgumentSet args, IPythonType self, Node callLocation = nul
141161
}
142162
}
143163

144-
return GetSpecificReturnType(self as IPythonClassType, args);
145-
}
146-
147-
#endregion
164+
// If function returns generic, determine actual type based on the passed in specific type (self).
165+
// If there is no self and no declaring type, the function is standalone.
166+
if (self == null && StaticReturnValue.IsGeneric() && Parameters.Any(p => p.IsGeneric)) {
167+
return null; // Evaluate standalone generic with arguments instead.
168+
}
169+
if (!(self is IPythonClassType selfClassType)) {
170+
return StaticReturnValue;
171+
}
148172

149-
private IMember GetSpecificReturnType(IPythonClassType selfClassType, IArgumentSet args) {
150173
var returnType = StaticReturnValue.GetPythonType();
151174
switch (returnType) {
152175
case PythonClassType cls when cls.IsGeneric():
153-
return CreateSpecificReturnFromClassType(selfClassType, cls, args); // -> A[_T1, _T2, ...]
154-
155-
case IGenericTypeDefinition gtd1 when selfClassType != null:
156-
return CreateSpecificReturnFromTypeVar(selfClassType, gtd1); // -> _T
157-
158-
case IGenericTypeDefinition gtd2 when args != null: // -> T on standalone function.
159-
return args.Arguments.FirstOrDefault(a => gtd2.Equals(a.Type))?.Value as IMember;
160-
161-
case IGenericType gt when args != null: // -> CLASS[T] on standalone function (i.e. -> List[T]).
162-
var typeArgs = ExpressionEval.GetTypeArgumentsFromParameters(this, args);
163-
return gt.CreateSpecificType(typeArgs);
164-
}
165-
166-
return null;
167-
}
168-
169-
private IMember CreateSpecificReturnFromClassType(IPythonClassType selfClassType, PythonClassType returnClassType, IArgumentSet args) {
170-
// -> A[_T1, _T2, ...]
171-
// Match arguments
172-
IReadOnlyList<IPythonType> typeArgs = null;
173-
var classGenericParameters = selfClassType?.GenericParameters.Keys.ToArray() ?? Array.Empty<string>();
174-
if (classGenericParameters.Length > 0 && selfClassType != null) {
175-
// Declaring class is specific and provides definitions of generic parameters
176-
typeArgs = classGenericParameters
177-
.Select(n => selfClassType.GenericParameters.TryGetValue(n, out var t) ? t : null)
178-
.ExcludeDefault()
179-
.ToArray();
180-
} else if (args != null) {
181-
typeArgs = ExpressionEval.GetTypeArgumentsFromParameters(this, args);
182-
}
183-
184-
if (typeArgs != null) {
185-
var specificReturnValue = returnClassType.CreateSpecificType(new ArgumentSet(typeArgs));
186-
return new PythonInstance(specificReturnValue);
176+
// -> A[_T1, _T2, ...]
177+
// Match arguments
178+
IReadOnlyList<IPythonType> typeArgs = null;
179+
var classGenericParameters = selfClassType.GenericParameters.Keys.ToArray();
180+
if (classGenericParameters.Length > 0) {
181+
// Declaring class is specific and provides definitions of generic parameters
182+
typeArgs = classGenericParameters
183+
.Select(n => selfClassType.GenericParameters.TryGetValue(n, out var t) ? t : null)
184+
.ExcludeDefault()
185+
.ToArray();
186+
} else {
187+
typeArgs = ExpressionEval.GetTypeArgumentsFromParameters(this, args);
188+
}
189+
190+
if (typeArgs != null) {
191+
var specificReturnValue = cls.CreateSpecificType(new ArgumentSet(typeArgs));
192+
return new PythonInstance(specificReturnValue);
193+
}
194+
break;
195+
196+
case IGenericTypeDefinition gtp1: {
197+
// -> _T
198+
if (selfClassType.GenericParameters.TryGetValue(gtp1.Name, out var specificType)) {
199+
return new PythonInstance(specificType);
200+
}
201+
// Try returning the constraint
202+
// TODO: improve this, the heuristic is pretty basic and tailored to simple func(_T) -> _T
203+
var name = StaticReturnValue.GetPythonType()?.Name;
204+
var typeDefVar = DeclaringModule.Analysis.GlobalScope.Variables[name];
205+
if (typeDefVar?.Value is IGenericTypeDefinition gtp2) {
206+
// See if the instance (self) type satisfies one of the constraints.
207+
return selfClassType.Mro.Any(b => gtp2.Constraints.Any(c => c.Equals(b)))
208+
? selfClassType
209+
: gtp2.Constraints.FirstOrDefault();
210+
}
211+
212+
break;
213+
}
187214
}
188-
189-
return null;
190-
}
191-
192-
private IMember CreateSpecificReturnFromTypeVar(IPythonClassType selfClassType, IGenericTypeDefinition returnType) {
193-
if (selfClassType.GenericParameters.TryGetValue(returnType.Name, out var specificType)) {
194-
return new PythonInstance(specificType);
195-
}
196-
197-
// Try returning the constraint
198-
// TODO: improve this, the heuristic is pretty basic and tailored to simple func(_T) -> _T
199-
var name = StaticReturnValue.GetPythonType()?.Name;
200-
var typeDefVar = DeclaringModule.Analysis.GlobalScope.Variables[name];
201-
if (typeDefVar?.Value is IGenericTypeDefinition gtp2) {
202-
// See if the instance (self) type satisfies one of the constraints.
203-
return selfClassType.Mro.Any(b => gtp2.Constraints.Any(c => c.Equals(b)))
204-
? selfClassType
205-
: gtp2.Constraints.FirstOrDefault();
206-
}
207-
208-
return null;
215+
return StaticReturnValue;
209216
}
217+
#endregion
210218
}
211219
}

src/Analysis/Ast/Impl/Types/PythonPropertyType.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,9 @@ public string Description
4545
=> Type == null ? Resources.PropertyOfUnknownType : Resources.PropertyOfType.FormatUI(Type.Name);
4646
public override IMember Call(IPythonInstance instance, string memberName, IArgumentSet args)
4747
=> _getter.Call(args, instance?.GetPythonType() ?? DeclaringType);
48-
public IPythonType Type => _getter?.Call(ArgumentSet.Empty, DeclaringType)?.GetPythonType();
4948
#endregion
5049

5150
internal void AddOverload(IPythonFunctionOverload overload) => _getter = _getter ?? overload;
51+
private IPythonType Type => _getter?.Call(ArgumentSet.Empty, DeclaringType)?.GetPythonType();
5252
}
5353
}

src/Analysis/Ast/Impl/Types/PythonTypeWrapper.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
using System;
1717
using System.Collections.Generic;
1818
using Microsoft.Python.Analysis.Values;
19+
using Microsoft.Python.Core.Text;
1920

2021
namespace Microsoft.Python.Analysis.Types {
2122
/// <summary>

src/Analysis/Ast/Impl/Values/Definitions/IPythonCollection.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ namespace Microsoft.Python.Analysis.Values {
2020
/// <summary>
2121
/// Represents an instance of a sequence.
2222
/// </summary>
23-
public interface IPythonCollection : IPythonInstance, IPythonIterable {
23+
public interface IPythonCollection : IPythonInstance {
2424
/// <summary>
2525
/// Collection contents
2626
/// </summary>

src/Analysis/Ast/Impl/Values/Definitions/IPythonInstance.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ namespace Microsoft.Python.Analysis.Values {
1919
/// <summary>
2020
/// Represents instance of a type.
2121
/// </summary>
22-
public interface IPythonInstance : IMember {
22+
public interface IPythonInstance : IMember, IPythonIterable {
2323
/// <summary>
2424
/// Type of the object the instance represents.
2525
/// </summary>

0 commit comments

Comments
 (0)