Skip to content

Commit 39c21d7

Browse files
authored
[ty] Generalize some infrastructure around type visitors (#21323)
We have lots of `TypeVisitor`s that end up having very similar `visit_type` implementations. This PR consolidates some of the code for these so that there's less repetition and duplication.
1 parent 1617292 commit 39c21d7

File tree

3 files changed

+37
-37
lines changed

3 files changed

+37
-37
lines changed

crates/ty_python_semantic/src/types/class.rs

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use crate::types::member::{Member, class_member};
3030
use crate::types::signatures::{CallableSignature, Parameter, Parameters, Signature};
3131
use crate::types::tuple::{TupleSpec, TupleType};
3232
use crate::types::typed_dict::typed_dict_params_from_class_def;
33-
use crate::types::visitor::{NonAtomicType, TypeKind, TypeVisitor, walk_non_atomic_type};
33+
use crate::types::visitor::{TypeCollector, TypeVisitor, walk_type_with_recursion_guard};
3434
use crate::types::{
3535
ApplyTypeMappingVisitor, Binding, BoundSuperType, CallableType, DataclassFlags,
3636
DataclassParams, DeprecatedInstance, FindLegacyTypeVarsVisitor, HasRelationToVisitor,
@@ -1437,7 +1437,7 @@ impl<'db> ClassLiteral<'db> {
14371437
#[derive(Default)]
14381438
struct CollectTypeVars<'db> {
14391439
typevars: RefCell<FxIndexSet<BoundTypeVarInstance<'db>>>,
1440-
seen_types: RefCell<FxIndexSet<NonAtomicType<'db>>>,
1440+
recursion_guard: TypeCollector<'db>,
14411441
}
14421442

14431443
impl<'db> TypeVisitor<'db> for CollectTypeVars<'db> {
@@ -1454,16 +1454,7 @@ impl<'db> ClassLiteral<'db> {
14541454
}
14551455

14561456
fn visit_type(&self, db: &'db dyn Db, ty: Type<'db>) {
1457-
match TypeKind::from(ty) {
1458-
TypeKind::Atomic => {}
1459-
TypeKind::NonAtomic(non_atomic_type) => {
1460-
if !self.seen_types.borrow_mut().insert(non_atomic_type) {
1461-
// If we have already seen this type, we can skip it.
1462-
return;
1463-
}
1464-
walk_non_atomic_type(db, non_atomic_type, self);
1465-
}
1466-
}
1457+
walk_type_with_recursion_guard(db, ty, self, &self.recursion_guard);
14671458
}
14681459
}
14691460

crates/ty_python_semantic/src/types/generics.rs

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@ use crate::types::constraints::ConstraintSet;
1414
use crate::types::instance::{Protocol, ProtocolInstanceType};
1515
use crate::types::signatures::{Parameter, Parameters, Signature};
1616
use crate::types::tuple::{TupleSpec, TupleType, walk_tuple_type};
17-
use crate::types::visitor::{NonAtomicType, TypeKind, TypeVisitor, walk_non_atomic_type};
17+
use crate::types::visitor::{TypeCollector, TypeVisitor, walk_type_with_recursion_guard};
1818
use crate::types::{
1919
ApplyTypeMappingVisitor, BoundTypeVarIdentity, BoundTypeVarInstance, ClassLiteral,
2020
FindLegacyTypeVarsVisitor, HasRelationToVisitor, IsDisjointVisitor, IsEquivalentVisitor,
2121
KnownClass, KnownInstanceType, MaterializationKind, NormalizedVisitor, Type, TypeContext,
2222
TypeMapping, TypeRelation, TypeVarBoundOrConstraints, TypeVarIdentity, TypeVarInstance,
2323
TypeVarKind, TypeVarVariance, UnionType, declaration_type, walk_bound_type_var_type,
2424
};
25-
use crate::{Db, FxIndexSet, FxOrderMap, FxOrderSet};
25+
use crate::{Db, FxOrderMap, FxOrderSet};
2626

2727
/// Returns an iterator of any generic context introduced by the given scope or any enclosing
2828
/// scope.
@@ -288,7 +288,7 @@ impl<'db> GenericContext<'db> {
288288
#[derive(Default)]
289289
struct CollectTypeVars<'db> {
290290
typevars: RefCell<FxHashSet<BoundTypeVarIdentity<'db>>>,
291-
seen_types: RefCell<FxIndexSet<NonAtomicType<'db>>>,
291+
recursion_guard: TypeCollector<'db>,
292292
}
293293

294294
impl<'db> TypeVisitor<'db> for CollectTypeVars<'db> {
@@ -308,16 +308,7 @@ impl<'db> GenericContext<'db> {
308308
}
309309

310310
fn visit_type(&self, db: &'db dyn Db, ty: Type<'db>) {
311-
match TypeKind::from(ty) {
312-
TypeKind::Atomic => {}
313-
TypeKind::NonAtomic(non_atomic_type) => {
314-
if !self.seen_types.borrow_mut().insert(non_atomic_type) {
315-
// If we have already seen this type, we can skip it.
316-
return;
317-
}
318-
walk_non_atomic_type(db, non_atomic_type, self);
319-
}
320-
}
311+
walk_type_with_recursion_guard(db, ty, self, &self.recursion_guard);
321312
}
322313
}
323314

