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

Commit 57a9a43

Browse files
author
Mikhail Arkhipov
authored
Unpacking typing Tuples and Lists correctly (#1553)
Fixes #1457 Fixes #1494 Fixes #411 Fixes #1382 Fixes #1293
1 parent eb0e081 commit 57a9a43

Some content is hidden

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

42 files changed

+497
-168
lines changed

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

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ public IMember GetValueFromCallable(CallExpression expr) {
4444
// so we can invoke Call over the instance. Second, an type info
4545
// so we can create an instance of the type (as in C() where C is class).
4646
IMember value = null;
47+
var args = ArgumentSet.Empty(expr, this);
4748
switch (target) {
4849
case IPythonBoundType bt: // Bound property, method or an iterator.
4950
value = GetValueFromBound(bt, expr);
@@ -52,7 +53,7 @@ public IMember GetValueFromCallable(CallExpression expr) {
5253
value = GetValueFromInstanceCall(pi, expr);
5354
break;
5455
case IPythonFunctionType ft: // Standalone function or a class method call.
55-
var instance = ft.DeclaringType != null ? new PythonInstance(ft.DeclaringType) : null;
56+
var instance = ft.DeclaringType?.CreateInstance(args);
5657
value = GetValueFromFunctionType(ft, instance, expr);
5758
break;
5859
case IPythonClassType cls:
@@ -61,7 +62,7 @@ public IMember GetValueFromCallable(CallExpression expr) {
6162
case IPythonType t:
6263
// Target is type (info), the call creates instance.
6364
// For example, 'x = C; y = x()' or 'x = C()' where C is class
64-
value = new PythonInstance(t);
65+
value = t.CreateInstance(args);
6566
break;
6667
}
6768

@@ -93,14 +94,14 @@ public IMember GetValueFromClassCtor(IPythonClassType cls, CallExpression expr)
9394
var init = cls.GetMember<IPythonFunctionType>(@"__init__");
9495
if (init != null) {
9596
using (OpenScope(cls.DeclaringModule, cls.ClassDefinition, out _)) {
96-
var a = new ArgumentSet(init, 0, new PythonInstance(cls), expr, this);
97+
var a = new ArgumentSet(init, 0, cls, expr, this);
9798
if (a.Errors.Count > 0) {
9899
// AddDiagnostics(Module.Uri, a.Errors);
99100
}
100101
args = a.Evaluate();
101102
}
102103
}
103-
return cls.CreateInstance(cls.Name, args);
104+
return cls.CreateInstance(args);
104105
}
105106

106107
private IMember GetValueFromBound(IPythonBoundType t, CallExpression expr) {
@@ -146,12 +147,14 @@ public IMember GetValueFromFunctionType(IPythonFunctionType fn, IPythonInstance
146147
// Pick the best overload.
147148
FunctionDefinition fd;
148149
ArgumentSet args;
150+
var instanceType = instance?.GetPythonType();
151+
149152
if (fn.Overloads.Count == 1) {
150153
fd = fn.Overloads[0].FunctionDefinition;
151-
args = new ArgumentSet(fn, 0, instance, expr, this);
154+
args = new ArgumentSet(fn, 0, instanceType, expr, this);
152155
args = args.Evaluate();
153156
} else {
154-
args = FindOverload(fn, instance, expr);
157+
args = FindOverload(fn, instanceType, expr);
155158
if (args == null) {
156159
return UnknownType;
157160
}
@@ -167,21 +170,20 @@ public IMember GetValueFromFunctionType(IPythonFunctionType fn, IPythonInstance
167170
}
168171
}
169172

170-
// If instance is not the same as the declaring type, then call most probably comes
173+
// If instance type is not the same as the declaring type, then call most probably comes
171174
// from the derived class which means that the original 'self' and 'cls' variables
172175
// are no longer valid and function has to be re-evaluated with new arguments.
173176
// Note that there is nothing to re-evaluate in stubs.
174-
var instanceType = instance?.GetPythonType();
175177
if (instanceType == null || fn.DeclaringType == null || fn.IsSpecialized ||
176178
instanceType.IsSpecialized || fn.DeclaringType.IsSpecialized ||
177179
instanceType.Equals(fn.DeclaringType) ||
178180
fn.IsStub || !string.IsNullOrEmpty(fn.Overloads[args.OverloadIndex].GetReturnDocumentation())) {
179181

180182
LoadFunctionDependencyModules(fn);
181183

182-
var t = instance?.Call(fn.Name, args) ?? fn.Call(null, fn.Name, args);
183-
if (!t.IsUnknown()) {
184-
return t;
184+
var m = instance?.Call(fn.Name, args) ?? fn.Call(null, fn.Name, args);
185+
if (!m.IsUnknown()) {
186+
return m;
185187
}
186188
}
187189

@@ -244,14 +246,14 @@ private IMember TryEvaluateWithArguments(IPythonFunctionType fn, IArgumentSet ar
244246
return result;
245247
}
246248

247-
private ArgumentSet FindOverload(IPythonFunctionType fn, IPythonInstance instance, CallExpression expr) {
249+
private ArgumentSet FindOverload(IPythonFunctionType fn, IPythonType instanceType, CallExpression expr) {
248250
if (fn.Overloads.Count == 1) {
249251
return null;
250252
}
251253

252254
var sets = new List<ArgumentSet>();
253255
for (var i = 0; i < fn.Overloads.Count; i++) {
254-
var a = new ArgumentSet(fn, i, instance, expr, this);
256+
var a = new ArgumentSet(fn, i, instanceType, expr, this);
255257
var args = a.Evaluate();
256258
sets.Add(args);
257259
}
@@ -329,7 +331,8 @@ public IReadOnlyList<IParameterInfo> CreateFunctionParameters(IPythonClassType s
329331
// The reason is that if method might be called on a derived class.
330332
// Declare self or cls in this scope.
331333
if (declareVariables) {
332-
DeclareVariable(p0.Name, new PythonInstance(self), VariableSource.Declaration, p0.NameExpression);
334+
DeclareVariable(p0.Name, self.CreateInstance(ArgumentSet.Empty(p0.NameExpression, this)),
335+
VariableSource.Declaration, p0.NameExpression);
333336
}
334337
// Set parameter info, declare type as annotation type for generic self
335338
// e.g def test(self: T)
@@ -377,7 +380,8 @@ private void DeclareParameter(Parameter p, ParameterInfo pi) {
377380
} else {
378381
paramType = pi?.DefaultValue?.GetPythonType() ?? UnknownType;
379382
}
380-
DeclareVariable(p.Name, new PythonInstance(paramType), VariableSource.Declaration, p.NameExpression);
383+
DeclareVariable(p.Name, paramType.CreateInstance(ArgumentSet.Empty(p.NameExpression, this)),
384+
VariableSource.Declaration, p.NameExpression);
381385
}
382386
}
383387
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,11 @@ public IMember GetValueFromIndex(IndexExpression expr) {
4545
var type = target.GetPythonType();
4646
if (type != null) {
4747
if (!(target is IPythonInstance instance)) {
48-
instance = new PythonInstance(type);
48+
instance = type.CreateInstance(ArgumentSet.Empty(expr, this));
4949
}
5050
var index = GetValueFromExpression(expr.Index);
5151
if (index != null) {
52-
return type.Index(instance, new ArgumentSet(new []{index}, expr, this));
52+
return type.Index(instance, new ArgumentSet(new[] { index }, expr, this));
5353
}
5454
}
5555

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public IPythonInstance GetConstantFromLiteral(Expression expr) {
3838
}
3939

4040
var t = SuppressBuiltinLookup ? UnknownType : (GetTypeFromLiteral(expr) ?? UnknownType);
41-
return new PythonInstance(t);
41+
return t.CreateInstance(ArgumentSet.Empty(expr, this));
4242
}
4343

4444
public IPythonType GetTypeFromLiteral(Expression expr) {

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,12 +172,12 @@ private IMember CreateClassInstance(PythonClassType cls, IReadOnlyList<IMember>
172172
var initOverload = initFunc?.DeclaringType == cls ? initFunc.Overloads.FirstOrDefault() : null;
173173

174174
var argSet = initOverload != null
175-
? new ArgumentSet(initFunc, 0, null, callExpr, this)
175+
? new ArgumentSet(initFunc, 0, cls, callExpr, this)
176176
: new ArgumentSet(constructorArguments, callExpr, this);
177177

178178
argSet.Evaluate();
179179
var specificType = cls.CreateSpecificType(argSet);
180-
return new PythonInstance(specificType);
180+
return specificType.CreateInstance(argSet);
181181
}
182182

183183
private ScopeStatement GetScope(IMember m) {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ private IMember GetValueFromMember(MemberExpression expr) {
258258
f.AddReference(GetLocationOfName(expr));
259259
return f.ToUnbound();
260260
}
261-
instance = new PythonInstance(type);
261+
instance = type.CreateInstance(ArgumentSet.Empty(expr, this));
262262
}
263263

264264
instance = instance ?? m as IPythonInstance;

src/Analysis/Ast/Impl/Analyzer/Handlers/AssignmentHandler.cs

Lines changed: 43 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@
1313
// See the Apache Version 2.0 License for specific language governing
1414
// permissions and limitations under the License.
1515

16-
using System.Diagnostics;
17-
using System.Linq;
1816
using Microsoft.Python.Analysis.Types;
1917
using Microsoft.Python.Analysis.Values;
2018
using Microsoft.Python.Core;
2119
using Microsoft.Python.Parsing.Ast;
20+
using System.Diagnostics;
21+
using System.Linq;
2222

2323
namespace Microsoft.Python.Analysis.Analyzer.Handlers {
2424
internal sealed class AssignmentHandler : StatementHandler {
@@ -30,10 +30,12 @@ public void HandleAssignment(AssignmentStatement node) {
3030
}
3131

3232
var value = Eval.GetValueFromExpression(node.Right) ?? Eval.UnknownType;
33+
// Filter out parenthesis expression in assignment because it makes no difference.
34+
var lhs = node.Left.Select(s => s.RemoveParenthesis());
3335
// Check PEP hint first
3436
var valueType = Eval.GetTypeFromPepHint(node.Right);
3537
if (valueType != null) {
36-
HandleTypedVariable(valueType, value, node.Left.FirstOrDefault());
38+
HandleTypedVariable(valueType, value, lhs.FirstOrDefault());
3739
return;
3840
}
3941

@@ -44,44 +46,49 @@ public void HandleAssignment(AssignmentStatement node) {
4446
value = Eval.UnknownType;
4547
}
4648

47-
if (node.Left.FirstOrDefault() is SequenceExpression seq) {
48-
// Tuple = Tuple. Transfer values.
49-
var seqHandler = new SequenceExpressionHandler(Walker);
50-
seqHandler.HandleAssignment(seq.Items, node.Right, value);
51-
return;
49+
foreach (var expr in lhs) {
50+
switch (expr) {
51+
case SequenceExpression seq:
52+
// Tuple = Tuple. Transfer values.
53+
var seqHandler = new SequenceExpressionHandler(Walker);
54+
seqHandler.HandleAssignment(seq, value);
55+
break;
56+
case ExpressionWithAnnotation annExpr:
57+
HandleAnnotatedExpression(annExpr, value);
58+
break;
59+
case NameExpression nameExpr:
60+
HandleNameExpression(nameExpr, value);
61+
break;
62+
case MemberExpression memberExpr:
63+
TryHandleClassVariable(memberExpr, value);
64+
break;
65+
}
5266
}
67+
}
5368

54-
// Process annotations, if any.
55-
foreach (var expr in node.Left.OfType<ExpressionWithAnnotation>()) {
56-
// x: List[str] = [...]
57-
HandleAnnotatedExpression(expr, value);
58-
}
69+
private bool IsValidAssignment(string name, Location loc) => !Eval.GetInScope(name).IsDeclaredAfter(loc);
5970

60-
foreach (var ne in node.Left.OfType<NameExpression>()) {
61-
IScope scope;
62-
if (Eval.CurrentScope.NonLocals[ne.Name] != null) {
63-
Eval.LookupNameInScopes(ne.Name, out scope, LookupOptions.Nonlocal);
64-
scope?.Variables[ne.Name].Assign(value, Eval.GetLocationOfName(ne));
65-
continue;
66-
}
67-
if (Eval.CurrentScope.Globals[ne.Name] != null) {
68-
Eval.LookupNameInScopes(ne.Name, out scope, LookupOptions.Global);
69-
scope?.Variables[ne.Name].Assign(value, Eval.GetLocationOfName(ne));
70-
continue;
71-
}
71+
private void HandleNameExpression(NameExpression ne, IMember value) {
72+
IScope scope;
73+
if (Eval.CurrentScope.NonLocals[ne.Name] != null) {
74+
Eval.LookupNameInScopes(ne.Name, out scope, LookupOptions.Nonlocal);
75+
scope?.Variables[ne.Name].Assign(value, Eval.GetLocationOfName(ne));
76+
return;
77+
}
7278

73-
var source = value.IsGeneric() ? VariableSource.Generic : VariableSource.Declaration;
74-
var location = Eval.GetLocationOfName(ne);
75-
if (IsValidAssignment(ne.Name, location)) {
76-
Eval.DeclareVariable(ne.Name, value ?? Module.Interpreter.UnknownType, source, location);
77-
}
79+
if (Eval.CurrentScope.Globals[ne.Name] != null) {
80+
Eval.LookupNameInScopes(ne.Name, out scope, LookupOptions.Global);
81+
scope?.Variables[ne.Name].Assign(value, Eval.GetLocationOfName(ne));
82+
return;
7883
}
7984

80-
TryHandleClassVariable(node, value);
85+
var source = value.IsGeneric() ? VariableSource.Generic : VariableSource.Declaration;
86+
var location = Eval.GetLocationOfName(ne);
87+
if (IsValidAssignment(ne.Name, location)) {
88+
Eval.DeclareVariable(ne.Name, value ?? Module.Interpreter.UnknownType, source, location);
89+
}
8190
}
8291

83-
private bool IsValidAssignment(string name, Location loc) => !Eval.GetInScope(name).IsDeclaredAfter(loc);
84-
8592
public void HandleAnnotatedExpression(ExpressionWithAnnotation expr, IMember value) {
8693
if (expr?.Annotation == null) {
8794
return;
@@ -95,8 +102,7 @@ public void HandleAnnotatedExpression(ExpressionWithAnnotation expr, IMember val
95102
HandleTypedVariable(variableType, value, expr.Expression);
96103
}
97104

98-
private void TryHandleClassVariable(AssignmentStatement node, IMember value) {
99-
var mex = node.Left.OfType<MemberExpression>().FirstOrDefault();
105+
private void TryHandleClassVariable(MemberExpression mex, IMember value) {
100106
if (!string.IsNullOrEmpty(mex?.Name) && mex.Target is NameExpression nex && nex.Name.EqualsOrdinal("self")) {
101107
var m = Eval.LookupNameInScopes(nex.Name, out _, LookupOptions.Local);
102108
var cls = m.GetPythonType<IPythonClassType>();
@@ -121,7 +127,8 @@ private void HandleTypedVariable(IPythonType variableType, IMember value, Expres
121127
instance = value;
122128
}
123129
}
124-
instance = instance ?? variableType?.CreateInstance(variableType.Name, ArgumentSet.Empty(expr, Eval)) ?? Eval.UnknownType;
130+
var args = ArgumentSet.Empty(expr, Eval);
131+
instance = instance ?? variableType?.CreateInstance(args) ?? Eval.UnknownType.CreateInstance(ArgumentSet.WithoutContext);
125132

126133
if (expr is NameExpression ne) {
127134
Eval.DeclareVariable(ne.Name, instance, VariableSource.Declaration, ne);

src/Analysis/Ast/Impl/Analyzer/Handlers/LoopHandler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public bool HandleFor(ForStatement node) {
3535
// x = [('abc', 42, True), ('abc', 23, False)]
3636
// for some_str, (some_int, some_bool) in x:
3737
var h = new SequenceExpressionHandler(Walker);
38-
h.HandleAssignment(seq.Items, node.List, value);
38+
h.HandleAssignment(seq, value);
3939
break;
4040
}
4141

0 commit comments

Comments
 (0)