1
1
use super :: { PyDictRef , PyList , PyStr , PyStrRef , PyType , PyTypeRef } ;
2
2
use crate :: common:: hash:: PyHash ;
3
+ use crate :: types:: PyTypeFlags ;
3
4
use crate :: {
4
5
class:: PyClassImpl ,
5
6
function:: { Either , FuncArgs , PyArithmeticValue , PyComparisonValue , PySetterValue } ,
@@ -281,7 +282,18 @@ impl PyBaseObject {
281
282
282
283
#[ pygetset( name = "__class__" , setter) ]
283
284
fn set_class ( instance : PyObjectRef , value : PyObjectRef , vm : & VirtualMachine ) -> PyResult < ( ) > {
284
- if instance. payload_is :: < PyBaseObject > ( ) {
285
+ let both_module = instance. class ( ) . fast_issubclass ( vm. ctx . types . module_type )
286
+ && value. class ( ) . fast_issubclass ( vm. ctx . types . module_type ) ;
287
+ let both_mutable = !instance
288
+ . class ( )
289
+ . slots
290
+ . flags
291
+ . has_feature ( PyTypeFlags :: IMMUTABLETYPE )
292
+ && !value
293
+ . downcast_ref :: < PyType > ( )
294
+ . map ( |t| t. slots . flags . has_feature ( PyTypeFlags :: IMMUTABLETYPE ) )
295
+ . unwrap_or ( false ) ;
296
+ if both_mutable || both_module {
285
297
match value. downcast :: < PyType > ( ) {
286
298
Ok ( cls) => {
287
299
// FIXME(#1979) cls instances might have a payload
@@ -298,7 +310,8 @@ impl PyBaseObject {
298
310
}
299
311
} else {
300
312
Err ( vm. new_type_error (
301
- "__class__ assignment only supported for types without a payload" . to_owned ( ) ,
313
+ "__class__ assignment only supported for mutable types or ModuleType subclasses"
314
+ . to_owned ( ) ,
302
315
) )
303
316
}
304
317
}
0 commit comments