Skip to content

Commit d7ea3c5

Browse files
authored
Enable nullable annotations in Super (#1534)
1 parent bce8b54 commit d7ea3c5

File tree

2 files changed

+53
-21
lines changed

2 files changed

+53
-21
lines changed

Src/IronPython/Runtime/Super.cs

Lines changed: 35 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@
22
// The .NET Foundation licenses this file to you under the Apache 2.0 License.
33
// See the LICENSE file in the project root for more information.
44

5+
#nullable enable
6+
7+
using System;
58
using System.Collections.Generic;
69
using System.Diagnostics;
10+
using System.Diagnostics.CodeAnalysis;
711
using System.Runtime.CompilerServices;
812

913
using Microsoft.Scripting;
@@ -15,9 +19,10 @@
1519
namespace IronPython.Runtime {
1620
[PythonType("super")]
1721
public class Super : PythonTypeSlot, ICodeFormattable {
18-
private PythonType _thisClass;
19-
private object _self;
20-
private object _selfClass;
22+
[DisallowNull]
23+
private PythonType? _thisClass; // set during __init__
24+
private object? _self;
25+
private object? _selfClass;
2126

2227
public Super() {
2328
}
@@ -28,12 +33,14 @@ public void __init__() {
2833
throw PythonOps.RuntimeError("super(): no arguments");
2934
}
3035

31-
public void __init__(PythonType type) {
36+
public void __init__([NotNone] PythonType type) {
3237
__init__(type, null);
3338
}
3439

35-
public void __init__(PythonType type, object obj) {
36-
if (obj != null) {
40+
public void __init__([NotNone] PythonType type, object? obj) {
41+
if (type is null) throw new ArgumentNullException(nameof(type));
42+
43+
if (obj is not null) {
3744
if (PythonOps.IsInstance(obj, type)) {
3845
_thisClass = type;
3946
_self = obj;
@@ -52,22 +59,29 @@ public void __init__(PythonType type, object obj) {
5259
}
5360
}
5461

55-
public PythonType __thisclass__ {
62+
public PythonType? __thisclass__ {
5663
get { return _thisClass; }
5764
}
5865

59-
public object __self__ {
66+
public object? __self__ {
6067
get { return _self; }
6168
}
6269

63-
public object __self_class__ {
70+
public object? __self_class__ {
6471
get { return _selfClass; }
6572
}
6673

67-
public new object __get__(CodeContext/*!*/ context, object instance, object owner) {
74+
public new object? __get__(CodeContext/*!*/ context, object? instance, object? owner = null) {
75+
if (instance is null && owner is null) {
76+
throw PythonOps.TypeError("__get__(None, None) is invalid");
77+
}
78+
6879
PythonType selfType = PythonType;
6980

7081
if (selfType == TypeCache.Super) {
82+
if (_thisClass is null) {
83+
throw PythonOps.TypeError("super(): __init__ not called");
84+
}
7185
Super res = new Super();
7286
res.__init__(_thisClass, instance);
7387
return res;
@@ -81,10 +95,10 @@ public object __self_class__ {
8195
#region Custom member access
8296

8397
[SpecialName]
84-
public object GetCustomMember(CodeContext context, string name) {
98+
public object GetCustomMember(CodeContext context, [NotNone] string name) {
8599
// first find where we are in the mro...
86-
object value;
87-
if (_selfClass is PythonType mroType) { // can be null if the user does super.__new__
100+
object? value;
101+
if (_selfClass is PythonType mroType && _thisClass is not null) { // can be null if the user does super.__new__
88102
IList<PythonType> mro = mroType.ResolutionOrder;
89103

90104
int lookupType;
@@ -105,7 +119,7 @@ public object GetCustomMember(CodeContext context, string name) {
105119
}
106120

107121
// if we're super on a class then we have no self.
108-
object self = _self == _selfClass ? null : _self;
122+
object? self = _self == _selfClass ? null : _self;
109123

110124
// then skip our class, and lookup in everything
111125
// above us until we get a hit.
@@ -127,16 +141,16 @@ public object GetCustomMember(CodeContext context, string name) {
127141
}
128142

129143
[SpecialName]
130-
public void SetMember(CodeContext context, string name, object value) {
144+
public void SetMember(CodeContext context, [NotNone] string name, object? value) {
131145
PythonType.SetMember(context, this, name, value);
132146
}
133147

134148
[SpecialName]
135-
public void DeleteCustomMember(CodeContext context, string name) {
149+
public void DeleteCustomMember(CodeContext context, [NotNone] string name) {
136150
PythonType.DeleteMember(context, this, name);
137151
}
138152

139-
private bool TryLookupInBase(CodeContext context, PythonType pt, string name, object self, out object value) {
153+
private bool TryLookupInBase(CodeContext context, PythonType pt, string name, object? self, [NotNullWhen(true)] out object? value) {
140154
// new-style class, or reflected type, lookup slot
141155
if (pt.TryLookupSlot(context, name, out PythonTypeSlot dts) &&
142156
dts.TryGetValue(context, self, DescriptorContext, out value)) {
@@ -146,7 +160,7 @@ private bool TryLookupInBase(CodeContext context, PythonType pt, string name, ob
146160
return false;
147161
}
148162

149-
private PythonType DescriptorContext {
163+
private PythonType? DescriptorContext {
150164
get {
151165
if (!DynamicHelpers.GetPythonType(_self).IsSubclassOf(_thisClass)) {
152166
if(_self == _selfClass) // Using @classmethod
@@ -164,16 +178,16 @@ private PythonType PythonType {
164178
if (GetType() == typeof(Super))
165179
return TypeCache.Super;
166180

167-
IPythonObject sdo = this as IPythonObject;
168-
Debug.Assert(sdo != null);
181+
Debug.Assert(this is IPythonObject);
182+
IPythonObject sdo = (IPythonObject)this;
169183

170184
return sdo.PythonType;
171185
}
172186
}
173187

174188
#endregion
175189

176-
internal override bool TryGetValue(CodeContext context, object instance, PythonType owner, out object value) {
190+
internal override bool TryGetValue(CodeContext context, object? instance, PythonType? owner, out object? value) {
177191
value = __get__(context, instance, owner);
178192
return true;
179193
}

Tests/test_inheritance.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1367,6 +1367,24 @@ def __new__(cls):
13671367

13681368
c = C()
13691369

1370+
def test_super_errors(self):
1371+
# Test that TyypeError is raised, rather than pass or SystemError: Object reference not set to an instance of an object.
1372+
1373+
with self.assertRaises(TypeError):
1374+
super(None)
1375+
with self.assertRaises(TypeError):
1376+
super(None, None)
1377+
1378+
x = super.__new__(super)
1379+
with self.assertRaises(TypeError):
1380+
x.__init__(None)
1381+
with self.assertRaises(TypeError):
1382+
x.__get__(None, None)
1383+
with self.assertRaises(TypeError):
1384+
x.__get__(int, None)
1385+
with self.assertRaises(TypeError):
1386+
x.__get__(1, None)
1387+
13701388
@skipUnlessIronPython()
13711389
def test_inherit_mixed_properties(self):
13721390
from IronPythonTest import MixedPropertiesInherited, MixedProperties

0 commit comments

Comments
 (0)