@@ -6772,7 +6772,11 @@ impl<'db> Type<'db> {
67726772 Type :: TypeIs ( type_is) => type_is. with_type ( db, type_is. return_type ( db) . apply_type_mapping ( db, type_mapping, tcx) ) ,
67736773
67746774 Type :: TypeAlias ( alias) => {
6775- visitor. visit ( self , || alias. value_type ( db) . apply_type_mapping_impl ( db, type_mapping, tcx, visitor) )
6775+ // Do not call `value_type` here. `value_type` does the specialization internally, so `apply_type_mapping` is performed without `visitor` inheritance.
6776+ // In the case of recursive type aliases, this leads to infinite recursion.
6777+ // Instead, call `raw_value_type` and perform the specialization after the `visitor` cache has been created.
6778+ let value_type = visitor. visit ( self , || alias. raw_value_type ( db) . apply_type_mapping_impl ( db, type_mapping, tcx, visitor) ) ;
6779+ alias. apply_function_specialization ( db, value_type) . apply_type_mapping_impl ( db, type_mapping, tcx, visitor)
67766780 }
67776781
67786782 Type :: ModuleLiteral ( _)
@@ -10716,31 +10720,12 @@ impl<'db> PEP695TypeAliasType<'db> {
1071610720 }
1071710721
1071810722 /// The RHS type of a PEP-695 style type alias with specialization applied.
10719- #[ salsa:: tracked( cycle_initial=value_type_cycle_initial, heap_size=ruff_memory_usage:: heap_size) ]
1072010723 pub ( crate ) fn value_type ( self , db : & ' db dyn Db ) -> Type < ' db > {
10721- let value_type = self . raw_value_type ( db) ;
10722-
10723- if let Some ( generic_context) = self . generic_context ( db) {
10724- let specialization = self
10725- . specialization ( db)
10726- . unwrap_or_else ( || generic_context. default_specialization ( db, None ) ) ;
10727-
10728- value_type. apply_specialization ( db, specialization)
10729- } else {
10730- value_type
10731- }
10724+ self . apply_function_specialization ( db, self . raw_value_type ( db) )
1073210725 }
1073310726
1073410727 /// The RHS type of a PEP-695 style type alias with *no* specialization applied.
10735- ///
10736- /// ## Warning
10737- ///
10738- /// This uses the semantic index to find the definition of the type alias. This means that if the
10739- /// calling query is not in the same file as this type alias is defined in, then this will create
10740- /// a cross-module dependency directly on the full AST which will lead to cache
10741- /// over-invalidation.
10742- /// This method also calls the type inference functions, and since type aliases can have recursive structures,
10743- /// we should be careful not to create infinite recursions in this method (or make it tracked if necessary).
10728+ #[ salsa:: tracked( cycle_initial=value_type_cycle_initial, heap_size=ruff_memory_usage:: heap_size) ]
1074410729 pub ( crate ) fn raw_value_type ( self , db : & ' db dyn Db ) -> Type < ' db > {
1074510730 let scope = self . rhs_scope ( db) ;
1074610731 let module = parsed_module ( db, scope. file ( db) ) . load ( db) ;
@@ -10750,6 +10735,17 @@ impl<'db> PEP695TypeAliasType<'db> {
1075010735 definition_expression_type ( db, definition, & type_alias_stmt_node. node ( & module) . value )
1075110736 }
1075210737
10738+ fn apply_function_specialization ( self , db : & ' db dyn Db , ty : Type < ' db > ) -> Type < ' db > {
10739+ if let Some ( generic_context) = self . generic_context ( db) {
10740+ let specialization = self
10741+ . specialization ( db)
10742+ . unwrap_or_else ( || generic_context. default_specialization ( db, None ) ) ;
10743+ ty. apply_specialization ( db, specialization)
10744+ } else {
10745+ ty
10746+ }
10747+ }
10748+
1075310749 pub ( crate ) fn apply_specialization (
1075410750 self ,
1075510751 db : & ' db dyn Db ,
@@ -10939,6 +10935,13 @@ impl<'db> TypeAliasType<'db> {
1093910935 }
1094010936 }
1094110937
10938+ fn apply_function_specialization ( self , db : & ' db dyn Db , ty : Type < ' db > ) -> Type < ' db > {
10939+ match self {
10940+ TypeAliasType :: PEP695 ( type_alias) => type_alias. apply_function_specialization ( db, ty) ,
10941+ TypeAliasType :: ManualPEP695 ( _) => ty,
10942+ }
10943+ }
10944+
1094210945 pub ( crate ) fn apply_specialization (
1094310946 self ,
1094410947 db : & ' db dyn Db ,
@@ -11799,6 +11802,9 @@ type CovariantAlias[T] = Covariant[T]
1179911802type ContravariantAlias[T] = Contravariant[T]
1180011803type InvariantAlias[T] = Invariant[T]
1180111804type BivariantAlias[T] = Bivariant[T]
11805+
11806+ type RecursiveAlias[T] = None | list[RecursiveAlias[T]]
11807+ type RecursiveAlias2[T] = None | list[T] | list[RecursiveAlias2[T]]
1180211808"# ,
1180311809 )
1180411810 . unwrap ( ) ;
@@ -11829,5 +11835,19 @@ type BivariantAlias[T] = Bivariant[T]
1182911835 . variance_of( & db, get_bound_typevar( & db, bivariant) ) ,
1183011836 TypeVarVariance :: Bivariant
1183111837 ) ;
11838+
11839+ let recursive = get_type_alias ( & db, "RecursiveAlias" ) ;
11840+ assert_eq ! (
11841+ KnownInstanceType :: TypeAliasType ( TypeAliasType :: PEP695 ( recursive) )
11842+ . variance_of( & db, get_bound_typevar( & db, recursive) ) ,
11843+ TypeVarVariance :: Bivariant
11844+ ) ;
11845+
11846+ let recursive2 = get_type_alias ( & db, "RecursiveAlias2" ) ;
11847+ assert_eq ! (
11848+ KnownInstanceType :: TypeAliasType ( TypeAliasType :: PEP695 ( recursive2) )
11849+ . variance_of( & db, get_bound_typevar( & db, recursive2) ) ,
11850+ TypeVarVariance :: Invariant
11851+ ) ;
1183211852 }
1183311853}
0 commit comments