Skip to content

Commit fa8629e

Browse files
committed
checkpoint
1 parent 3fccfd5 commit fa8629e

File tree

11 files changed

+516
-147
lines changed

11 files changed

+516
-147
lines changed

pythonnet/src/runtime/arrayobject.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,6 @@ public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) {
3939
return IntPtr.Zero;
4040
}
4141
return CLRObject.GetInstHandle(result, tp);
42-
string message = "cannot instantiate array wrapper";
43-
return Exceptions.RaiseTypeError(message);
4442
}
4543

4644

pythonnet/src/runtime/assemblymanager.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,8 @@ public static bool IsValidNamespace(string name) {
327327

328328
public static List<string> GetNames(string nsname) {
329329
List<string> names = new List<string>(32);
330+
Dictionary<string, int> seen = new Dictionary<string, int>();
331+
330332
if (namespaces.ContainsKey(nsname)) {
331333
foreach (Assembly a in namespaces[nsname].Keys) {
332334
Type[] types = a.GetTypes();
@@ -347,6 +349,7 @@ public static List<string> GetNames(string nsname) {
347349
}
348350
}
349351
}
352+
names.Sort(); // ensure that non-generics come first!
350353
return names;
351354
}
352355

pythonnet/src/runtime/classbase.cs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ internal class ClassBase : ManagedType {
2828

2929
internal bool is_exception;
3030
internal Indexer indexer;
31+
internal Type[] generics;
3132
internal Type type;
3233

3334
internal ClassBase(Type tp) : base() {
@@ -40,8 +41,6 @@ internal virtual bool CanSubclass() {
4041
return (!this.type.IsEnum);
4142
}
4243

43-
44-
4544
//====================================================================
4645
// Implements __init__ for reflected classes and value types.
4746
//====================================================================
@@ -50,15 +49,13 @@ public static int tp_init(IntPtr ob, IntPtr args, IntPtr kw) {
5049
return 0;
5150
}
5251

53-
5452
//====================================================================
5553
// Default implementation of [] semantics for reflected types.
5654
//====================================================================
5755

58-
public virtual IntPtr type_subscript(IntPtr ob, IntPtr idx) {
59-
return Exceptions.RaiseTypeError("unsubscriptable object");
60-
}
61-
56+
public virtual IntPtr type_subscript(IntPtr idx) {
57+
return Exceptions.RaiseTypeError("unsubscriptable object");
58+
}
6259

6360
//====================================================================
6461
// Standard comparison implementation for instances of reflected types.

pythonnet/src/runtime/classmanager.cs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -80,16 +80,12 @@ private static ClassBase CreateClass(Type type) {
8080
// lets us check once (vs. on every lookup) in case we need to
8181
// wrap Exception-derived types in old-style classes
8282

83-
if (type.IsSubclassOf(dtype)) {
84-
impl = new DelegateObject(type);
85-
}
86-
87-
else if (type.ContainsGenericParameters) {
83+
if (type.ContainsGenericParameters) {
8884
impl = new GenericType(type);
8985
}
9086

91-
else if (type.IsGenericType) {
92-
impl = new GenericType(type);
87+
else if (type.IsSubclassOf(dtype)) {
88+
impl = new DelegateObject(type);
9389
}
9490

9591
else if (type.IsArray) {

pythonnet/src/runtime/classobject.cs

Lines changed: 44 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,10 @@ namespace Python.Runtime {
2222
internal class ClassObject : ClassBase {
2323

2424
ConstructorBinder binder;
25+
ConstructorInfo[] ctors;
2526

2627
internal ClassObject(Type tp) : base(tp) {
27-
ConstructorInfo[] ctors = type.GetConstructors();
28+
ctors = type.GetConstructors();
2829
binder = new ConstructorBinder();
2930

3031
for (int i = 0; i < ctors.Length; i++) {
@@ -125,28 +126,49 @@ public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) {
125126

126127

127128
//====================================================================
128-
// Implementation of [] semantics for reflected types. This mainly
129-
// exists to implement the Array[int] syntax for creating arrays.
129+
// Implementation of [] semantics for reflected types. This exists
130+
// both to implement the Array[int] syntax for creating arrays and
131+
// to support generic name overload resolution using [].
130132
//====================================================================
131133

132-
public override IntPtr type_subscript(IntPtr ob, IntPtr idx) {
133-
if ((this.type) != typeof(Array)) {
134-
return Exceptions.RaiseTypeError("unsubscriptable object");
135-
}
136-
137-
if (Runtime.PyTuple_Check(idx)) {
138-
return Exceptions.RaiseTypeError("expected single type");
139-
}
140-
141-
ClassBase c = GetManagedObject(idx) as ClassBase;
142-
Type t = (c != null) ? c.type : Converter.GetTypeByAlias(idx);
143-
if (t == null) {
144-
return Exceptions.RaiseTypeError("type expected");
145-
}
146-
Array a = Array.CreateInstance(t, 0);
147-
c = ClassManager.GetClass(a.GetType());
148-
Runtime.Incref(c.pyHandle);
149-
return c.pyHandle;
134+
public override IntPtr type_subscript(IntPtr idx) {
135+
136+
// If this type is the Array type, the [<type>] means we need to
137+
// construct and return an array type of the given element type.
138+
139+
if ((this.type) == typeof(Array)) {
140+
if (Runtime.PyTuple_Check(idx)) {
141+
return Exceptions.RaiseTypeError("type expected");
142+
}
143+
ClassBase c = GetManagedObject(idx) as ClassBase;
144+
Type t = (c != null) ? c.type : Converter.GetTypeByAlias(idx);
145+
if (t == null) {
146+
return Exceptions.RaiseTypeError("type expected");
147+
}
148+
Array a = Array.CreateInstance(t, 0);
149+
ClassBase o = ClassManager.GetClass(a.GetType());
150+
Runtime.Incref(o.pyHandle);
151+
return o.pyHandle;
152+
}
153+
154+
// If there are generics in our namespace with the same base name
155+
// as the current type, then [<type>] means the caller wants to
156+
// bind the generic type matching the given type parameters.
157+
158+
Type[] types = Runtime.PythonArgsToTypeArray(idx);
159+
if (types == null) {
160+
return Exceptions.RaiseTypeError("type(s) expected");
161+
}
162+
163+
string gname = this.type.FullName + "`" + types.Length.ToString();
164+
Type gtype = AssemblyManager.LookupType(gname);
165+
if (gtype != null) {
166+
GenericType g = ClassManager.GetClass(gtype) as GenericType;
167+
return g.type_subscript(idx);
168+
Runtime.Incref(g.pyHandle);
169+
return g.pyHandle;
170+
}
171+
return Exceptions.RaiseTypeError("unsubscriptable object");
150172
}
151173

152174

@@ -205,7 +227,7 @@ public static int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v) {
205227

206228
if (cls.indexer == null || !cls.indexer.CanSet) {
207229
Exceptions.SetError(Exceptions.TypeError,
208-
"object doesn't support item assignment x"
230+
"object doesn't support item assignment"
209231
);
210232
return -1;
211233
}

pythonnet/src/runtime/generictype.cs

Lines changed: 15 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -46,58 +46,29 @@ public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) {
4646
}
4747

4848
//====================================================================
49-
// Implements __getitem__ for reflected open generic types. A closed
49+
// Implements subscript syntax for reflected generic types. A closed
5050
// type is created by binding the generic type via subscript syntax:
5151
// inst = List[str]()
5252
//====================================================================
5353

54-
public static IntPtr bind(IntPtr ob, IntPtr idx) {
55-
ClassBase cls = (ClassBase)GetManagedObject(ob) as ClassBase;
56-
57-
// Ensure that the reflected class is a generic type definition,
58-
// or that
59-
if (!cls.type.IsGenericTypeDefinition) {
60-
return Exceptions.RaiseTypeError(
61-
"type is not a generic type definition"
62-
);
63-
}
64-
65-
// The index argument will often be a tuple, for generic types
66-
// that have more than one generic binding parameter.
67-
68-
IntPtr args = idx;
69-
bool free = false;
70-
71-
if (!Runtime.PyTuple_Check(idx)) {
72-
args = Runtime.PyTuple_New(1);
73-
Runtime.Incref(idx);
74-
Runtime.PyTuple_SetItem(args, 0, idx);
75-
free = true;
54+
public override IntPtr type_subscript(IntPtr idx) {
55+
Type[] types = Runtime.PythonArgsToTypeArray(idx);
56+
if (types == null) {
57+
return Exceptions.RaiseTypeError("type(s) expected");
7658
}
77-
78-
int n = Runtime.PyTuple_Size(args);
79-
Type[] types = new Type[n];
80-
Type t = null;
81-
82-
for (int i = 0; i < n; i++) {
83-
IntPtr op = Runtime.PyTuple_GetItem(args, i);
84-
ClassBase cb = GetManagedObject(op) as ClassBase;
85-
t = (cb != null) ? cb.type : Converter.GetTypeByAlias(op);
86-
if (t == null) {
87-
if (free) Runtime.Decref(args);
88-
return Exceptions.RaiseTypeError("type expected");
89-
}
90-
types[i] = t;
59+
if (!this.type.IsGenericTypeDefinition) {
60+
return Exceptions.RaiseTypeError(
61+
"type is not a generic type definition"
62+
);
9163
}
92-
93-
if (free) {
94-
Runtime.Decref(args);
64+
if (this.type.ContainsGenericParameters) {
65+
Type t = this.type.MakeGenericType(types);
66+
ManagedType c = (ManagedType)ClassManager.GetClass(t);
67+
Runtime.Incref(c.pyHandle);
68+
return c.pyHandle;
9569
}
9670

97-
t =cls.type.MakeGenericType(types);
98-
ManagedType c = (ManagedType)ClassManager.GetClass(t);
99-
Runtime.Incref(c.pyHandle);
100-
return c.pyHandle;
71+
return Exceptions.RaiseTypeError("unsubscriptable object");
10172
}
10273

10374
}

pythonnet/src/runtime/metatype.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ public static int tp_setattro(IntPtr tp, IntPtr name, IntPtr value) {
223223
public static IntPtr mp_subscript(IntPtr tp, IntPtr idx) {
224224
ClassBase cb = GetManagedObject(tp) as ClassBase;
225225
if (cb != null) {
226-
return cb.type_subscript(tp, idx);
226+
return cb.type_subscript(idx);
227227
}
228228
return Exceptions.RaiseTypeError("unsubscriptable object");
229229
}

pythonnet/src/runtime/runtime.cs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,39 @@ internal static IntPtr ExtendTuple(IntPtr t, params IntPtr[] args) {
206206
return items;
207207
}
208208

209+
internal static Type[] PythonArgsToTypeArray(IntPtr arg) {
210+
// Given a PyObject * that is either a single type object or a
211+
// tuple of (managed or unmanaged) type objects, return a Type[]
212+
// containing the CLR Type objects that map to those types.
213+
IntPtr args = arg;
214+
bool free = false;
215+
216+
if (!Runtime.PyTuple_Check(arg)) {
217+
args = Runtime.PyTuple_New(1);
218+
Runtime.Incref(arg);
219+
Runtime.PyTuple_SetItem(args, 0, arg);
220+
free = true;
221+
}
222+
223+
int n = Runtime.PyTuple_Size(args);
224+
Type[] types = new Type[n];
225+
Type t = null;
226+
227+
for (int i = 0; i < n; i++) {
228+
IntPtr op = Runtime.PyTuple_GetItem(args, i);
229+
ClassBase cb = ManagedType.GetManagedObject(op) as ClassBase;
230+
t = (cb != null) ? cb.type : Converter.GetTypeByAlias(op);
231+
if (t == null) {
232+
types = null;
233+
break;
234+
}
235+
types[i] = t;
236+
}
237+
if (free) {
238+
Runtime.Decref(args);
239+
}
240+
return types;
241+
}
209242

210243
//===================================================================
211244
// Managed exports of the Python C API. Where appropriate, we do

pythonnet/src/testing/generictest.cs

Lines changed: 72 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,6 @@ public GenericTypeDefinition(T arg1, U arg2) {
3333
this.value1 = arg1;
3434
this.value2 = arg2;
3535
}
36-
37-
38-
3936
}
4037

4138
public class DerivedFromOpenGeneric<V, W> :
@@ -50,9 +47,78 @@ public DerivedFromOpenGeneric(int arg1, V arg2, W arg3) :
5047
}
5148

5249

53-
public class NameTest {}
54-
public class NameTest<T,U> {}
55-
public class NameTest<T> {}
50+
public class GenericNameTest1 {
51+
public static int value = 0;
52+
}
53+
54+
public class GenericNameTest1<T> {
55+
public static int value = 1;
56+
}
57+
58+
public class GenericNameTest1<T,U> {
59+
public static int value = 2;
60+
}
61+
62+
public class GenericNameTest2<T> {
63+
public static int value = 1;
64+
}
65+
66+
public class GenericNameTest2<T,U> {
67+
public static int value = 2;
68+
}
69+
70+
71+
public class GenericMethodTest<T> {
72+
73+
public GenericMethodTest() {}
74+
75+
public int OverloadedMethod() {
76+
return 1;
77+
}
78+
79+
public int OverloadedMethod(int arg) {
80+
return arg;
81+
}
82+
83+
public T OverloadedMethod(T arg) {
84+
return arg;
85+
}
86+
87+
public Q OverloadedMethod<Q>(Q arg) {
88+
return arg;
89+
}
90+
91+
public U OverloadedMethod<Q, U>(Q arg1, U arg2) {
92+
return arg2;
93+
}
94+
95+
}
96+
97+
public class GenericStaticMethodTest<T> {
98+
99+
public GenericStaticMethodTest() {}
100+
101+
public static int OverloadedMethod() {
102+
return 1;
103+
}
104+
105+
public static int OverloadedMethod(int arg) {
106+
return arg;
107+
}
108+
109+
public static T OverloadedMethod(T arg) {
110+
return arg;
111+
}
112+
113+
public static Q OverloadedMethod<Q>(Q arg) {
114+
return arg;
115+
}
116+
117+
public static U OverloadedMethod<Q, U>(Q arg1, U arg2) {
118+
return arg2;
119+
}
120+
121+
}
56122

57123

58124
}

pythonnet/src/tests/runtests.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
'test_exceptions',
1616
'test_module',
1717
'test_compat',
18-
#'test_generic',
18+
'test_generic',
1919
'test_conversion',
2020
'test_class',
2121
'test_interface',

0 commit comments

Comments
 (0)