@@ -70,22 +70,9 @@ static NewReference tp_new_impl(BorrowedReference tp, BorrowedReference args, Bo
70
70
// Primitive types do not have constructors, but they look like
71
71
// they do from Python. If the ClassObject represents one of the
72
72
// convertible primitive types, just convert the arg directly.
73
- if ( type . IsPrimitive || type == typeof ( string ) )
73
+ if ( type . IsPrimitive )
74
74
{
75
- if ( Runtime . PyTuple_Size ( args ) != 1 )
76
- {
77
- Exceptions . SetError ( Exceptions . TypeError , "no constructors match given arguments" ) ;
78
- return default ;
79
- }
80
-
81
- BorrowedReference op = Runtime . PyTuple_GetItem ( args , 0 ) ;
82
-
83
- if ( ! Converter . ToManaged ( op , type , out var result , true ) )
84
- {
85
- return default ;
86
- }
87
-
88
- return CLRObject . GetReference ( result ! , tp ) ;
75
+ return NewPrimitive ( tp , args , type ) ;
89
76
}
90
77
91
78
if ( type . IsAbstract )
@@ -99,6 +86,11 @@ static NewReference tp_new_impl(BorrowedReference tp, BorrowedReference args, Bo
99
86
return NewEnum ( type , args , tp ) ;
100
87
}
101
88
89
+ if ( type == typeof ( string ) )
90
+ {
91
+ return NewString ( args , tp ) ;
92
+ }
93
+
102
94
if ( IsGenericNullable ( type ) )
103
95
{
104
96
// Nullable<T> has special handling in .NET runtime.
@@ -112,6 +104,127 @@ static NewReference tp_new_impl(BorrowedReference tp, BorrowedReference args, Bo
112
104
return self . NewObjectToPython ( obj , tp ) ;
113
105
}
114
106
107
+ /// <summary>
108
+ /// Construct a new .NET String object from Python args
109
+ /// </summary>
110
+ private static NewReference NewString ( BorrowedReference args , BorrowedReference tp )
111
+ {
112
+ if ( Runtime . PyTuple_Size ( args ) == 1 )
113
+ {
114
+ BorrowedReference ob = Runtime . PyTuple_GetItem ( args , 0 ) ;
115
+ if ( Runtime . PyString_Check ( ob ) )
116
+ {
117
+ if ( Runtime . GetManagedString ( ob ) is string val )
118
+ return CLRObject . GetReference ( val , tp ) ;
119
+ }
120
+
121
+ // TODO: Initialise using constructors instead
122
+
123
+ Exceptions . SetError ( Exceptions . TypeError , "no constructors match given arguments" ) ;
124
+ return default ;
125
+ }
126
+
127
+ return default ;
128
+ }
129
+
130
+ /// <summary>
131
+ /// Create a new Python object for a primitive type
132
+ ///
133
+ /// The primitive types are Boolean, Byte, SByte, Int16, UInt16,
134
+ /// Int32, UInt32, Int64, UInt64, IntPtr, UIntPtr, Char, Double,
135
+ /// and Single.
136
+ ///
137
+ /// All numeric types and Boolean can be handled by a simple
138
+ /// conversion, (U)IntPtr has to be handled separately as we
139
+ /// do not want to convert them automically to/from integers.
140
+ /// </summary>
141
+ /// <param name="type">.NET type to construct</param>
142
+ /// <param name="tp">Corresponding Python type</param>
143
+ /// <param name="args">Constructor arguments</param>
144
+ private static NewReference NewPrimitive ( BorrowedReference tp , BorrowedReference args , Type type )
145
+ {
146
+ // TODO: Handle IntPtr
147
+ if ( Runtime . PyTuple_Size ( args ) != 1 )
148
+ {
149
+ Exceptions . SetError ( Exceptions . TypeError , "no constructors match given arguments" ) ;
150
+ return default ;
151
+ }
152
+
153
+ BorrowedReference op = Runtime . PyTuple_GetItem ( args , 0 ) ;
154
+ object ? result = null ;
155
+
156
+ if ( type == typeof ( IntPtr ) )
157
+ {
158
+ if ( ManagedType . GetManagedObject ( op ) is CLRObject clrObject )
159
+ {
160
+ switch ( clrObject . inst )
161
+ {
162
+ case nint val :
163
+ result = new IntPtr ( val ) ;
164
+ break ;
165
+ case Int64 val :
166
+ result = new IntPtr ( val ) ;
167
+ break ;
168
+ case Int32 val :
169
+ result = new IntPtr ( val ) ;
170
+ break ;
171
+ }
172
+ }
173
+ else if ( Runtime . PyInt_Check ( op ) )
174
+ {
175
+ long ? num = Runtime . PyLong_AsLongLong ( op ) ;
176
+ if ( num is long n && n >= Runtime . IntPtrMinValue && n <= Runtime . IntPtrMaxValue )
177
+ {
178
+ result = new IntPtr ( n ) ;
179
+ }
180
+ else
181
+ {
182
+ Exceptions . SetError ( Exceptions . OverflowError , "value not in range for IntPtr" ) ;
183
+ return default ;
184
+ }
185
+ }
186
+ }
187
+
188
+ if ( type == typeof ( UIntPtr ) )
189
+ {
190
+ if ( ManagedType . GetManagedObject ( op ) is CLRObject clrObject )
191
+ {
192
+ switch ( clrObject . inst )
193
+ {
194
+ case nuint val :
195
+ result = new UIntPtr ( val ) ;
196
+ break ;
197
+ case UInt64 val :
198
+ result = new UIntPtr ( val ) ;
199
+ break ;
200
+ case UInt32 val :
201
+ result = new UIntPtr ( val ) ;
202
+ break ;
203
+ }
204
+ }
205
+ else if ( Runtime . PyInt_Check ( op ) )
206
+ {
207
+ ulong ? num = Runtime . PyLong_AsUnsignedLongLong ( op ) ;
208
+ if ( num is ulong n && n <= Runtime . UIntPtrMaxValue )
209
+ {
210
+ result = new UIntPtr ( n ) ;
211
+ }
212
+ else
213
+ {
214
+ Exceptions . SetError ( Exceptions . OverflowError , "value not in range for UIntPtr" ) ;
215
+ return default ;
216
+ }
217
+ }
218
+ }
219
+
220
+ if ( result == null && ! Converter . ToManaged ( op , type , out result , true ) )
221
+ {
222
+ return default ;
223
+ }
224
+
225
+ return CLRObject . GetReference ( result ! , tp ) ;
226
+ }
227
+
115
228
protected virtual void SetTypeNewSlot ( BorrowedReference pyType , SlotsHolder slotsHolder )
116
229
{
117
230
TypeManager . InitializeSlotIfEmpty ( pyType , TypeOffset . tp_new , new Interop . BBB_N ( tp_new_impl ) , slotsHolder ) ;
0 commit comments