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

Commit

Permalink
Fix null ref in super() (#1739)
Browse files Browse the repository at this point in the history
* Remove stale reference

* Super declaring module

* Persistence

* Use builtins
  • Loading branch information
Mikhail Arkhipov authored Nov 2, 2019
1 parent bf86615 commit cf915c3
Show file tree
Hide file tree
Showing 5 changed files with 28 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public static IMember Super(IPythonModule declaringModule, IPythonFunctionOverlo
//Zero argument form only works inside a class definition
foreach (var s in argSet.Eval.CurrentScope.EnumerateTowardsGlobal.Where(s => s.Node is ClassDefinition)) {
var classType = s.Variables["__class__"].GetPythonType<IPythonClassType>();
return PythonSuperType.CreateSuper(classType)?.CreateInstance(argSet);
return PythonSuperType.Create(classType)?.CreateInstance(argSet);
}
return null;
}
Expand All @@ -114,14 +114,14 @@ public static IMember Super(IPythonModule declaringModule, IPythonFunctionOverlo
// second argument optional
bool isUnbound = args.Count == 1;
if (isUnbound) {
return PythonSuperType.CreateSuper(firstCls)?.CreateInstance(argSet);
return PythonSuperType.Create(firstCls)?.CreateInstance(argSet);
}

var secondCls = args[1].GetPythonType<IPythonClassType>();
if (secondCls?.Equals(firstCls) == true ||
secondCls?.IsSubClassOf(firstCls) == true) {
// We walk the mro of the second parameter looking for the first
return PythonSuperType.CreateSuper(secondCls, typeToFind: firstCls)?.CreateInstance(argSet);
return PythonSuperType.Create(secondCls, typeToFind: firstCls)?.CreateInstance(argSet);
}

return null;
Expand Down
6 changes: 5 additions & 1 deletion src/Analysis/Ast/Impl/Types/LocatedMember.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,16 @@
using System.Linq;
using Microsoft.Python.Analysis.Modules;
using Microsoft.Python.Core;
using Microsoft.Python.Core.Diagnostics;

namespace Microsoft.Python.Analysis.Types {
internal abstract class LocatedMember : ILocatedMember {
private HashSet<Location> _references;

protected LocatedMember(IPythonModule module) : this(new Location(module)) { }
protected LocatedMember(IPythonModule module) : this(new Location(module)) {
Check.InvalidOperation(module != null || this is IPythonModule,
"Located member can only have null declaring module if it is the module.");
}

protected LocatedMember(Location location) {
Location = location;
Expand Down
4 changes: 1 addition & 3 deletions src/Analysis/Ast/Impl/Types/Location.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@

namespace Microsoft.Python.Analysis.Types {
public readonly struct Location {
public Location(IPythonModule module) : this(module, default) { }

public Location(IPythonModule module, IndexSpan indexSpan) {
public Location(IPythonModule module, IndexSpan indexSpan = default) {
Module = module;
IndexSpan = indexSpan;
}
Expand Down
37 changes: 18 additions & 19 deletions src/Analysis/Ast/Impl/Types/PythonSuperType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,34 +21,37 @@
namespace Microsoft.Python.Analysis.Types {
internal sealed class PythonSuperType : PythonType, IPythonSuperType {
/// <summary>
/// more info at https://docs.python.org/3/library/functions.html#super
/// Implements 'super' specialization type.
/// See also https://docs.python.org/3/library/functions.html#super
/// </summary>
/// <param name="location"></param>
/// <param name="mro">Should be a list of IPythonType</param>
public PythonSuperType(IReadOnlyList<IPythonType> mro)
: base("super", new Location(), string.Empty, BuiltinTypeId.Type) {
/// <param name="mro">The derived class MRO.</param>
/// <param name="builtins">Builtins module.</param>
public PythonSuperType(IReadOnlyList<IPythonType> mro, IBuiltinsPythonModule builtins)
: base("super", new Location(builtins), string.Empty, BuiltinTypeId.Type) {
Mro = mro;
}

public override string QualifiedName => $":SuperType[{string.Join(",", Mro.Select(t => t.QualifiedName))}]";

public IReadOnlyList<IPythonType> Mro { get; }

public override IMember GetMember(string name) => Mro.MaybeEnumerate().Select(c => c.GetMember(name)).ExcludeDefault().FirstOrDefault();

public override IEnumerable<string> GetMemberNames() => Mro.MaybeEnumerate().SelectMany(cls => cls.GetMemberNames()).Distinct();
public override IMember GetMember(string name)
=> Mro.MaybeEnumerate().Select(c => c.GetMember(name)).ExcludeDefault().FirstOrDefault();

public override IEnumerable<string> GetMemberNames()
=> Mro.MaybeEnumerate().SelectMany(cls => cls.GetMemberNames()).Distinct();

/// <summary>
/// This will return PythonSuperType with a mro list that starts with the next class in line in classType's mro,
/// or it will search classType's mro for typeToFild then build an mro list for the remaining classses after typeToFind.
/// Creates PythonSuperType with a MRO list that starts with the next class in line in classType's MRO,
/// or searches classType's MRO for <see cref="typeToFind"/>, then builds an MRO list for
/// the remaining classes after <see cref="typeToFind"/>.
/// </summary>
/// <param name="classType"></param>
/// <param name="typeToFind"></param>
/// <returns></returns>
internal static PythonSuperType CreateSuper(IPythonClassType classType, IPythonType typeToFind = null) {
internal static PythonSuperType Create(IPythonClassType classType, IPythonType typeToFind = null) {
var mro = classType?.Mro ?? Array.Empty<IPythonType>();
if (mro.Count == 0) {
if (classType == null || mro.Count == 0) {
return null;
}

Expand All @@ -64,13 +67,9 @@ internal static PythonSuperType CreateSuper(IPythonClassType classType, IPythonT
}

var nextClassInLine = mro?.FirstOrDefault();
if (nextClassInLine != null) {
// Skip the first element, super's search starts at the next elemement in the mro for both super() and super(cls, typeToFind)
return new PythonSuperType(mro.Skip(1).ToArray());
}

return null;
var builtins = classType.DeclaringModule.Interpreter.ModuleResolution.BuiltinsModule;
// Skip the first element, super's search starts at the next element in the mro for both super() and super(cls, typeToFind)
return nextClassInLine != null ? new PythonSuperType(mro.Skip(1).ToArray(), builtins) : null;
}
}
}

2 changes: 1 addition & 1 deletion src/Caching/Impl/ModuleFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ private IMember GetBuiltinMember(IBuiltinsPythonModule builtins, string memberNa
case "Unknown":
return builtins.Interpreter.UnknownType;
case "SuperType":
return new PythonSuperType(typeArgs);
return new PythonSuperType(typeArgs, builtins);
}
return builtins.GetMember(memberName);
}
Expand Down

0 comments on commit cf915c3

Please sign in to comment.