@@ -31,6 +31,7 @@ use crate::{
3131} ;
3232use indexmap:: { IndexMap , map:: Entry } ;
3333use itertools:: Itertools ;
34+ use num_traits:: ToPrimitive ;
3435use std:: { borrow:: Borrow , collections:: HashSet , ops:: Deref , pin:: Pin , ptr:: NonNull } ;
3536
3637#[ pyclass( module = false , name = "type" , traverse = "manual" ) ]
@@ -231,6 +232,58 @@ impl PyType {
231232 linearise_mro ( mros)
232233 }
233234
235+ /// Inherit SEQUENCE and MAPPING flags from base class (CPython: inherit_patma_flags)
236+ fn inherit_patma_flags ( slots : & mut PyTypeSlots , base : & PyRef < Self > ) {
237+ const COLLECTION_FLAGS : PyTypeFlags = PyTypeFlags :: from_bits_truncate (
238+ PyTypeFlags :: SEQUENCE . bits ( ) | PyTypeFlags :: MAPPING . bits ( ) ,
239+ ) ;
240+ if !slots. flags . intersects ( COLLECTION_FLAGS ) {
241+ slots. flags |= base. slots . flags & COLLECTION_FLAGS ;
242+ }
243+ }
244+
245+ /// Check for __abc_tpflags__ and set the appropriate flags
246+ /// This checks in attrs and all base classes for __abc_tpflags__
247+ fn check_abc_tpflags (
248+ slots : & mut PyTypeSlots ,
249+ attrs : & PyAttributes ,
250+ bases : & [ PyRef < Self > ] ,
251+ ctx : & Context ,
252+ ) {
253+ const COLLECTION_FLAGS : PyTypeFlags = PyTypeFlags :: from_bits_truncate (
254+ PyTypeFlags :: SEQUENCE . bits ( ) | PyTypeFlags :: MAPPING . bits ( ) ,
255+ ) ;
256+
257+ // Don't override if flags are already set
258+ if slots. flags . intersects ( COLLECTION_FLAGS ) {
259+ return ;
260+ }
261+
262+ // First check in our own attributes
263+ let abc_tpflags_name = ctx. intern_str ( "__abc_tpflags__" ) ;
264+ if let Some ( abc_tpflags_obj) = attrs. get ( abc_tpflags_name) {
265+ if let Some ( int_obj) = abc_tpflags_obj. downcast_ref :: < crate :: builtins:: int:: PyInt > ( ) {
266+ let flags_val = int_obj. as_bigint ( ) . to_i64 ( ) . unwrap_or ( 0 ) ;
267+ let abc_flags = PyTypeFlags :: from_bits_truncate ( flags_val as u64 ) ;
268+ slots. flags |= abc_flags & COLLECTION_FLAGS ;
269+ return ;
270+ }
271+ }
272+
273+ // Then check in base classes
274+ for base in bases {
275+ if let Some ( abc_tpflags_obj) = base. find_name_in_mro ( abc_tpflags_name) {
276+ if let Some ( int_obj) = abc_tpflags_obj. downcast_ref :: < crate :: builtins:: int:: PyInt > ( )
277+ {
278+ let flags_val = int_obj. as_bigint ( ) . to_i64 ( ) . unwrap_or ( 0 ) ;
279+ let abc_flags = PyTypeFlags :: from_bits_truncate ( flags_val as u64 ) ;
280+ slots. flags |= abc_flags & COLLECTION_FLAGS ;
281+ return ;
282+ }
283+ }
284+ }
285+ }
286+
234287 #[ allow( clippy:: too_many_arguments) ]
235288 fn new_heap_inner (
236289 base : PyRef < Self > ,
@@ -246,6 +299,13 @@ impl PyType {
246299 if base. slots . flags . has_feature ( PyTypeFlags :: HAS_DICT ) {
247300 slots. flags |= PyTypeFlags :: HAS_DICT
248301 }
302+
303+ // Inherit SEQUENCE and MAPPING flags from base class
304+ Self :: inherit_patma_flags ( & mut slots, & base) ;
305+
306+ // Check for __abc_tpflags__ from ABCMeta (for collections.abc.Sequence, Mapping, etc.)
307+ Self :: check_abc_tpflags ( & mut slots, & attrs, & bases, ctx) ;
308+
249309 if slots. basicsize == 0 {
250310 slots. basicsize = base. slots . basicsize ;
251311 }
@@ -297,6 +357,10 @@ impl PyType {
297357 if base. slots . flags . has_feature ( PyTypeFlags :: HAS_DICT ) {
298358 slots. flags |= PyTypeFlags :: HAS_DICT
299359 }
360+
361+ // Inherit SEQUENCE and MAPPING flags from base class
362+ Self :: inherit_patma_flags ( & mut slots, & base) ;
363+
300364 if slots. basicsize == 0 {
301365 slots. basicsize = base. slots . basicsize ;
302366 }
0 commit comments