@@ -581,7 +581,11 @@ impl<'db> Specialization<'db> {
581581 /// That lets us produce the generic alias `A[int]`, which is the corresponding entry in the
582582 /// MRO of `B[int]`.
583583 pub ( crate ) fn apply_specialization ( self , db : & ' db dyn Db , other : Specialization < ' db > ) -> Self {
584- self . apply_type_mapping ( db, & TypeMapping :: Specialization ( other) )
584+ let new_specialization = self . apply_type_mapping ( db, & TypeMapping :: Specialization ( other) ) ;
585+ match other. materialization_kind ( db) {
586+ None => new_specialization,
587+ Some ( materialization_kind) => new_specialization. materialize ( db, materialization_kind) ,
588+ }
585589 }
586590
587591 pub ( crate ) fn apply_type_mapping < ' a > (
@@ -598,59 +602,20 @@ impl<'db> Specialization<'db> {
598602 type_mapping : & TypeMapping < ' a , ' db > ,
599603 visitor : & ApplyTypeMappingVisitor < ' db > ,
600604 ) -> Self {
601- // TODO it seems like this should be possible to do in a much simpler way in
602- // `Self::apply_specialization`; just apply the type mapping to create the new
603- // specialization, then materialize the new specialization appropriately, if the type
604- // mapping is a materialization. But this doesn't work; see discussion in
605- // https://github.com/astral-sh/ruff/pull/20076
606- let applied_materialization_kind = type_mapping. materialization_kind ( db) ;
607- let mut has_dynamic_invariant_typevar = false ;
608605 let types: Box < [ _ ] > = self
609- . generic_context ( db)
610- . variables ( db)
611- . into_iter ( )
612- . zip ( self . types ( db) )
613- . map ( |( bound_typevar, vartype) | {
614- let ty = vartype. apply_type_mapping_impl ( db, type_mapping, visitor) ;
615- match ( applied_materialization_kind, bound_typevar. variance ( db) ) {
616- ( None , _) => ty,
617- ( Some ( _) , TypeVarVariance :: Bivariant ) =>
618- // With bivariance, all specializations are subtypes of each other,
619- // so any materialization is acceptable.
620- {
621- ty. materialize ( db, MaterializationKind :: Top )
622- }
623- ( Some ( materialization_kind) , TypeVarVariance :: Covariant ) => {
624- ty. materialize ( db, materialization_kind)
625- }
626- ( Some ( materialization_kind) , TypeVarVariance :: Contravariant ) => {
627- ty. materialize ( db, materialization_kind. flip ( ) )
628- }
629- ( Some ( _) , TypeVarVariance :: Invariant ) => {
630- let top_materialization = ty. materialize ( db, MaterializationKind :: Top ) ;
631- if !ty. is_equivalent_to ( db, top_materialization) {
632- has_dynamic_invariant_typevar = true ;
633- }
634- ty
635- }
636- }
637- } )
606+ . types ( db)
607+ . iter ( )
608+ . map ( |ty| ty. apply_type_mapping_impl ( db, type_mapping, visitor) )
638609 . collect ( ) ;
639610
640611 let tuple_inner = self
641612 . tuple_inner ( db)
642613 . and_then ( |tuple| tuple. apply_type_mapping_impl ( db, type_mapping, visitor) ) ;
643- let new_materialization_kind = if has_dynamic_invariant_typevar {
644- self . materialization_kind ( db)
645- . or ( applied_materialization_kind)
646- } else {
647- None
648- } ;
649614 Specialization :: new (
650615 db,
651616 self . generic_context ( db) ,
652617 types,
653- new_materialization_kind ,
618+ self . materialization_kind ( db ) ,
654619 tuple_inner,
655620 )
656621 }
0 commit comments