mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-30 13:51:16 +00:00
[ty] Rewrite Type::any_over_type
using a new generalised TypeVisitor
trait (#19094)
Some checks are pending
CI / Determine changes (push) Waiting to run
CI / cargo fmt (push) Waiting to run
CI / cargo clippy (push) Blocked by required conditions
CI / cargo test (linux) (push) Blocked by required conditions
CI / cargo test (linux, release) (push) Blocked by required conditions
CI / cargo test (windows) (push) Blocked by required conditions
CI / cargo test (wasm) (push) Blocked by required conditions
CI / cargo build (release) (push) Waiting to run
CI / cargo build (msrv) (push) Blocked by required conditions
CI / cargo fuzz build (push) Blocked by required conditions
CI / fuzz parser (push) Blocked by required conditions
CI / test scripts (push) Blocked by required conditions
CI / ecosystem (push) Blocked by required conditions
CI / Fuzz for new ty panics (push) Blocked by required conditions
CI / cargo shear (push) Blocked by required conditions
CI / python package (push) Waiting to run
CI / pre-commit (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / formatter instabilities and black similarity (push) Blocked by required conditions
CI / test ruff-lsp (push) Blocked by required conditions
CI / check playground (push) Blocked by required conditions
CI / benchmarks-instrumented (push) Blocked by required conditions
CI / benchmarks-walltime (push) Blocked by required conditions
[ty Playground] Release / publish (push) Waiting to run
Some checks are pending
CI / Determine changes (push) Waiting to run
CI / cargo fmt (push) Waiting to run
CI / cargo clippy (push) Blocked by required conditions
CI / cargo test (linux) (push) Blocked by required conditions
CI / cargo test (linux, release) (push) Blocked by required conditions
CI / cargo test (windows) (push) Blocked by required conditions
CI / cargo test (wasm) (push) Blocked by required conditions
CI / cargo build (release) (push) Waiting to run
CI / cargo build (msrv) (push) Blocked by required conditions
CI / cargo fuzz build (push) Blocked by required conditions
CI / fuzz parser (push) Blocked by required conditions
CI / test scripts (push) Blocked by required conditions
CI / ecosystem (push) Blocked by required conditions
CI / Fuzz for new ty panics (push) Blocked by required conditions
CI / cargo shear (push) Blocked by required conditions
CI / python package (push) Waiting to run
CI / pre-commit (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / formatter instabilities and black similarity (push) Blocked by required conditions
CI / test ruff-lsp (push) Blocked by required conditions
CI / check playground (push) Blocked by required conditions
CI / benchmarks-instrumented (push) Blocked by required conditions
CI / benchmarks-walltime (push) Blocked by required conditions
[ty Playground] Release / publish (push) Waiting to run
This commit is contained in:
parent
77a5c5ac80
commit
333191b7f7
13 changed files with 769 additions and 209 deletions
|
@ -43,6 +43,7 @@ pub mod pull_types;
|
|||
|
||||
type FxOrderSet<V> = ordermap::set::OrderSet<V, BuildHasherDefault<FxHasher>>;
|
||||
type FxIndexMap<K, V> = indexmap::IndexMap<K, V, BuildHasherDefault<FxHasher>>;
|
||||
type FxIndexSet<V> = indexmap::IndexSet<V, BuildHasherDefault<FxHasher>>;
|
||||
|
||||
/// Returns the default registry with all known semantic lints.
|
||||
pub fn default_lint_registry() -> &'static LintRegistry {
|
||||
|
|
|
@ -19,7 +19,7 @@ use ruff_text_size::{Ranged, TextRange};
|
|||
use type_ordering::union_or_intersection_elements_ordering;
|
||||
|
||||
pub(crate) use self::builder::{IntersectionBuilder, UnionBuilder};
|
||||
pub(crate) use self::cyclic::TypeVisitor;
|
||||
pub(crate) use self::cyclic::TypeTransformer;
|
||||
pub use self::diagnostic::TypeCheckDiagnostics;
|
||||
pub(crate) use self::diagnostic::register_lints;
|
||||
pub(crate) use self::infer::{
|
||||
|
@ -42,12 +42,15 @@ use crate::types::diagnostic::{INVALID_TYPE_FORM, UNSUPPORTED_BOOL_CONVERSION};
|
|||
use crate::types::function::{
|
||||
DataclassTransformerParams, FunctionSpans, FunctionType, KnownFunction,
|
||||
};
|
||||
use crate::types::generics::{GenericContext, PartialSpecialization, Specialization};
|
||||
use crate::types::generics::{
|
||||
GenericContext, PartialSpecialization, Specialization, walk_generic_context,
|
||||
walk_partial_specialization, walk_specialization,
|
||||
};
|
||||
pub use crate::types::ide_support::all_members;
|
||||
use crate::types::infer::infer_unpack_types;
|
||||
use crate::types::mro::{Mro, MroError, MroIterator};
|
||||
pub(crate) use crate::types::narrow::infer_narrowing_constraint;
|
||||
use crate::types::signatures::{Parameter, ParameterForm, Parameters};
|
||||
use crate::types::signatures::{Parameter, ParameterForm, Parameters, walk_signature};
|
||||
use crate::types::tuple::{TupleSpec, TupleType};
|
||||
pub use crate::util::diagnostics::add_inferred_python_version_hint_to_diagnostic;
|
||||
use crate::{Db, FxOrderSet, Module, Program};
|
||||
|
@ -79,6 +82,7 @@ mod subclass_of;
|
|||
mod tuple;
|
||||
mod type_ordering;
|
||||
mod unpacker;
|
||||
mod visitor;
|
||||
|
||||
mod definition;
|
||||
#[cfg(test)]
|
||||
|
@ -368,6 +372,19 @@ pub struct PropertyInstanceType<'db> {
|
|||
setter: Option<Type<'db>>,
|
||||
}
|
||||
|
||||
fn walk_property_instance_type<'db, V: visitor::TypeVisitor<'db> + ?Sized>(
|
||||
db: &'db dyn Db,
|
||||
property: PropertyInstanceType<'db>,
|
||||
visitor: &mut V,
|
||||
) {
|
||||
if let Some(getter) = property.getter(db) {
|
||||
visitor.visit_type(db, getter);
|
||||
}
|
||||
if let Some(setter) = property.setter(db) {
|
||||
visitor.visit_type(db, setter);
|
||||
}
|
||||
}
|
||||
|
||||
// The Salsa heap is tracked separately.
|
||||
impl get_size2::GetSize for PropertyInstanceType<'_> {}
|
||||
|
||||
|
@ -382,7 +399,7 @@ impl<'db> PropertyInstanceType<'db> {
|
|||
Self::new(db, getter, setter)
|
||||
}
|
||||
|
||||
fn normalized_impl(self, db: &'db dyn Db, visitor: &mut TypeVisitor<'db>) -> Self {
|
||||
fn normalized_impl(self, db: &'db dyn Db, visitor: &mut TypeTransformer<'db>) -> Self {
|
||||
Self::new(
|
||||
db,
|
||||
self.getter(db).map(|ty| ty.normalized_impl(db, visitor)),
|
||||
|
@ -410,14 +427,6 @@ impl<'db> PropertyInstanceType<'db> {
|
|||
self.setter(db).map(|ty| ty.materialize(db, variance)),
|
||||
)
|
||||
}
|
||||
|
||||
fn any_over_type(self, db: &'db dyn Db, type_fn: &dyn Fn(Type<'db>) -> bool) -> bool {
|
||||
self.getter(db)
|
||||
.is_some_and(|ty| ty.any_over_type(db, type_fn))
|
||||
|| self
|
||||
.setter(db)
|
||||
.is_some_and(|ty| ty.any_over_type(db, type_fn))
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
|
@ -751,110 +760,6 @@ impl<'db> Type<'db> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Return `true` if `self`, or any of the types contained in `self`, match the closure passed in.
|
||||
pub fn any_over_type(self, db: &'db dyn Db, type_fn: &dyn Fn(Type<'db>) -> bool) -> bool {
|
||||
if type_fn(self) {
|
||||
return true;
|
||||
}
|
||||
|
||||
match self {
|
||||
Self::AlwaysFalsy
|
||||
| Self::AlwaysTruthy
|
||||
| Self::Never
|
||||
| Self::BooleanLiteral(_)
|
||||
| Self::BytesLiteral(_)
|
||||
| Self::ModuleLiteral(_)
|
||||
| Self::FunctionLiteral(_)
|
||||
| Self::ClassLiteral(_)
|
||||
| Self::SpecialForm(_)
|
||||
| Self::KnownInstance(_)
|
||||
| Self::StringLiteral(_)
|
||||
| Self::IntLiteral(_)
|
||||
| Self::LiteralString
|
||||
| Self::Dynamic(_)
|
||||
| Self::BoundMethod(_)
|
||||
| Self::WrapperDescriptor(_)
|
||||
| Self::MethodWrapper(_)
|
||||
| Self::DataclassDecorator(_)
|
||||
| Self::DataclassTransformer(_) => false,
|
||||
|
||||
Self::GenericAlias(generic) => generic
|
||||
.specialization(db)
|
||||
.types(db)
|
||||
.iter()
|
||||
.copied()
|
||||
.any(|ty| ty.any_over_type(db, type_fn)),
|
||||
|
||||
Self::Callable(callable) => {
|
||||
let signatures = callable.signatures(db);
|
||||
signatures.iter().any(|signature| {
|
||||
signature.parameters().iter().any(|param| {
|
||||
param
|
||||
.annotated_type()
|
||||
.is_some_and(|ty| ty.any_over_type(db, type_fn))
|
||||
}) || signature
|
||||
.return_ty
|
||||
.is_some_and(|ty| ty.any_over_type(db, type_fn))
|
||||
})
|
||||
}
|
||||
|
||||
Self::SubclassOf(subclass_of) => {
|
||||
Type::from(subclass_of.subclass_of()).any_over_type(db, type_fn)
|
||||
}
|
||||
|
||||
Self::TypeVar(typevar) => match typevar.bound_or_constraints(db) {
|
||||
None => false,
|
||||
Some(TypeVarBoundOrConstraints::UpperBound(bound)) => {
|
||||
bound.any_over_type(db, type_fn)
|
||||
}
|
||||
Some(TypeVarBoundOrConstraints::Constraints(constraints)) => constraints
|
||||
.elements(db)
|
||||
.iter()
|
||||
.any(|constraint| constraint.any_over_type(db, type_fn)),
|
||||
},
|
||||
|
||||
Self::BoundSuper(bound_super) => {
|
||||
Type::from(bound_super.pivot_class(db)).any_over_type(db, type_fn)
|
||||
|| Type::from(bound_super.owner(db)).any_over_type(db, type_fn)
|
||||
}
|
||||
|
||||
Self::Tuple(tuple) => tuple
|
||||
.tuple(db)
|
||||
.all_elements()
|
||||
.any(|ty| ty.any_over_type(db, type_fn)),
|
||||
|
||||
Self::Union(union) => union
|
||||
.elements(db)
|
||||
.iter()
|
||||
.any(|ty| ty.any_over_type(db, type_fn)),
|
||||
|
||||
Self::Intersection(intersection) => {
|
||||
intersection
|
||||
.positive(db)
|
||||
.iter()
|
||||
.any(|ty| ty.any_over_type(db, type_fn))
|
||||
|| intersection
|
||||
.negative(db)
|
||||
.iter()
|
||||
.any(|ty| ty.any_over_type(db, type_fn))
|
||||
}
|
||||
|
||||
Self::ProtocolInstance(protocol) => protocol.any_over_type(db, type_fn),
|
||||
Self::PropertyInstance(property) => property.any_over_type(db, type_fn),
|
||||
|
||||
Self::NominalInstance(instance) => match instance.class {
|
||||
ClassType::NonGeneric(_) => false,
|
||||
ClassType::Generic(generic) => generic
|
||||
.specialization(db)
|
||||
.types(db)
|
||||
.iter()
|
||||
.any(|ty| ty.any_over_type(db, type_fn)),
|
||||
},
|
||||
|
||||
Self::TypeIs(type_is) => type_is.return_type(db).any_over_type(db, type_fn),
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn into_class_literal(self) -> Option<ClassLiteral<'db>> {
|
||||
match self {
|
||||
Type::ClassLiteral(class_type) => Some(class_type),
|
||||
|
@ -1068,12 +973,16 @@ impl<'db> Type<'db> {
|
|||
/// - Converts class-based protocols into synthesized protocols
|
||||
#[must_use]
|
||||
pub fn normalized(self, db: &'db dyn Db) -> Self {
|
||||
let mut visitor = TypeVisitor::default();
|
||||
let mut visitor = TypeTransformer::default();
|
||||
self.normalized_impl(db, &mut visitor)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &mut TypeVisitor<'db>) -> Self {
|
||||
pub(crate) fn normalized_impl(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
visitor: &mut TypeTransformer<'db>,
|
||||
) -> Self {
|
||||
match self {
|
||||
Type::Union(union) => {
|
||||
visitor.visit(self, |v| Type::Union(union.normalized_impl(db, v)))
|
||||
|
@ -5733,6 +5642,22 @@ pub enum TypeMapping<'a, 'db> {
|
|||
PromoteLiterals,
|
||||
}
|
||||
|
||||
fn walk_type_mapping<'db, V: visitor::TypeVisitor<'db> + ?Sized>(
|
||||
db: &'db dyn Db,
|
||||
mapping: &TypeMapping<'_, 'db>,
|
||||
visitor: &mut V,
|
||||
) {
|
||||
match mapping {
|
||||
TypeMapping::Specialization(specialization) => {
|
||||
walk_specialization(db, *specialization, visitor);
|
||||
}
|
||||
TypeMapping::PartialSpecialization(specialization) => {
|
||||
walk_partial_specialization(db, specialization, visitor);
|
||||
}
|
||||
TypeMapping::PromoteLiterals => {}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db> TypeMapping<'_, 'db> {
|
||||
fn to_owned(&self) -> TypeMapping<'db, 'db> {
|
||||
match self {
|
||||
|
@ -5746,7 +5671,7 @@ impl<'db> TypeMapping<'_, 'db> {
|
|||
}
|
||||
}
|
||||
|
||||
fn normalized_impl(&self, db: &'db dyn Db, visitor: &mut TypeVisitor<'db>) -> Self {
|
||||
fn normalized_impl(&self, db: &'db dyn Db, visitor: &mut TypeTransformer<'db>) -> Self {
|
||||
match self {
|
||||
TypeMapping::Specialization(specialization) => {
|
||||
TypeMapping::Specialization(specialization.normalized_impl(db, visitor))
|
||||
|
@ -5797,8 +5722,27 @@ pub enum KnownInstanceType<'db> {
|
|||
TypeAliasType(TypeAliasType<'db>),
|
||||
}
|
||||
|
||||
fn walk_known_instance_type<'db, V: visitor::TypeVisitor<'db> + ?Sized>(
|
||||
db: &'db dyn Db,
|
||||
known_instance: KnownInstanceType<'db>,
|
||||
visitor: &mut V,
|
||||
) {
|
||||
match known_instance {
|
||||
KnownInstanceType::SubscriptedProtocol(context)
|
||||
| KnownInstanceType::SubscriptedGeneric(context) => {
|
||||
walk_generic_context(db, context, visitor);
|
||||
}
|
||||
KnownInstanceType::TypeVar(typevar) => {
|
||||
visitor.visit_type_var_type(db, typevar);
|
||||
}
|
||||
KnownInstanceType::TypeAliasType(type_alias) => {
|
||||
visitor.visit_type_alias_type(db, type_alias);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db> KnownInstanceType<'db> {
|
||||
fn normalized_impl(self, db: &'db dyn Db, visitor: &mut TypeVisitor<'db>) -> Self {
|
||||
fn normalized_impl(self, db: &'db dyn Db, visitor: &mut TypeTransformer<'db>) -> Self {
|
||||
match self {
|
||||
Self::SubscriptedProtocol(context) => {
|
||||
Self::SubscriptedProtocol(context.normalized_impl(db, visitor))
|
||||
|
@ -6169,6 +6113,19 @@ pub struct TypeVarInstance<'db> {
|
|||
// The Salsa heap is tracked separately.
|
||||
impl get_size2::GetSize for TypeVarInstance<'_> {}
|
||||
|
||||
fn walk_type_var_type<'db, V: visitor::TypeVisitor<'db> + ?Sized>(
|
||||
db: &'db dyn Db,
|
||||
type_var: TypeVarInstance<'db>,
|
||||
visitor: &mut V,
|
||||
) {
|
||||
if let Some(bounds) = type_var.bound_or_constraints(db) {
|
||||
walk_type_var_bounds(db, bounds, visitor);
|
||||
}
|
||||
if let Some(default_type) = type_var.default_ty(db) {
|
||||
visitor.visit_type(db, default_type);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db> TypeVarInstance<'db> {
|
||||
pub(crate) fn is_legacy(self, db: &'db dyn Db) -> bool {
|
||||
matches!(self.kind(db), TypeVarKind::Legacy)
|
||||
|
@ -6190,7 +6147,11 @@ impl<'db> TypeVarInstance<'db> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &mut TypeVisitor<'db>) -> Self {
|
||||
pub(crate) fn normalized_impl(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
visitor: &mut TypeTransformer<'db>,
|
||||
) -> Self {
|
||||
Self::new(
|
||||
db,
|
||||
self.name(db),
|
||||
|
@ -6245,8 +6206,21 @@ pub enum TypeVarBoundOrConstraints<'db> {
|
|||
Constraints(UnionType<'db>),
|
||||
}
|
||||
|
||||
fn walk_type_var_bounds<'db, V: visitor::TypeVisitor<'db> + ?Sized>(
|
||||
db: &'db dyn Db,
|
||||
bounds: TypeVarBoundOrConstraints<'db>,
|
||||
visitor: &mut V,
|
||||
) {
|
||||
match bounds {
|
||||
TypeVarBoundOrConstraints::UpperBound(bound) => visitor.visit_type(db, bound),
|
||||
TypeVarBoundOrConstraints::Constraints(constraints) => {
|
||||
visitor.visit_union_type(db, constraints);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db> TypeVarBoundOrConstraints<'db> {
|
||||
fn normalized_impl(self, db: &'db dyn Db, visitor: &mut TypeVisitor<'db>) -> Self {
|
||||
fn normalized_impl(self, db: &'db dyn Db, visitor: &mut TypeTransformer<'db>) -> Self {
|
||||
match self {
|
||||
TypeVarBoundOrConstraints::UpperBound(bound) => {
|
||||
TypeVarBoundOrConstraints::UpperBound(bound.normalized_impl(db, visitor))
|
||||
|
@ -7149,6 +7123,15 @@ pub struct BoundMethodType<'db> {
|
|||
// The Salsa heap is tracked separately.
|
||||
impl get_size2::GetSize for BoundMethodType<'_> {}
|
||||
|
||||
fn walk_bound_method_type<'db, V: visitor::TypeVisitor<'db> + ?Sized>(
|
||||
db: &'db dyn Db,
|
||||
method: BoundMethodType<'db>,
|
||||
visitor: &mut V,
|
||||
) {
|
||||
visitor.visit_function_type(db, method.function(db));
|
||||
visitor.visit_type(db, method.self_instance(db));
|
||||
}
|
||||
|
||||
impl<'db> BoundMethodType<'db> {
|
||||
pub(crate) fn into_callable_type(self, db: &'db dyn Db) -> Type<'db> {
|
||||
Type::Callable(CallableType::new(
|
||||
|
@ -7164,7 +7147,7 @@ impl<'db> BoundMethodType<'db> {
|
|||
))
|
||||
}
|
||||
|
||||
fn normalized_impl(self, db: &'db dyn Db, visitor: &mut TypeVisitor<'db>) -> Self {
|
||||
fn normalized_impl(self, db: &'db dyn Db, visitor: &mut TypeTransformer<'db>) -> Self {
|
||||
Self::new(
|
||||
db,
|
||||
self.function(db).normalized_impl(db, visitor),
|
||||
|
@ -7214,6 +7197,16 @@ pub struct CallableType<'db> {
|
|||
is_function_like: bool,
|
||||
}
|
||||
|
||||
pub(super) fn walk_callable_type<'db, V: visitor::TypeVisitor<'db> + ?Sized>(
|
||||
db: &'db dyn Db,
|
||||
ty: CallableType<'db>,
|
||||
visitor: &mut V,
|
||||
) {
|
||||
for signature in &ty.signatures(db).overloads {
|
||||
walk_signature(db, signature, visitor);
|
||||
}
|
||||
}
|
||||
|
||||
// The Salsa heap is tracked separately.
|
||||
impl get_size2::GetSize for CallableType<'_> {}
|
||||
|
||||
|
@ -7271,7 +7264,7 @@ impl<'db> CallableType<'db> {
|
|||
/// Return a "normalized" version of this `Callable` type.
|
||||
///
|
||||
/// See [`Type::normalized`] for more details.
|
||||
fn normalized_impl(self, db: &'db dyn Db, visitor: &mut TypeVisitor<'db>) -> Self {
|
||||
fn normalized_impl(self, db: &'db dyn Db, visitor: &mut TypeTransformer<'db>) -> Self {
|
||||
CallableType::new(
|
||||
db,
|
||||
self.signatures(db).normalized_impl(db, visitor),
|
||||
|
@ -7338,6 +7331,30 @@ pub enum MethodWrapperKind<'db> {
|
|||
StrStartswith(StringLiteralType<'db>),
|
||||
}
|
||||
|
||||
pub(super) fn walk_method_wrapper_type<'db, V: visitor::TypeVisitor<'db> + ?Sized>(
|
||||
db: &'db dyn Db,
|
||||
method_wrapper: MethodWrapperKind<'db>,
|
||||
visitor: &mut V,
|
||||
) {
|
||||
match method_wrapper {
|
||||
MethodWrapperKind::FunctionTypeDunderGet(function) => {
|
||||
visitor.visit_function_type(db, function);
|
||||
}
|
||||
MethodWrapperKind::FunctionTypeDunderCall(function) => {
|
||||
visitor.visit_function_type(db, function);
|
||||
}
|
||||
MethodWrapperKind::PropertyDunderGet(property) => {
|
||||
visitor.visit_property_instance_type(db, property);
|
||||
}
|
||||
MethodWrapperKind::PropertyDunderSet(property) => {
|
||||
visitor.visit_property_instance_type(db, property);
|
||||
}
|
||||
MethodWrapperKind::StrStartswith(string_literal) => {
|
||||
visitor.visit_type(db, Type::StringLiteral(string_literal));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db> MethodWrapperKind<'db> {
|
||||
fn has_relation_to(self, db: &'db dyn Db, other: Self, relation: TypeRelation) -> bool {
|
||||
match (self, other) {
|
||||
|
@ -7405,7 +7422,7 @@ impl<'db> MethodWrapperKind<'db> {
|
|||
}
|
||||
}
|
||||
|
||||
fn normalized_impl(self, db: &'db dyn Db, visitor: &mut TypeVisitor<'db>) -> Self {
|
||||
fn normalized_impl(self, db: &'db dyn Db, visitor: &mut TypeTransformer<'db>) -> Self {
|
||||
match self {
|
||||
MethodWrapperKind::FunctionTypeDunderGet(function) => {
|
||||
MethodWrapperKind::FunctionTypeDunderGet(function.normalized_impl(db, visitor))
|
||||
|
@ -7512,6 +7529,14 @@ pub struct PEP695TypeAliasType<'db> {
|
|||
// The Salsa heap is tracked separately.
|
||||
impl get_size2::GetSize for PEP695TypeAliasType<'_> {}
|
||||
|
||||
fn walk_pep_695_type_alias<'db, V: visitor::TypeVisitor<'db> + ?Sized>(
|
||||
db: &'db dyn Db,
|
||||
type_alias: PEP695TypeAliasType<'db>,
|
||||
visitor: &mut V,
|
||||
) {
|
||||
visitor.visit_type(db, type_alias.value_type(db));
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
impl<'db> PEP695TypeAliasType<'db> {
|
||||
pub(crate) fn definition(self, db: &'db dyn Db) -> Definition<'db> {
|
||||
|
@ -7531,7 +7556,7 @@ impl<'db> PEP695TypeAliasType<'db> {
|
|||
definition_expression_type(db, definition, &type_alias_stmt_node.value)
|
||||
}
|
||||
|
||||
fn normalized_impl(self, _db: &'db dyn Db, _visitor: &mut TypeVisitor<'db>) -> Self {
|
||||
fn normalized_impl(self, _db: &'db dyn Db, _visitor: &mut TypeTransformer<'db>) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
@ -7551,8 +7576,16 @@ pub struct BareTypeAliasType<'db> {
|
|||
// The Salsa heap is tracked separately.
|
||||
impl get_size2::GetSize for BareTypeAliasType<'_> {}
|
||||
|
||||
fn walk_bare_type_alias<'db, V: visitor::TypeVisitor<'db> + ?Sized>(
|
||||
db: &'db dyn Db,
|
||||
type_alias: BareTypeAliasType<'db>,
|
||||
visitor: &mut V,
|
||||
) {
|
||||
visitor.visit_type(db, type_alias.value(db));
|
||||
}
|
||||
|
||||
impl<'db> BareTypeAliasType<'db> {
|
||||
fn normalized_impl(self, db: &'db dyn Db, visitor: &mut TypeVisitor<'db>) -> Self {
|
||||
fn normalized_impl(self, db: &'db dyn Db, visitor: &mut TypeTransformer<'db>) -> Self {
|
||||
Self::new(
|
||||
db,
|
||||
self.name(db),
|
||||
|
@ -7570,8 +7603,27 @@ pub enum TypeAliasType<'db> {
|
|||
Bare(BareTypeAliasType<'db>),
|
||||
}
|
||||
|
||||
fn walk_type_alias_type<'db, V: visitor::TypeVisitor<'db> + ?Sized>(
|
||||
db: &'db dyn Db,
|
||||
type_alias: TypeAliasType<'db>,
|
||||
visitor: &mut V,
|
||||
) {
|
||||
match type_alias {
|
||||
TypeAliasType::PEP695(type_alias) => {
|
||||
walk_pep_695_type_alias(db, type_alias, visitor);
|
||||
}
|
||||
TypeAliasType::Bare(type_alias) => {
|
||||
walk_bare_type_alias(db, type_alias, visitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db> TypeAliasType<'db> {
|
||||
pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &mut TypeVisitor<'db>) -> Self {
|
||||
pub(crate) fn normalized_impl(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
visitor: &mut TypeTransformer<'db>,
|
||||
) -> Self {
|
||||
match self {
|
||||
TypeAliasType::PEP695(type_alias) => {
|
||||
TypeAliasType::PEP695(type_alias.normalized_impl(db, visitor))
|
||||
|
@ -7618,6 +7670,16 @@ pub struct UnionType<'db> {
|
|||
pub elements: Box<[Type<'db>]>,
|
||||
}
|
||||
|
||||
pub(crate) fn walk_union<'db, V: visitor::TypeVisitor<'db> + ?Sized>(
|
||||
db: &'db dyn Db,
|
||||
union: UnionType<'db>,
|
||||
visitor: &mut V,
|
||||
) {
|
||||
for element in union.elements(db) {
|
||||
visitor.visit_type(db, *element);
|
||||
}
|
||||
}
|
||||
|
||||
// The Salsa heap is tracked separately.
|
||||
impl get_size2::GetSize for UnionType<'_> {}
|
||||
|
||||
|
@ -7787,10 +7849,14 @@ impl<'db> UnionType<'db> {
|
|||
/// See [`Type::normalized`] for more details.
|
||||
#[must_use]
|
||||
pub(crate) fn normalized(self, db: &'db dyn Db) -> Self {
|
||||
self.normalized_impl(db, &mut TypeVisitor::default())
|
||||
self.normalized_impl(db, &mut TypeTransformer::default())
|
||||
}
|
||||
|
||||
pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &mut TypeVisitor<'db>) -> Self {
|
||||
pub(crate) fn normalized_impl(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
visitor: &mut TypeTransformer<'db>,
|
||||
) -> Self {
|
||||
let mut new_elements: Vec<Type<'db>> = self
|
||||
.elements(db)
|
||||
.iter()
|
||||
|
@ -7841,6 +7907,19 @@ pub struct IntersectionType<'db> {
|
|||
// The Salsa heap is tracked separately.
|
||||
impl get_size2::GetSize for IntersectionType<'_> {}
|
||||
|
||||
pub(super) fn walk_intersection_type<'db, V: visitor::TypeVisitor<'db> + ?Sized>(
|
||||
db: &'db dyn Db,
|
||||
intersection: IntersectionType<'db>,
|
||||
visitor: &mut V,
|
||||
) {
|
||||
for element in intersection.positive(db) {
|
||||
visitor.visit_type(db, *element);
|
||||
}
|
||||
for element in intersection.negative(db) {
|
||||
visitor.visit_type(db, *element);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db> IntersectionType<'db> {
|
||||
/// Return a new `IntersectionType` instance with the positive and negative types sorted
|
||||
/// according to a canonical ordering, and other normalizations applied to each element as applicable.
|
||||
|
@ -7848,15 +7927,19 @@ impl<'db> IntersectionType<'db> {
|
|||
/// See [`Type::normalized`] for more details.
|
||||
#[must_use]
|
||||
pub(crate) fn normalized(self, db: &'db dyn Db) -> Self {
|
||||
let mut visitor = TypeVisitor::default();
|
||||
let mut visitor = TypeTransformer::default();
|
||||
self.normalized_impl(db, &mut visitor)
|
||||
}
|
||||
|
||||
pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &mut TypeVisitor<'db>) -> Self {
|
||||
pub(crate) fn normalized_impl(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
visitor: &mut TypeTransformer<'db>,
|
||||
) -> Self {
|
||||
fn normalized_set<'db>(
|
||||
db: &'db dyn Db,
|
||||
elements: &FxOrderSet<Type<'db>>,
|
||||
visitor: &mut TypeVisitor<'db>,
|
||||
visitor: &mut TypeTransformer<'db>,
|
||||
) -> FxOrderSet<Type<'db>> {
|
||||
let mut elements: FxOrderSet<Type<'db>> = elements
|
||||
.iter()
|
||||
|
@ -8109,7 +8192,7 @@ pub enum SuperOwnerKind<'db> {
|
|||
}
|
||||
|
||||
impl<'db> SuperOwnerKind<'db> {
|
||||
fn normalized_impl(self, db: &'db dyn Db, visitor: &mut TypeVisitor<'db>) -> Self {
|
||||
fn normalized_impl(self, db: &'db dyn Db, visitor: &mut TypeTransformer<'db>) -> Self {
|
||||
match self {
|
||||
SuperOwnerKind::Dynamic(dynamic) => SuperOwnerKind::Dynamic(dynamic.normalized()),
|
||||
SuperOwnerKind::Class(class) => {
|
||||
|
@ -8197,6 +8280,15 @@ pub struct BoundSuperType<'db> {
|
|||
// The Salsa heap is tracked separately.
|
||||
impl get_size2::GetSize for BoundSuperType<'_> {}
|
||||
|
||||
fn walk_bound_super_type<'db, V: visitor::TypeVisitor<'db> + ?Sized>(
|
||||
db: &'db dyn Db,
|
||||
bound_super: BoundSuperType<'db>,
|
||||
visitor: &mut V,
|
||||
) {
|
||||
visitor.visit_type(db, bound_super.pivot_class(db).into());
|
||||
visitor.visit_type(db, bound_super.owner(db).into_type());
|
||||
}
|
||||
|
||||
impl<'db> BoundSuperType<'db> {
|
||||
/// Attempts to build a `Type::BoundSuper` based on the given `pivot_class` and `owner`.
|
||||
///
|
||||
|
@ -8358,7 +8450,11 @@ impl<'db> BoundSuperType<'db> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) fn normalized_impl(self, db: &'db dyn Db, visitor: &mut TypeVisitor<'db>) -> Self {
|
||||
pub(super) fn normalized_impl(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
visitor: &mut TypeTransformer<'db>,
|
||||
) -> Self {
|
||||
Self::new(
|
||||
db,
|
||||
self.pivot_class(db).normalized_impl(db, visitor),
|
||||
|
@ -8375,6 +8471,14 @@ pub struct TypeIsType<'db> {
|
|||
place_info: Option<(ScopeId<'db>, ScopedPlaceId)>,
|
||||
}
|
||||
|
||||
fn walk_typeis_type<'db, V: visitor::TypeVisitor<'db> + ?Sized>(
|
||||
db: &'db dyn Db,
|
||||
typeis_type: TypeIsType<'db>,
|
||||
visitor: &mut V,
|
||||
) {
|
||||
visitor.visit_type(db, typeis_type.return_type(db));
|
||||
}
|
||||
|
||||
// The Salsa heap is tracked separately.
|
||||
impl get_size2::GetSize for TypeIsType<'_> {}
|
||||
|
||||
|
|
|
@ -15,14 +15,14 @@ use crate::semantic_index::{DeclarationWithConstraint, SemanticIndex};
|
|||
use crate::types::context::InferContext;
|
||||
use crate::types::diagnostic::{INVALID_LEGACY_TYPE_VARIABLE, INVALID_TYPE_ALIAS_TYPE};
|
||||
use crate::types::function::{DataclassTransformerParams, KnownFunction};
|
||||
use crate::types::generics::{GenericContext, Specialization};
|
||||
use crate::types::generics::{GenericContext, Specialization, walk_specialization};
|
||||
use crate::types::infer::nearest_enclosing_class;
|
||||
use crate::types::signatures::{CallableSignature, Parameter, Parameters, Signature};
|
||||
use crate::types::tuple::TupleType;
|
||||
use crate::types::{
|
||||
BareTypeAliasType, Binding, BoundSuperError, BoundSuperType, CallableType, DataclassParams,
|
||||
KnownInstanceType, TypeAliasType, TypeMapping, TypeRelation, TypeVarBoundOrConstraints,
|
||||
TypeVarInstance, TypeVarKind, TypeVisitor, infer_definition_types,
|
||||
KnownInstanceType, TypeAliasType, TypeMapping, TypeRelation, TypeTransformer,
|
||||
TypeVarBoundOrConstraints, TypeVarInstance, TypeVarKind, infer_definition_types,
|
||||
};
|
||||
use crate::{
|
||||
Db, FxOrderSet, KnownModule, Program,
|
||||
|
@ -177,11 +177,23 @@ pub struct GenericAlias<'db> {
|
|||
pub(crate) specialization: Specialization<'db>,
|
||||
}
|
||||
|
||||
pub(super) fn walk_generic_alias<'db, V: super::visitor::TypeVisitor<'db> + ?Sized>(
|
||||
db: &'db dyn Db,
|
||||
alias: GenericAlias<'db>,
|
||||
visitor: &mut V,
|
||||
) {
|
||||
walk_specialization(db, alias.specialization(db), visitor);
|
||||
}
|
||||
|
||||
// The Salsa heap is tracked separately.
|
||||
impl get_size2::GetSize for GenericAlias<'_> {}
|
||||
|
||||
impl<'db> GenericAlias<'db> {
|
||||
pub(super) fn normalized_impl(self, db: &'db dyn Db, visitor: &mut TypeVisitor<'db>) -> Self {
|
||||
pub(super) fn normalized_impl(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
visitor: &mut TypeTransformer<'db>,
|
||||
) -> Self {
|
||||
Self::new(
|
||||
db,
|
||||
self.origin(db),
|
||||
|
@ -252,7 +264,11 @@ pub enum ClassType<'db> {
|
|||
|
||||
#[salsa::tracked]
|
||||
impl<'db> ClassType<'db> {
|
||||
pub(super) fn normalized_impl(self, db: &'db dyn Db, visitor: &mut TypeVisitor<'db>) -> Self {
|
||||
pub(super) fn normalized_impl(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
visitor: &mut TypeTransformer<'db>,
|
||||
) -> Self {
|
||||
match self {
|
||||
Self::NonGeneric(_) => self,
|
||||
Self::Generic(generic) => Self::Generic(generic.normalized_impl(db, visitor)),
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::Db;
|
|||
use crate::types::generics::Specialization;
|
||||
use crate::types::{
|
||||
ClassType, DynamicType, KnownClass, KnownInstanceType, MroError, MroIterator, SpecialFormType,
|
||||
Type, TypeMapping, TypeVisitor, todo_type,
|
||||
Type, TypeMapping, TypeTransformer, todo_type,
|
||||
};
|
||||
|
||||
/// Enumeration of the possible kinds of types we allow in class bases.
|
||||
|
@ -31,7 +31,11 @@ impl<'db> ClassBase<'db> {
|
|||
Self::Dynamic(DynamicType::Unknown)
|
||||
}
|
||||
|
||||
pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &mut TypeVisitor<'db>) -> Self {
|
||||
pub(crate) fn normalized_impl(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
visitor: &mut TypeTransformer<'db>,
|
||||
) -> Self {
|
||||
match self {
|
||||
Self::Dynamic(dynamic) => Self::Dynamic(dynamic.normalized()),
|
||||
Self::Class(class) => Self::Class(class.normalized_impl(db, visitor)),
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
use crate::FxOrderSet;
|
||||
use crate::FxIndexSet;
|
||||
use crate::types::Type;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub(crate) struct TypeVisitor<'db> {
|
||||
seen: FxOrderSet<Type<'db>>,
|
||||
pub(crate) struct TypeTransformer<'db> {
|
||||
seen: FxIndexSet<Type<'db>>,
|
||||
}
|
||||
|
||||
impl<'db> TypeVisitor<'db> {
|
||||
impl<'db> TypeTransformer<'db> {
|
||||
pub(crate) fn visit(
|
||||
&mut self,
|
||||
ty: Type<'db>,
|
||||
|
|
|
@ -70,12 +70,13 @@ use crate::types::diagnostic::{
|
|||
report_bad_argument_to_get_protocol_members,
|
||||
report_runtime_check_against_non_runtime_checkable_protocol,
|
||||
};
|
||||
use crate::types::generics::GenericContext;
|
||||
use crate::types::generics::{GenericContext, walk_generic_context};
|
||||
use crate::types::narrow::ClassInfoConstraintFunction;
|
||||
use crate::types::signatures::{CallableSignature, Signature};
|
||||
use crate::types::visitor::any_over_type;
|
||||
use crate::types::{
|
||||
BoundMethodType, CallableType, DynamicType, KnownClass, Type, TypeMapping, TypeRelation,
|
||||
TypeVarInstance, TypeVisitor,
|
||||
TypeTransformer, TypeVarInstance, walk_type_mapping,
|
||||
};
|
||||
use crate::{Db, FxOrderSet, ModuleName, resolve_module};
|
||||
|
||||
|
@ -421,6 +422,16 @@ pub struct FunctionLiteral<'db> {
|
|||
inherited_generic_context: Option<GenericContext<'db>>,
|
||||
}
|
||||
|
||||
fn walk_function_literal<'db, V: super::visitor::TypeVisitor<'db> + ?Sized>(
|
||||
db: &'db dyn Db,
|
||||
function: FunctionLiteral<'db>,
|
||||
visitor: &mut V,
|
||||
) {
|
||||
if let Some(context) = function.inherited_generic_context(db) {
|
||||
walk_generic_context(db, context, visitor);
|
||||
}
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
impl<'db> FunctionLiteral<'db> {
|
||||
fn with_inherited_generic_context(
|
||||
|
@ -545,7 +556,7 @@ impl<'db> FunctionLiteral<'db> {
|
|||
}))
|
||||
}
|
||||
|
||||
fn normalized_impl(self, db: &'db dyn Db, visitor: &mut TypeVisitor<'db>) -> Self {
|
||||
fn normalized_impl(self, db: &'db dyn Db, visitor: &mut TypeTransformer<'db>) -> Self {
|
||||
let context = self
|
||||
.inherited_generic_context(db)
|
||||
.map(|ctx| ctx.normalized_impl(db, visitor));
|
||||
|
@ -570,6 +581,17 @@ pub struct FunctionType<'db> {
|
|||
// The Salsa heap is tracked separately.
|
||||
impl get_size2::GetSize for FunctionType<'_> {}
|
||||
|
||||
pub(super) fn walk_function_type<'db, V: super::visitor::TypeVisitor<'db> + ?Sized>(
|
||||
db: &'db dyn Db,
|
||||
function: FunctionType<'db>,
|
||||
visitor: &mut V,
|
||||
) {
|
||||
walk_function_literal(db, function.literal(db), visitor);
|
||||
for mapping in function.type_mappings(db) {
|
||||
walk_type_mapping(db, mapping, visitor);
|
||||
}
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
impl<'db> FunctionType<'db> {
|
||||
pub(crate) fn with_inherited_generic_context(
|
||||
|
@ -819,11 +841,15 @@ impl<'db> FunctionType<'db> {
|
|||
}
|
||||
|
||||
pub(crate) fn normalized(self, db: &'db dyn Db) -> Self {
|
||||
let mut visitor = TypeVisitor::default();
|
||||
let mut visitor = TypeTransformer::default();
|
||||
self.normalized_impl(db, &mut visitor)
|
||||
}
|
||||
|
||||
pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &mut TypeVisitor<'db>) -> Self {
|
||||
pub(crate) fn normalized_impl(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
visitor: &mut TypeTransformer<'db>,
|
||||
) -> Self {
|
||||
let mappings: Box<_> = self
|
||||
.type_mappings(db)
|
||||
.iter()
|
||||
|
@ -1148,8 +1174,8 @@ impl KnownFunction {
|
|||
let contains_unknown_or_todo =
|
||||
|ty| matches!(ty, Type::Dynamic(dynamic) if dynamic != DynamicType::Any);
|
||||
if source_type.is_equivalent_to(db, *casted_type)
|
||||
&& !casted_type.any_over_type(db, &|ty| contains_unknown_or_todo(ty))
|
||||
&& !source_type.any_over_type(db, &|ty| contains_unknown_or_todo(ty))
|
||||
&& !any_over_type(db, *source_type, &contains_unknown_or_todo)
|
||||
&& !any_over_type(db, *casted_type, &contains_unknown_or_todo)
|
||||
{
|
||||
let builder = context.report_lint(&REDUNDANT_CAST, call_expression)?;
|
||||
builder.into_diagnostic(format_args!(
|
||||
|
|
|
@ -10,8 +10,8 @@ use crate::types::instance::{NominalInstanceType, Protocol, ProtocolInstanceType
|
|||
use crate::types::signatures::{Parameter, Parameters, Signature};
|
||||
use crate::types::tuple::{TupleSpec, TupleType};
|
||||
use crate::types::{
|
||||
KnownInstanceType, Type, TypeMapping, TypeRelation, TypeVarBoundOrConstraints, TypeVarInstance,
|
||||
TypeVarVariance, TypeVisitor, UnionType, declaration_type,
|
||||
KnownInstanceType, Type, TypeMapping, TypeRelation, TypeTransformer, TypeVarBoundOrConstraints,
|
||||
TypeVarInstance, TypeVarVariance, UnionType, declaration_type,
|
||||
};
|
||||
use crate::{Db, FxOrderSet};
|
||||
|
||||
|
@ -30,6 +30,16 @@ pub struct GenericContext<'db> {
|
|||
pub(crate) variables: FxOrderSet<TypeVarInstance<'db>>,
|
||||
}
|
||||
|
||||
pub(super) fn walk_generic_context<'db, V: super::visitor::TypeVisitor<'db> + ?Sized>(
|
||||
db: &'db dyn Db,
|
||||
context: GenericContext<'db>,
|
||||
visitor: &mut V,
|
||||
) {
|
||||
for typevar in context.variables(db) {
|
||||
visitor.visit_type_var_type(db, *typevar);
|
||||
}
|
||||
}
|
||||
|
||||
// The Salsa heap is tracked separately.
|
||||
impl get_size2::GetSize for GenericContext<'_> {}
|
||||
|
||||
|
@ -233,7 +243,11 @@ impl<'db> GenericContext<'db> {
|
|||
Specialization::new(db, self, expanded.into_boxed_slice(), None)
|
||||
}
|
||||
|
||||
pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &mut TypeVisitor<'db>) -> Self {
|
||||
pub(crate) fn normalized_impl(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
visitor: &mut TypeTransformer<'db>,
|
||||
) -> Self {
|
||||
let variables: FxOrderSet<_> = self
|
||||
.variables(db)
|
||||
.iter()
|
||||
|
@ -279,6 +293,20 @@ pub struct Specialization<'db> {
|
|||
tuple_inner: Option<TupleType<'db>>,
|
||||
}
|
||||
|
||||
pub(super) fn walk_specialization<'db, V: super::visitor::TypeVisitor<'db> + ?Sized>(
|
||||
db: &'db dyn Db,
|
||||
specialization: Specialization<'db>,
|
||||
visitor: &mut V,
|
||||
) {
|
||||
walk_generic_context(db, specialization.generic_context(db), visitor);
|
||||
for ty in specialization.types(db) {
|
||||
visitor.visit_type(db, *ty);
|
||||
}
|
||||
if let Some(tuple) = specialization.tuple_inner(db) {
|
||||
visitor.visit_tuple_type(db, tuple);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db> Specialization<'db> {
|
||||
/// Returns the tuple spec for a specialization of the `tuple` class.
|
||||
pub(crate) fn tuple(self, db: &'db dyn Db) -> &'db TupleSpec<'db> {
|
||||
|
@ -376,7 +404,11 @@ impl<'db> Specialization<'db> {
|
|||
Specialization::new(db, self.generic_context(db), types, None)
|
||||
}
|
||||
|
||||
pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &mut TypeVisitor<'db>) -> Self {
|
||||
pub(crate) fn normalized_impl(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
visitor: &mut TypeTransformer<'db>,
|
||||
) -> Self {
|
||||
let types: Box<[_]> = self
|
||||
.types(db)
|
||||
.iter()
|
||||
|
@ -518,6 +550,17 @@ pub struct PartialSpecialization<'a, 'db> {
|
|||
types: Cow<'a, [Type<'db>]>,
|
||||
}
|
||||
|
||||
pub(super) fn walk_partial_specialization<'db, V: super::visitor::TypeVisitor<'db> + ?Sized>(
|
||||
db: &'db dyn Db,
|
||||
specialization: &PartialSpecialization<'_, 'db>,
|
||||
visitor: &mut V,
|
||||
) {
|
||||
walk_generic_context(db, specialization.generic_context, visitor);
|
||||
for ty in &*specialization.types {
|
||||
visitor.visit_type(db, *ty);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db> PartialSpecialization<'_, 'db> {
|
||||
/// Returns the type that a typevar is mapped to, or None if the typevar isn't part of this
|
||||
/// mapping.
|
||||
|
@ -536,7 +579,7 @@ impl<'db> PartialSpecialization<'_, 'db> {
|
|||
pub(crate) fn normalized_impl(
|
||||
&self,
|
||||
db: &'db dyn Db,
|
||||
visitor: &mut TypeVisitor<'db>,
|
||||
visitor: &mut TypeTransformer<'db>,
|
||||
) -> PartialSpecialization<'db, 'db> {
|
||||
let generic_context = self.generic_context.normalized_impl(db, visitor);
|
||||
let types: Cow<_> = self
|
||||
|
|
|
@ -5,8 +5,9 @@ use std::marker::PhantomData;
|
|||
use super::protocol_class::ProtocolInterface;
|
||||
use super::{ClassType, KnownClass, SubclassOfType, Type, TypeVarVariance};
|
||||
use crate::place::PlaceAndQualifiers;
|
||||
use crate::types::protocol_class::walk_protocol_interface;
|
||||
use crate::types::tuple::TupleType;
|
||||
use crate::types::{DynamicType, TypeMapping, TypeRelation, TypeVarInstance, TypeVisitor};
|
||||
use crate::types::{DynamicType, TypeMapping, TypeRelation, TypeTransformer, TypeVarInstance};
|
||||
use crate::{Db, FxOrderSet};
|
||||
|
||||
pub(super) use synthesized_protocol::SynthesizedProtocolType;
|
||||
|
@ -44,7 +45,7 @@ impl<'db> Type<'db> {
|
|||
SynthesizedProtocolType::new(
|
||||
db,
|
||||
ProtocolInterface::with_property_members(db, members),
|
||||
&mut TypeVisitor::default(),
|
||||
&mut TypeTransformer::default(),
|
||||
),
|
||||
))
|
||||
}
|
||||
|
@ -74,6 +75,14 @@ pub struct NominalInstanceType<'db> {
|
|||
_phantom: PhantomData<()>,
|
||||
}
|
||||
|
||||
pub(super) fn walk_nominal_instance_type<'db, V: super::visitor::TypeVisitor<'db> + ?Sized>(
|
||||
db: &'db dyn Db,
|
||||
nominal: NominalInstanceType<'db>,
|
||||
visitor: &mut V,
|
||||
) {
|
||||
visitor.visit_type(db, nominal.class.into());
|
||||
}
|
||||
|
||||
impl<'db> NominalInstanceType<'db> {
|
||||
// Keep this method private, so that the only way of constructing `NominalInstanceType`
|
||||
// instances is through the `Type::instance` constructor function.
|
||||
|
@ -84,7 +93,11 @@ impl<'db> NominalInstanceType<'db> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) fn normalized_impl(self, db: &'db dyn Db, visitor: &mut TypeVisitor<'db>) -> Self {
|
||||
pub(super) fn normalized_impl(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
visitor: &mut TypeTransformer<'db>,
|
||||
) -> Self {
|
||||
Self::from_class(self.class.normalized_impl(db, visitor))
|
||||
}
|
||||
|
||||
|
@ -160,6 +173,14 @@ pub struct ProtocolInstanceType<'db> {
|
|||
_phantom: PhantomData<()>,
|
||||
}
|
||||
|
||||
pub(super) fn walk_protocol_instance_type<'db, V: super::visitor::TypeVisitor<'db> + ?Sized>(
|
||||
db: &'db dyn Db,
|
||||
protocol: ProtocolInstanceType<'db>,
|
||||
visitor: &mut V,
|
||||
) {
|
||||
walk_protocol_interface(db, protocol.inner.interface(db), visitor);
|
||||
}
|
||||
|
||||
impl<'db> ProtocolInstanceType<'db> {
|
||||
// Keep this method private, so that the only way of constructing `ProtocolInstanceType`
|
||||
// instances is through the `Type::instance` constructor function.
|
||||
|
@ -205,7 +226,7 @@ impl<'db> ProtocolInstanceType<'db> {
|
|||
///
|
||||
/// See [`Type::normalized`] for more details.
|
||||
pub(super) fn normalized(self, db: &'db dyn Db) -> Type<'db> {
|
||||
let mut visitor = TypeVisitor::default();
|
||||
let mut visitor = TypeTransformer::default();
|
||||
self.normalized_impl(db, &mut visitor)
|
||||
}
|
||||
|
||||
|
@ -215,7 +236,7 @@ impl<'db> ProtocolInstanceType<'db> {
|
|||
pub(super) fn normalized_impl(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
visitor: &mut TypeVisitor<'db>,
|
||||
visitor: &mut TypeTransformer<'db>,
|
||||
) -> Type<'db> {
|
||||
let object = KnownClass::Object.to_instance(db);
|
||||
if object.satisfies_protocol(db, self, TypeRelation::Subtyping) {
|
||||
|
@ -229,15 +250,6 @@ impl<'db> ProtocolInstanceType<'db> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Return `true` if the types of any of the members match the closure passed in.
|
||||
pub(super) fn any_over_type(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
type_fn: &dyn Fn(Type<'db>) -> bool,
|
||||
) -> bool {
|
||||
self.inner.interface(db).any_over_type(db, type_fn)
|
||||
}
|
||||
|
||||
/// Return `true` if this protocol type has the given type relation to the protocol `other`.
|
||||
///
|
||||
/// TODO: consider the types of the members as well as their existence
|
||||
|
@ -348,7 +360,7 @@ impl<'db> Protocol<'db> {
|
|||
|
||||
mod synthesized_protocol {
|
||||
use crate::types::protocol_class::ProtocolInterface;
|
||||
use crate::types::{TypeMapping, TypeVarInstance, TypeVarVariance, TypeVisitor};
|
||||
use crate::types::{TypeMapping, TypeTransformer, TypeVarInstance, TypeVarVariance};
|
||||
use crate::{Db, FxOrderSet};
|
||||
|
||||
/// A "synthesized" protocol type that is dissociated from a class definition in source code.
|
||||
|
@ -369,7 +381,7 @@ mod synthesized_protocol {
|
|||
pub(super) fn new(
|
||||
db: &'db dyn Db,
|
||||
interface: ProtocolInterface<'db>,
|
||||
visitor: &mut TypeVisitor<'db>,
|
||||
visitor: &mut TypeTransformer<'db>,
|
||||
) -> Self {
|
||||
Self(interface.normalized_impl(db, visitor))
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ use crate::{
|
|||
semantic_index::{place_table, use_def_map},
|
||||
types::{
|
||||
CallableType, ClassBase, ClassLiteral, KnownFunction, PropertyInstanceType, Signature,
|
||||
Type, TypeMapping, TypeQualifiers, TypeRelation, TypeVarInstance, TypeVisitor,
|
||||
Type, TypeMapping, TypeQualifiers, TypeRelation, TypeTransformer, TypeVarInstance,
|
||||
signatures::{Parameter, Parameters},
|
||||
},
|
||||
};
|
||||
|
@ -76,6 +76,16 @@ pub(super) struct ProtocolInterface<'db> {
|
|||
|
||||
impl get_size2::GetSize for ProtocolInterface<'_> {}
|
||||
|
||||
pub(super) fn walk_protocol_interface<'db, V: super::visitor::TypeVisitor<'db> + ?Sized>(
|
||||
db: &'db dyn Db,
|
||||
interface: ProtocolInterface<'db>,
|
||||
visitor: &mut V,
|
||||
) {
|
||||
for member in interface.members(db) {
|
||||
walk_protocol_member(db, &member, visitor);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db> ProtocolInterface<'db> {
|
||||
/// Synthesize a new protocol interface with the given members.
|
||||
///
|
||||
|
@ -152,17 +162,11 @@ impl<'db> ProtocolInterface<'db> {
|
|||
.all(|member_name| other.inner(db).contains_key(member_name))
|
||||
}
|
||||
|
||||
/// Return `true` if the types of any of the members match the closure passed in.
|
||||
pub(super) fn any_over_type(
|
||||
pub(super) fn normalized_impl(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
type_fn: &dyn Fn(Type<'db>) -> bool,
|
||||
) -> bool {
|
||||
self.members(db)
|
||||
.any(|member| member.any_over_type(db, type_fn))
|
||||
}
|
||||
|
||||
pub(super) fn normalized_impl(self, db: &'db dyn Db, visitor: &mut TypeVisitor<'db>) -> Self {
|
||||
visitor: &mut TypeTransformer<'db>,
|
||||
) -> Self {
|
||||
Self::new(
|
||||
db,
|
||||
self.inner(db)
|
||||
|
@ -220,10 +224,10 @@ pub(super) struct ProtocolMemberData<'db> {
|
|||
|
||||
impl<'db> ProtocolMemberData<'db> {
|
||||
fn normalized(&self, db: &'db dyn Db) -> Self {
|
||||
self.normalized_impl(db, &mut TypeVisitor::default())
|
||||
self.normalized_impl(db, &mut TypeTransformer::default())
|
||||
}
|
||||
|
||||
fn normalized_impl(&self, db: &'db dyn Db, visitor: &mut TypeVisitor<'db>) -> Self {
|
||||
fn normalized_impl(&self, db: &'db dyn Db, visitor: &mut TypeTransformer<'db>) -> Self {
|
||||
Self {
|
||||
kind: self.kind.normalized_impl(db, visitor),
|
||||
qualifiers: self.qualifiers,
|
||||
|
@ -261,7 +265,7 @@ enum ProtocolMemberKind<'db> {
|
|||
}
|
||||
|
||||
impl<'db> ProtocolMemberKind<'db> {
|
||||
fn normalized_impl(&self, db: &'db dyn Db, visitor: &mut TypeVisitor<'db>) -> Self {
|
||||
fn normalized_impl(&self, db: &'db dyn Db, visitor: &mut TypeTransformer<'db>) -> Self {
|
||||
match self {
|
||||
ProtocolMemberKind::Method(callable) => {
|
||||
ProtocolMemberKind::Method(callable.normalized_impl(db, visitor))
|
||||
|
@ -324,6 +328,20 @@ pub(super) struct ProtocolMember<'a, 'db> {
|
|||
qualifiers: TypeQualifiers,
|
||||
}
|
||||
|
||||
fn walk_protocol_member<'db, V: super::visitor::TypeVisitor<'db> + ?Sized>(
|
||||
db: &'db dyn Db,
|
||||
member: &ProtocolMember<'_, 'db>,
|
||||
visitor: &mut V,
|
||||
) {
|
||||
match member.kind {
|
||||
ProtocolMemberKind::Method(method) => visitor.visit_type(db, method),
|
||||
ProtocolMemberKind::Property(property) => {
|
||||
visitor.visit_property_instance_type(db, property);
|
||||
}
|
||||
ProtocolMemberKind::Other(ty) => visitor.visit_type(db, ty),
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'db> ProtocolMember<'a, 'db> {
|
||||
pub(super) fn name(&self) -> &'a str {
|
||||
self.name
|
||||
|
@ -371,14 +389,6 @@ impl<'a, 'db> ProtocolMember<'a, 'db> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn any_over_type(&self, db: &'db dyn Db, type_fn: &dyn Fn(Type<'db>) -> bool) -> bool {
|
||||
match &self.kind {
|
||||
ProtocolMemberKind::Method(callable) => callable.any_over_type(db, type_fn),
|
||||
ProtocolMemberKind::Property(property) => property.any_over_type(db, type_fn),
|
||||
ProtocolMemberKind::Other(ty) => ty.any_over_type(db, type_fn),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if a declaration or binding to a given name in a protocol class body
|
||||
|
|
|
@ -15,9 +15,9 @@ use std::{collections::HashMap, slice::Iter};
|
|||
use itertools::EitherOrBoth;
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
|
||||
use super::{DynamicType, Type, TypeVarVariance, TypeVisitor, definition_expression_type};
|
||||
use super::{DynamicType, Type, TypeTransformer, TypeVarVariance, definition_expression_type};
|
||||
use crate::semantic_index::definition::Definition;
|
||||
use crate::types::generics::GenericContext;
|
||||
use crate::types::generics::{GenericContext, walk_generic_context};
|
||||
use crate::types::{TypeMapping, TypeRelation, TypeVarInstance, todo_type};
|
||||
use crate::{Db, FxOrderSet};
|
||||
use ruff_python_ast::{self as ast, name::Name};
|
||||
|
@ -61,7 +61,11 @@ impl<'db> CallableSignature<'db> {
|
|||
)
|
||||
}
|
||||
|
||||
pub(crate) fn normalized_impl(&self, db: &'db dyn Db, visitor: &mut TypeVisitor<'db>) -> Self {
|
||||
pub(crate) fn normalized_impl(
|
||||
&self,
|
||||
db: &'db dyn Db,
|
||||
visitor: &mut TypeTransformer<'db>,
|
||||
) -> Self {
|
||||
Self::from_overloads(
|
||||
self.overloads
|
||||
.iter()
|
||||
|
@ -233,6 +237,29 @@ pub struct Signature<'db> {
|
|||
pub(crate) return_ty: Option<Type<'db>>,
|
||||
}
|
||||
|
||||
pub(super) fn walk_signature<'db, V: super::visitor::TypeVisitor<'db> + ?Sized>(
|
||||
db: &'db dyn Db,
|
||||
signature: &Signature<'db>,
|
||||
visitor: &mut V,
|
||||
) {
|
||||
if let Some(generic_context) = &signature.generic_context {
|
||||
walk_generic_context(db, *generic_context, visitor);
|
||||
}
|
||||
if let Some(inherited_generic_context) = &signature.inherited_generic_context {
|
||||
walk_generic_context(db, *inherited_generic_context, visitor);
|
||||
}
|
||||
// By default we usually don't visit the type of the default value,
|
||||
// as it isn't relevant to most things
|
||||
for parameter in &signature.parameters {
|
||||
if let Some(ty) = parameter.annotated_type() {
|
||||
visitor.visit_type(db, ty);
|
||||
}
|
||||
}
|
||||
if let Some(return_ty) = &signature.return_ty {
|
||||
visitor.visit_type(db, *return_ty);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db> Signature<'db> {
|
||||
pub(crate) fn new(parameters: Parameters<'db>, return_ty: Option<Type<'db>>) -> Self {
|
||||
Self {
|
||||
|
@ -334,7 +361,11 @@ impl<'db> Signature<'db> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn normalized_impl(&self, db: &'db dyn Db, visitor: &mut TypeVisitor<'db>) -> Self {
|
||||
pub(crate) fn normalized_impl(
|
||||
&self,
|
||||
db: &'db dyn Db,
|
||||
visitor: &mut TypeTransformer<'db>,
|
||||
) -> Self {
|
||||
Self {
|
||||
generic_context: self
|
||||
.generic_context
|
||||
|
@ -1276,7 +1307,11 @@ impl<'db> Parameter<'db> {
|
|||
/// Normalize nested unions and intersections in the annotated type, if any.
|
||||
///
|
||||
/// See [`Type::normalized`] for more details.
|
||||
pub(crate) fn normalized_impl(&self, db: &'db dyn Db, visitor: &mut TypeVisitor<'db>) -> Self {
|
||||
pub(crate) fn normalized_impl(
|
||||
&self,
|
||||
db: &'db dyn Db,
|
||||
visitor: &mut TypeTransformer<'db>,
|
||||
) -> Self {
|
||||
let Parameter {
|
||||
annotated_type,
|
||||
kind,
|
||||
|
|
|
@ -3,7 +3,7 @@ use ruff_python_ast::name::Name;
|
|||
use crate::place::PlaceAndQualifiers;
|
||||
use crate::types::{
|
||||
ClassType, DynamicType, KnownClass, MemberLookupPolicy, Type, TypeMapping, TypeRelation,
|
||||
TypeVarInstance, TypeVisitor,
|
||||
TypeTransformer, TypeVarInstance,
|
||||
};
|
||||
use crate::{Db, FxOrderSet};
|
||||
|
||||
|
@ -16,6 +16,14 @@ pub struct SubclassOfType<'db> {
|
|||
subclass_of: SubclassOfInner<'db>,
|
||||
}
|
||||
|
||||
pub(super) fn walk_subclass_of_type<'db, V: super::visitor::TypeVisitor<'db> + ?Sized>(
|
||||
db: &'db dyn Db,
|
||||
subclass_of: SubclassOfType<'db>,
|
||||
visitor: &mut V,
|
||||
) {
|
||||
visitor.visit_type(db, Type::from(subclass_of.subclass_of));
|
||||
}
|
||||
|
||||
impl<'db> SubclassOfType<'db> {
|
||||
/// Construct a new [`Type`] instance representing a given class object (or a given dynamic type)
|
||||
/// and all possible subclasses of that class object/dynamic type.
|
||||
|
@ -171,7 +179,11 @@ impl<'db> SubclassOfType<'db> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &mut TypeVisitor<'db>) -> Self {
|
||||
pub(crate) fn normalized_impl(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
visitor: &mut TypeTransformer<'db>,
|
||||
) -> Self {
|
||||
Self {
|
||||
subclass_of: self.subclass_of.normalized_impl(db, visitor),
|
||||
}
|
||||
|
@ -228,7 +240,11 @@ impl<'db> SubclassOfInner<'db> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &mut TypeVisitor<'db>) -> Self {
|
||||
pub(crate) fn normalized_impl(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
visitor: &mut TypeTransformer<'db>,
|
||||
) -> Self {
|
||||
match self {
|
||||
Self::Class(class) => Self::Class(class.normalized_impl(db, visitor)),
|
||||
Self::Dynamic(dynamic) => Self::Dynamic(dynamic.normalized()),
|
||||
|
|
|
@ -24,8 +24,8 @@ use itertools::{Either, EitherOrBoth, Itertools};
|
|||
|
||||
use crate::types::class::{ClassType, KnownClass};
|
||||
use crate::types::{
|
||||
Type, TypeMapping, TypeRelation, TypeVarInstance, TypeVarVariance, TypeVisitor, UnionBuilder,
|
||||
UnionType,
|
||||
Type, TypeMapping, TypeRelation, TypeTransformer, TypeVarInstance, TypeVarVariance,
|
||||
UnionBuilder, UnionType,
|
||||
};
|
||||
use crate::util::subscript::{Nth, OutOfBoundsError, PyIndex, PySlice, StepSizeZeroError};
|
||||
use crate::{Db, FxOrderSet};
|
||||
|
@ -88,6 +88,16 @@ pub struct TupleType<'db> {
|
|||
pub(crate) tuple: TupleSpec<'db>,
|
||||
}
|
||||
|
||||
pub(super) fn walk_tuple_type<'db, V: super::visitor::TypeVisitor<'db> + ?Sized>(
|
||||
db: &'db dyn Db,
|
||||
tuple: TupleType<'db>,
|
||||
visitor: &mut V,
|
||||
) {
|
||||
for element in tuple.tuple(db).all_elements() {
|
||||
visitor.visit_type(db, *element);
|
||||
}
|
||||
}
|
||||
|
||||
// The Salsa heap is tracked separately.
|
||||
impl get_size2::GetSize for TupleType<'_> {}
|
||||
|
||||
|
@ -178,7 +188,7 @@ impl<'db> TupleType<'db> {
|
|||
pub(crate) fn normalized_impl(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
visitor: &mut TypeVisitor<'db>,
|
||||
visitor: &mut TypeTransformer<'db>,
|
||||
) -> Option<Self> {
|
||||
TupleType::new(db, self.tuple(db).normalized_impl(db, visitor))
|
||||
}
|
||||
|
@ -332,7 +342,7 @@ impl<'db> FixedLengthTuple<Type<'db>> {
|
|||
}
|
||||
|
||||
#[must_use]
|
||||
fn normalized_impl(&self, db: &'db dyn Db, visitor: &mut TypeVisitor<'db>) -> Self {
|
||||
fn normalized_impl(&self, db: &'db dyn Db, visitor: &mut TypeTransformer<'db>) -> Self {
|
||||
Self::from_elements(self.0.iter().map(|ty| ty.normalized_impl(db, visitor)))
|
||||
}
|
||||
|
||||
|
@ -645,7 +655,11 @@ impl<'db> VariableLengthTuple<Type<'db>> {
|
|||
}
|
||||
|
||||
#[must_use]
|
||||
fn normalized_impl(&self, db: &'db dyn Db, visitor: &mut TypeVisitor<'db>) -> TupleSpec<'db> {
|
||||
fn normalized_impl(
|
||||
&self,
|
||||
db: &'db dyn Db,
|
||||
visitor: &mut TypeTransformer<'db>,
|
||||
) -> TupleSpec<'db> {
|
||||
let prefix = self
|
||||
.prenormalized_prefix_elements(db, None)
|
||||
.map(|ty| ty.normalized_impl(db, visitor))
|
||||
|
@ -985,7 +999,11 @@ impl<'db> Tuple<Type<'db>> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn normalized_impl(&self, db: &'db dyn Db, visitor: &mut TypeVisitor<'db>) -> Self {
|
||||
pub(crate) fn normalized_impl(
|
||||
&self,
|
||||
db: &'db dyn Db,
|
||||
visitor: &mut TypeTransformer<'db>,
|
||||
) -> Self {
|
||||
match self {
|
||||
Tuple::Fixed(tuple) => Tuple::Fixed(tuple.normalized_impl(db, visitor)),
|
||||
Tuple::Variable(tuple) => tuple.normalized_impl(db, visitor),
|
||||
|
|
275
crates/ty_python_semantic/src/types/visitor.rs
Normal file
275
crates/ty_python_semantic/src/types/visitor.rs
Normal file
|
@ -0,0 +1,275 @@
|
|||
use crate::{
|
||||
Db, FxIndexSet,
|
||||
types::{
|
||||
BoundMethodType, BoundSuperType, CallableType, GenericAlias, IntersectionType,
|
||||
KnownInstanceType, MethodWrapperKind, NominalInstanceType, PropertyInstanceType,
|
||||
ProtocolInstanceType, SubclassOfType, Type, TypeAliasType, TypeIsType, TypeVarInstance,
|
||||
UnionType,
|
||||
class::walk_generic_alias,
|
||||
function::{FunctionType, walk_function_type},
|
||||
instance::{walk_nominal_instance_type, walk_protocol_instance_type},
|
||||
subclass_of::walk_subclass_of_type,
|
||||
tuple::{TupleType, walk_tuple_type},
|
||||
walk_bound_method_type, walk_bound_super_type, walk_callable_type, walk_intersection_type,
|
||||
walk_known_instance_type, walk_method_wrapper_type, walk_property_instance_type,
|
||||
walk_type_alias_type, walk_type_var_type, walk_typeis_type, walk_union,
|
||||
},
|
||||
};
|
||||
|
||||
/// A visitor trait that recurses into nested types.
|
||||
///
|
||||
/// The trait does not guard against infinite recursion out of the box,
|
||||
/// but it makes it easy for implementors of the trait to do so.
|
||||
/// See [`any_over_type`] for an example of how to do this.
|
||||
pub(crate) trait TypeVisitor<'db> {
|
||||
fn visit_type(&mut self, db: &'db dyn Db, ty: Type<'db>);
|
||||
|
||||
fn visit_union_type(&mut self, db: &'db dyn Db, union: UnionType<'db>) {
|
||||
walk_union(db, union, self);
|
||||
}
|
||||
|
||||
fn visit_intersection_type(&mut self, db: &'db dyn Db, intersection: IntersectionType<'db>) {
|
||||
walk_intersection_type(db, intersection, self);
|
||||
}
|
||||
|
||||
fn visit_tuple_type(&mut self, db: &'db dyn Db, tuple: TupleType<'db>) {
|
||||
walk_tuple_type(db, tuple, self);
|
||||
}
|
||||
|
||||
fn visit_callable_type(&mut self, db: &'db dyn Db, callable: CallableType<'db>) {
|
||||
walk_callable_type(db, callable, self);
|
||||
}
|
||||
|
||||
fn visit_property_instance_type(
|
||||
&mut self,
|
||||
db: &'db dyn Db,
|
||||
property: PropertyInstanceType<'db>,
|
||||
) {
|
||||
walk_property_instance_type(db, property, self);
|
||||
}
|
||||
|
||||
fn visit_typeis_type(&mut self, db: &'db dyn Db, type_is: TypeIsType<'db>) {
|
||||
walk_typeis_type(db, type_is, self);
|
||||
}
|
||||
|
||||
fn visit_subclass_of_type(&mut self, db: &'db dyn Db, subclass_of: SubclassOfType<'db>) {
|
||||
walk_subclass_of_type(db, subclass_of, self);
|
||||
}
|
||||
|
||||
fn visit_generic_alias_type(&mut self, db: &'db dyn Db, alias: GenericAlias<'db>) {
|
||||
walk_generic_alias(db, alias, self);
|
||||
}
|
||||
|
||||
fn visit_function_type(&mut self, db: &'db dyn Db, function: FunctionType<'db>) {
|
||||
walk_function_type(db, function, self);
|
||||
}
|
||||
|
||||
fn visit_bound_method_type(&mut self, db: &'db dyn Db, method: BoundMethodType<'db>) {
|
||||
walk_bound_method_type(db, method, self);
|
||||
}
|
||||
|
||||
fn visit_bound_super_type(&mut self, db: &'db dyn Db, bound_super: BoundSuperType<'db>) {
|
||||
walk_bound_super_type(db, bound_super, self);
|
||||
}
|
||||
|
||||
fn visit_nominal_instance_type(&mut self, db: &'db dyn Db, nominal: NominalInstanceType<'db>) {
|
||||
walk_nominal_instance_type(db, nominal, self);
|
||||
}
|
||||
|
||||
fn visit_type_var_type(&mut self, db: &'db dyn Db, type_var: TypeVarInstance<'db>) {
|
||||
walk_type_var_type(db, type_var, self);
|
||||
}
|
||||
|
||||
fn visit_protocol_instance_type(
|
||||
&mut self,
|
||||
db: &'db dyn Db,
|
||||
protocol: ProtocolInstanceType<'db>,
|
||||
) {
|
||||
walk_protocol_instance_type(db, protocol, self);
|
||||
}
|
||||
|
||||
fn visit_method_wrapper_type(
|
||||
&mut self,
|
||||
db: &'db dyn Db,
|
||||
method_wrapper: MethodWrapperKind<'db>,
|
||||
) {
|
||||
walk_method_wrapper_type(db, method_wrapper, self);
|
||||
}
|
||||
|
||||
fn visit_known_instance_type(
|
||||
&mut self,
|
||||
db: &'db dyn Db,
|
||||
known_instance: KnownInstanceType<'db>,
|
||||
) {
|
||||
walk_known_instance_type(db, known_instance, self);
|
||||
}
|
||||
|
||||
fn visit_type_alias_type(&mut self, db: &'db dyn Db, type_alias: TypeAliasType<'db>) {
|
||||
walk_type_alias_type(db, type_alias, self);
|
||||
}
|
||||
}
|
||||
|
||||
/// Enumeration of types that may contain other types, such as unions, intersections, and generics.
|
||||
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
||||
enum NonAtomicType<'db> {
|
||||
Union(UnionType<'db>),
|
||||
Intersection(IntersectionType<'db>),
|
||||
Tuple(TupleType<'db>),
|
||||
FunctionLiteral(FunctionType<'db>),
|
||||
BoundMethod(BoundMethodType<'db>),
|
||||
BoundSuper(BoundSuperType<'db>),
|
||||
MethodWrapper(MethodWrapperKind<'db>),
|
||||
Callable(CallableType<'db>),
|
||||
GenericAlias(GenericAlias<'db>),
|
||||
KnownInstance(KnownInstanceType<'db>),
|
||||
SubclassOf(SubclassOfType<'db>),
|
||||
NominalInstance(NominalInstanceType<'db>),
|
||||
PropertyInstance(PropertyInstanceType<'db>),
|
||||
TypeIs(TypeIsType<'db>),
|
||||
TypeVar(TypeVarInstance<'db>),
|
||||
ProtocolInstance(ProtocolInstanceType<'db>),
|
||||
}
|
||||
|
||||
enum TypeKind<'db> {
|
||||
Atomic,
|
||||
NonAtomic(NonAtomicType<'db>),
|
||||
}
|
||||
|
||||
impl<'db> From<Type<'db>> for TypeKind<'db> {
|
||||
fn from(ty: Type<'db>) -> Self {
|
||||
match ty {
|
||||
Type::AlwaysFalsy
|
||||
| Type::AlwaysTruthy
|
||||
| Type::Never
|
||||
| Type::LiteralString
|
||||
| Type::IntLiteral(_)
|
||||
| Type::BooleanLiteral(_)
|
||||
| Type::StringLiteral(_)
|
||||
| Type::BytesLiteral(_)
|
||||
| Type::DataclassDecorator(_)
|
||||
| Type::DataclassTransformer(_)
|
||||
| Type::WrapperDescriptor(_)
|
||||
| Type::ModuleLiteral(_)
|
||||
| Type::ClassLiteral(_)
|
||||
| Type::SpecialForm(_)
|
||||
| Type::Dynamic(_) => TypeKind::Atomic,
|
||||
|
||||
// Non-atomic types
|
||||
Type::FunctionLiteral(function) => {
|
||||
TypeKind::NonAtomic(NonAtomicType::FunctionLiteral(function))
|
||||
}
|
||||
Type::Intersection(intersection) => {
|
||||
TypeKind::NonAtomic(NonAtomicType::Intersection(intersection))
|
||||
}
|
||||
Type::Union(union) => TypeKind::NonAtomic(NonAtomicType::Union(union)),
|
||||
Type::Tuple(tuple) => TypeKind::NonAtomic(NonAtomicType::Tuple(tuple)),
|
||||
Type::BoundMethod(method) => TypeKind::NonAtomic(NonAtomicType::BoundMethod(method)),
|
||||
Type::BoundSuper(bound_super) => {
|
||||
TypeKind::NonAtomic(NonAtomicType::BoundSuper(bound_super))
|
||||
}
|
||||
Type::MethodWrapper(method_wrapper) => {
|
||||
TypeKind::NonAtomic(NonAtomicType::MethodWrapper(method_wrapper))
|
||||
}
|
||||
Type::Callable(callable) => TypeKind::NonAtomic(NonAtomicType::Callable(callable)),
|
||||
Type::GenericAlias(alias) => TypeKind::NonAtomic(NonAtomicType::GenericAlias(alias)),
|
||||
Type::KnownInstance(known_instance) => {
|
||||
TypeKind::NonAtomic(NonAtomicType::KnownInstance(known_instance))
|
||||
}
|
||||
Type::SubclassOf(subclass_of) => {
|
||||
TypeKind::NonAtomic(NonAtomicType::SubclassOf(subclass_of))
|
||||
}
|
||||
Type::NominalInstance(nominal) => {
|
||||
TypeKind::NonAtomic(NonAtomicType::NominalInstance(nominal))
|
||||
}
|
||||
Type::ProtocolInstance(protocol) => {
|
||||
TypeKind::NonAtomic(NonAtomicType::ProtocolInstance(protocol))
|
||||
}
|
||||
Type::PropertyInstance(property) => {
|
||||
TypeKind::NonAtomic(NonAtomicType::PropertyInstance(property))
|
||||
}
|
||||
Type::TypeVar(type_var) => TypeKind::NonAtomic(NonAtomicType::TypeVar(type_var)),
|
||||
Type::TypeIs(type_is) => TypeKind::NonAtomic(NonAtomicType::TypeIs(type_is)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn walk_non_atomic_type<'db, V: TypeVisitor<'db> + ?Sized>(
|
||||
db: &'db dyn Db,
|
||||
non_atomic_type: NonAtomicType<'db>,
|
||||
visitor: &mut V,
|
||||
) {
|
||||
match non_atomic_type {
|
||||
NonAtomicType::FunctionLiteral(function) => visitor.visit_function_type(db, function),
|
||||
NonAtomicType::Intersection(intersection) => {
|
||||
visitor.visit_intersection_type(db, intersection);
|
||||
}
|
||||
NonAtomicType::Union(union) => visitor.visit_union_type(db, union),
|
||||
NonAtomicType::Tuple(tuple) => visitor.visit_tuple_type(db, tuple),
|
||||
NonAtomicType::BoundMethod(method) => visitor.visit_bound_method_type(db, method),
|
||||
NonAtomicType::BoundSuper(bound_super) => visitor.visit_bound_super_type(db, bound_super),
|
||||
NonAtomicType::MethodWrapper(method_wrapper) => {
|
||||
visitor.visit_method_wrapper_type(db, method_wrapper);
|
||||
}
|
||||
NonAtomicType::Callable(callable) => visitor.visit_callable_type(db, callable),
|
||||
NonAtomicType::GenericAlias(alias) => visitor.visit_generic_alias_type(db, alias),
|
||||
NonAtomicType::KnownInstance(known_instance) => {
|
||||
visitor.visit_known_instance_type(db, known_instance);
|
||||
}
|
||||
NonAtomicType::SubclassOf(subclass_of) => visitor.visit_subclass_of_type(db, subclass_of),
|
||||
NonAtomicType::NominalInstance(nominal) => visitor.visit_nominal_instance_type(db, nominal),
|
||||
NonAtomicType::PropertyInstance(property) => {
|
||||
visitor.visit_property_instance_type(db, property);
|
||||
}
|
||||
NonAtomicType::TypeIs(type_is) => visitor.visit_typeis_type(db, type_is),
|
||||
NonAtomicType::TypeVar(type_var) => visitor.visit_type_var_type(db, type_var),
|
||||
NonAtomicType::ProtocolInstance(protocol) => {
|
||||
visitor.visit_protocol_instance_type(db, protocol);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Return `true` if `ty`, or any of the types contained in `ty`, match the closure passed in.
|
||||
///
|
||||
/// The function guards against infinite recursion
|
||||
/// by keeping track of the non-atomic types it has already seen.
|
||||
pub(super) fn any_over_type<'db>(
|
||||
db: &'db dyn Db,
|
||||
ty: Type<'db>,
|
||||
query: &dyn Fn(Type<'db>) -> bool,
|
||||
) -> bool {
|
||||
struct AnyOverTypeVisitor<'db, 'a> {
|
||||
query: &'a dyn Fn(Type<'db>) -> bool,
|
||||
seen_types: FxIndexSet<NonAtomicType<'db>>,
|
||||
found_matching_type: bool,
|
||||
}
|
||||
|
||||
impl<'db> TypeVisitor<'db> for AnyOverTypeVisitor<'db, '_> {
|
||||
fn visit_type(&mut self, db: &'db dyn Db, ty: Type<'db>) {
|
||||
if self.found_matching_type {
|
||||
return;
|
||||
}
|
||||
self.found_matching_type |= (self.query)(ty);
|
||||
if self.found_matching_type {
|
||||
return;
|
||||
}
|
||||
match TypeKind::from(ty) {
|
||||
TypeKind::Atomic => {}
|
||||
TypeKind::NonAtomic(non_atomic_type) => {
|
||||
if !self.seen_types.insert(non_atomic_type) {
|
||||
// If we have already seen this type, we can skip it.
|
||||
return;
|
||||
}
|
||||
walk_non_atomic_type(db, non_atomic_type, self);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut visitor = AnyOverTypeVisitor {
|
||||
query,
|
||||
seen_types: FxIndexSet::default(),
|
||||
found_matching_type: false,
|
||||
};
|
||||
visitor.visit_type(db, ty);
|
||||
visitor.found_matching_type
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue