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

Commit 15a0f4e

Browse files
authored
Adding super as a specialized keyword (#1702)
* wip adding super as a specialized keyword * moving super logic into its own type * slimed down super * -refactorings -adding multi param support -adding tests around gotoDefinition (still broken) * refacting to better parse the second parameter of super * adding more edge cases to tests, and fixes for them * Updates for gotoDefinition tests to succeed * adding test for generic with super refactoing python 2.7 two param super(..) I was using the mro from the frist param always, but it should be the second. - new helper functions IsInstanceOf() and IsSubClass() * refactor removing IsInstanceOf removing nested if * Now filter GetMemberNames using distinct Added Distinct completion tests * replacing Count() with Count * adding copywrite and formatting * refactor to condense null checks minor fixups * Adding tests for current missing super support - multiple inheritance test - persistence test * updating persistence test removing unused json for now * changing ClassesWithSuper() to return super so that it tests persistence of the super type * Adding variable and member checks. currently HaveSameMemberAs() is asserting in debug do to no model found for super. * changing asser.inconclusive to [ignore] * Persistence update: - changing qualified name to :SuperType - trimming the leading ":" from builttin types * removing white space * new test file SyperTypeTests moving createSuper(..) to PythonSuperTypes * removing duplicate tests * adding namedtuple test
1 parent 76c8f18 commit 15a0f4e

File tree

13 files changed

+637
-11
lines changed

13 files changed

+637
-11
lines changed

src/Analysis/Ast/Impl/Extensions/PythonClassExtensions.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
using Microsoft.Python.Analysis.Analyzer;
1818
using Microsoft.Python.Analysis.Specializations.Typing;
1919
using Microsoft.Python.Analysis.Types;
20+
using Microsoft.Python.Analysis.Values;
2021
using Microsoft.Python.Core;
2122

2223
namespace Microsoft.Python.Analysis {
@@ -77,5 +78,12 @@ public static bool GetSpecificType(this IPythonClassType cls, string paramName,
7778
}
7879
return specificType != null;
7980
}
81+
82+
public static bool IsSubClassOf(this IPythonClassType cls, IPythonClassType classToCheck) {
83+
if (classToCheck == null) {
84+
return false;
85+
}
86+
return cls?.Bases.MaybeEnumerate().Any(b => b.Equals(classToCheck)) ?? false;
87+
}
8088
}
8189
}

src/Analysis/Ast/Impl/Modules/BuiltinsPythonModule.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,9 +174,9 @@ private void SpecializeFunctions() {
174174
Analysis.SpecializeFunction("type", BuiltinsSpecializations.TypeInfo);
175175
Analysis.SpecializeFunction("vars", BuiltinsSpecializations.DictStringToObject);
176176

177+
Analysis.SpecializeFunction("super", BuiltinsSpecializations.Super);
177178
//SpecializeFunction(_builtinName, "range", RangeConstructor);
178179
//SpecializeFunction(_builtinName, "sorted", ReturnsListOfInputIterable);
179-
//SpecializeFunction(_builtinName, "super", SpecialSuper);
180180
}
181181

182182
private IReadOnlyList<ParameterInfo> OpenConstructor() {

src/Analysis/Ast/Impl/Specializations/BuiltinsSpecializations.cs

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
// See the Apache Version 2.0 License for specific language governing
1414
// permissions and limitations under the License.
1515

16+
using System;
1617
using System.Linq;
1718
using Microsoft.Python.Analysis.Specializations.Typing.Types;
1819
using Microsoft.Python.Analysis.Specializations.Typing.Values;
@@ -21,6 +22,7 @@
2122
using Microsoft.Python.Analysis.Values;
2223
using Microsoft.Python.Analysis.Values.Collections;
2324
using Microsoft.Python.Core.Text;
25+
using Microsoft.Python.Parsing.Ast;
2426

2527
namespace Microsoft.Python.Analysis.Specializations {
2628
public static class BuiltinsSpecializations {
@@ -91,6 +93,40 @@ public static IMember CollectionItem(IPythonModule module, IPythonFunctionOverlo
9193
return args.Count > 0 && args[0] is PythonCollection c ? c.Contents.FirstOrDefault() : null;
9294
}
9395

96+
public static IMember Super(IPythonModule declaringModule, IPythonFunctionOverload overload, IArgumentSet argSet, IndexSpan indexSpan) {
97+
var args = argSet.Values<IMember>();
98+
99+
if (args.Count == 0) {
100+
//Zero argument form only works inside a class definition
101+
foreach (var s in argSet.Eval.CurrentScope.EnumerateTowardsGlobal.Where(s => s.Node is ClassDefinition)) {
102+
var classType = s.Variables["__class__"].GetPythonType<IPythonClassType>();
103+
return PythonSuperType.CreateSuper(classType)?.CreateInstance(argSet);
104+
}
105+
return null;
106+
}
107+
108+
// If multiple arguments first argument is required
109+
var firstCls = args.FirstOrDefault().GetPythonType<IPythonClassType>();
110+
if (firstCls == null) {
111+
return null;
112+
}
113+
114+
// second argument optional
115+
bool isUnbound = args.Count == 1;
116+
if (isUnbound) {
117+
return PythonSuperType.CreateSuper(firstCls)?.CreateInstance(argSet);
118+
}
119+
120+
var secondCls = args[1].GetPythonType<IPythonClassType>();
121+
if (secondCls?.Equals(firstCls) == true ||
122+
secondCls?.IsSubClassOf(firstCls) == true) {
123+
// We walk the mro of the second parameter looking for the first
124+
return PythonSuperType.CreateSuper(secondCls, typeToFind: firstCls)?.CreateInstance(argSet);
125+
}
126+
127+
return null;
128+
}
129+
94130
public static IMember Open(IPythonModule declaringModule, IPythonFunctionOverload overload, IArgumentSet argSet, IndexSpan indexSpan) {
95131
var mode = argSet.GetArgumentValue<IPythonConstant>("mode");
96132

@@ -141,7 +177,7 @@ public static IMember GetAttr(IPythonModule module, IPythonFunctionOverload over
141177
// getattr(a, 3.14)
142178
if (name == null) {
143179
// TODO diagnostic error when second arg of getattr is not a string
144-
return module.Interpreter.UnknownType;
180+
return module.Interpreter.UnknownType;
145181
}
146182

147183
return o?.GetPythonType().GetMember(name) ?? def;
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright(c) Microsoft Corporation
2+
// All rights reserved.
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the License); you may not use
5+
// this file except in compliance with the License. You may obtain a copy of the
6+
// License at http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS
9+
// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY
10+
// IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
11+
// MERCHANTABILITY OR NON-INFRINGEMENT.
12+
//
13+
// See the Apache Version 2.0 License for specific language governing
14+
// permissions and limitations under the License.
15+
16+
using System.Collections.Generic;
17+
18+
namespace Microsoft.Python.Analysis.Types {
19+
/// <summary>
20+
/// Represents Python class type definition.
21+
/// </summary>
22+
public interface IPythonSuperType {
23+
/// <summary>
24+
/// Python Method Resolution Order (MRO).
25+
/// </summary>
26+
IReadOnlyList<IPythonType> Mro { get; }
27+
}
28+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// Copyright(c) Microsoft Corporation
2+
// All rights reserved.
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the License); you may not use
5+
// this file except in compliance with the License. You may obtain a copy of the
6+
// License at http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS
9+
// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY
10+
// IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
11+
// MERCHANTABILITY OR NON-INFRINGEMENT.
12+
//
13+
// See the Apache Version 2.0 License for specific language governing
14+
// permissions and limitations under the License.
15+
16+
using System;
17+
using System.Collections.Generic;
18+
using System.Linq;
19+
using Microsoft.Python.Core;
20+
21+
namespace Microsoft.Python.Analysis.Types {
22+
internal sealed class PythonSuperType : PythonType, IPythonSuperType {
23+
/// <summary>
24+
/// more info at https://docs.python.org/3/library/functions.html#super
25+
/// </summary>
26+
/// <param name="location"></param>
27+
/// <param name="mro">Should be a list of IPythonType</param>
28+
public PythonSuperType(IReadOnlyList<IPythonType> mro)
29+
: base("super", new Location(), string.Empty, BuiltinTypeId.Type) {
30+
Mro = mro;
31+
}
32+
33+
public override string QualifiedName => $":SuperType[{string.Join(",", Mro.Select(t => t.QualifiedName))}]";
34+
35+
public IReadOnlyList<IPythonType> Mro { get; }
36+
37+
public override IMember GetMember(string name) => Mro.MaybeEnumerate().Select(c => c.GetMember(name)).ExcludeDefault().FirstOrDefault();
38+
39+
public override IEnumerable<string> GetMemberNames() => Mro.MaybeEnumerate().SelectMany(cls => cls.GetMemberNames()).Distinct();
40+
41+
42+
/// <summary>
43+
/// This will return PythonSuperType with a mro list that starts with the next class in line in classType's mro,
44+
/// or it will search classType's mro for typeToFild then build an mro list for the remaining classses after typeToFind.
45+
/// </summary>
46+
/// <param name="classType"></param>
47+
/// <param name="typeToFind"></param>
48+
/// <returns></returns>
49+
internal static PythonSuperType CreateSuper(IPythonClassType classType, IPythonType typeToFind = null) {
50+
var mro = classType?.Mro ?? Array.Empty<IPythonType>();
51+
if (mro.Count == 0) {
52+
return null;
53+
}
54+
55+
// skip doing work if the newStartType is the first element in the callers mro
56+
if (typeToFind?.Equals(classType.Mro.FirstOrDefault()) == false) {
57+
var mroList = classType.Mro.ToList();
58+
var start = mroList.FindIndex(0, t => t.Equals(typeToFind));
59+
if (start >= 0) {
60+
mro = mroList.GetRange(start, mro.Count - start).ToArray();
61+
} else {
62+
return null; // typeToFind wasn't in the mro
63+
}
64+
}
65+
66+
var nextClassInLine = mro?.FirstOrDefault();
67+
if (nextClassInLine != null) {
68+
// Skip the first element, super's search starts at the next elemement in the mro for both super() and super(cls, typeToFind)
69+
return new PythonSuperType(mro.Skip(1).ToArray());
70+
}
71+
72+
return null;
73+
}
74+
}
75+
}
76+

0 commit comments

Comments
 (0)