crates/ty_python_semantic/src/types/visitor.rs

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,33 @@ pub(super) fn walk_non_atomic_type<'db, V: TypeVisitor<'db> + ?Sized>(
242242
}
243243
}
244244

245+
pub(crate) fn walk_type_with_recursion_guard<'db>(
246+
db: &'db dyn Db,
247+
ty: Type<'db>,
248+
visitor: &impl TypeVisitor<'db>,
249+
recursion_guard: &TypeCollector<'db>,
250+
) {
251+
match TypeKind::from(ty) {
252+
TypeKind::Atomic => {}
253+
TypeKind::NonAtomic(non_atomic_type) => {
254+
if recursion_guard.type_was_already_seen(ty) {
255+
// If we have already seen this type, we can skip it.
256+
return;
257+
}
258+
walk_non_atomic_type(db, non_atomic_type, visitor);
259+
}
260+
}
261+
}
262+
263+
#[derive(Default, Debug)]
264+
pub(crate) struct TypeCollector<'db>(RefCell<FxIndexSet<Type<'db>>>);
265+
266+
impl<'db> TypeCollector<'db> {
267+
pub(crate) fn type_was_already_seen(&self, ty: Type<'db>) -> bool {
268+
!self.0.borrow_mut().insert(ty)
269+
}
270+
}
271+
245272
/// Return `true` if `ty`, or any of the types contained in `ty`, match the closure passed in.
246273
///
247274
/// The function guards against infinite recursion
@@ -258,7 +285,7 @@ pub(super) fn any_over_type<'db>(
258285
) -> bool {
259286
struct AnyOverTypeVisitor<'db, 'a> {
260287
query: &'a dyn Fn(Type<'db>) -> bool,
261-
seen_types: RefCell<FxIndexSet<NonAtomicType<'db>>>,
288+
recursion_guard: TypeCollector<'db>,
262289
found_matching_type: Cell<bool>,
263290
should_visit_lazy_type_attributes: bool,
264291
}
@@ -278,22 +305,13 @@ pub(super) fn any_over_type<'db>(
278305
if found {
279306
return;
280307
}
281-
match TypeKind::from(ty) {
282-
TypeKind::Atomic => {}
283-
TypeKind::NonAtomic(non_atomic_type) => {
284-
if !self.seen_types.borrow_mut().insert(non_atomic_type) {
285-
// If we have already seen this type, we can skip it.
286-
return;
287-
}
288-
walk_non_atomic_type(db, non_atomic_type, self);
289-
}
290-
}
308+
walk_type_with_recursion_guard(db, ty, self, &self.recursion_guard);
291309
}
292310
}
293311

294312
let visitor = AnyOverTypeVisitor {
295313
query,
296-
seen_types: RefCell::new(FxIndexSet::default()),
314+
recursion_guard: TypeCollector::default(),
297315
found_matching_type: Cell::new(false),
298316
should_visit_lazy_type_attributes,
299317
};

0 commit comments

Comments
 (0)