diff --git a/crates/ty_python_semantic/resources/corpus/cyclic_pep695_variance.py b/crates/ty_python_semantic/resources/corpus/cyclic_pep695_variance.py new file mode 100644 index 0000000000..70f354337d --- /dev/null +++ b/crates/ty_python_semantic/resources/corpus/cyclic_pep695_variance.py @@ -0,0 +1,14 @@ +from typing import Protocol + +class A(Protocol): + @property + def f(self): ... + +type Recursive = int | tuple[Recursive, ...] + +class B[T: A]: ... + +class C[T: A](A): + x: tuple[Recursive, ...] + +class D(B[C]): ... diff --git a/crates/ty_python_semantic/src/types/class.rs b/crates/ty_python_semantic/src/types/class.rs index 0abb33c54f..5ebf92fb06 100644 --- a/crates/ty_python_semantic/src/types/class.rs +++ b/crates/ty_python_semantic/src/types/class.rs @@ -340,9 +340,18 @@ impl<'db> From> for Type<'db> { } } +fn variance_of_cycle_initial<'db>( + _db: &'db dyn Db, + _id: salsa::Id, + _self: GenericAlias<'db>, + _typevar: BoundTypeVarInstance<'db>, +) -> TypeVarVariance { + TypeVarVariance::Bivariant +} + #[salsa::tracked] impl<'db> VarianceInferable<'db> for GenericAlias<'db> { - #[salsa::tracked(heap_size=ruff_memory_usage::heap_size)] + #[salsa::tracked(heap_size=ruff_memory_usage::heap_size, cycle_initial=variance_of_cycle_initial)] fn variance_of(self, db: &'db dyn Db, typevar: BoundTypeVarInstance<'db>) -> TypeVarVariance { let origin = self.origin(db);