mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-29 13:24:57 +00:00
[ty] Add some additional type safety to CycleDetector
(#19903)
This PR adds a type tag to the `CycleDetector` visitor (and its aliases). There are some places where we implement e.g. an equivalence check by making a disjointness check. Both `is_equivalent_to` and `is_disjoint_from` use a `PairVisitor` to handle cycles, but they should not use the same visitor. I was finding it tedious to remember when it was appropriate to pass on a visitor and when not to. This adds a `PhantomData` type tag to ensure that we can't pass on one method's visitor to a different method. For `has_relation` and `apply_type_mapping`, we have an existing type that we can use as the tag. For the other methods, I've added empty structs (`Normalized`, `IsDisjointFrom`, `IsEquivalentTo`) to use as tags.
This commit is contained in:
parent
df0648aae0
commit
baadb5a78d
11 changed files with 155 additions and 105 deletions
|
@ -170,6 +170,24 @@ fn definition_expression_type<'db>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A [`TypeTransformer`] that is used in `apply_type_mapping` methods.
|
||||||
|
pub(crate) type ApplyTypeMappingVisitor<'db> = TypeTransformer<'db, TypeMapping<'db, 'db>>;
|
||||||
|
|
||||||
|
/// A [`PairVisitor`] that is used in `has_relation_to` methods.
|
||||||
|
pub(crate) type HasRelationToVisitor<'db> = PairVisitor<'db, TypeRelation>;
|
||||||
|
|
||||||
|
/// A [`PairVisitor`] that is used in `is_disjoint_from` methods.
|
||||||
|
pub(crate) type IsDisjointVisitor<'db> = PairVisitor<'db, IsDisjoint>;
|
||||||
|
pub(crate) struct IsDisjoint;
|
||||||
|
|
||||||
|
/// A [`PairVisitor`] that is used in `is_equivalent` methods.
|
||||||
|
pub(crate) type IsEquivalentVisitor<'db> = PairVisitor<'db, IsEquivalent>;
|
||||||
|
pub(crate) struct IsEquivalent;
|
||||||
|
|
||||||
|
/// A [`TypeTransformer`] that is used in `normalized` methods.
|
||||||
|
pub(crate) type NormalizedVisitor<'db> = TypeTransformer<'db, Normalized>;
|
||||||
|
pub(crate) struct Normalized;
|
||||||
|
|
||||||
/// The descriptor protocol distinguishes two kinds of descriptors. Non-data descriptors
|
/// The descriptor protocol distinguishes two kinds of descriptors. Non-data descriptors
|
||||||
/// define a `__get__` method, while data descriptors additionally define a `__set__`
|
/// define a `__get__` method, while data descriptors additionally define a `__set__`
|
||||||
/// method or a `__delete__` method. This enum is used to categorize attributes into two
|
/// method or a `__delete__` method. This enum is used to categorize attributes into two
|
||||||
|
@ -419,7 +437,7 @@ impl<'db> PropertyInstanceType<'db> {
|
||||||
Self::new(db, getter, setter)
|
Self::new(db, getter, setter)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self {
|
fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self {
|
||||||
Self::new(
|
Self::new(
|
||||||
db,
|
db,
|
||||||
self.getter(db).map(|ty| ty.normalized_impl(db, visitor)),
|
self.getter(db).map(|ty| ty.normalized_impl(db, visitor)),
|
||||||
|
@ -1068,7 +1086,7 @@ impl<'db> Type<'db> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self {
|
pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self {
|
||||||
match self {
|
match self {
|
||||||
Type::Union(union) => {
|
Type::Union(union) => {
|
||||||
visitor.visit(self, || Type::Union(union.normalized_impl(db, visitor)))
|
visitor.visit(self, || Type::Union(union.normalized_impl(db, visitor)))
|
||||||
|
@ -1326,7 +1344,7 @@ impl<'db> Type<'db> {
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
target: Type<'db>,
|
target: Type<'db>,
|
||||||
relation: TypeRelation,
|
relation: TypeRelation,
|
||||||
visitor: &PairVisitor<'db>,
|
visitor: &HasRelationToVisitor<'db>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
// Subtyping implies assignability, so if subtyping is reflexive and the two types are
|
// Subtyping implies assignability, so if subtyping is reflexive and the two types are
|
||||||
// equal, it is both a subtype and assignable. Assignability is always reflexive.
|
// equal, it is both a subtype and assignable. Assignability is always reflexive.
|
||||||
|
@ -1762,7 +1780,7 @@ impl<'db> Type<'db> {
|
||||||
self,
|
self,
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
other: Type<'db>,
|
other: Type<'db>,
|
||||||
visitor: &PairVisitor<'db>,
|
visitor: &IsEquivalentVisitor<'db>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
if self == other {
|
if self == other {
|
||||||
return true;
|
return true;
|
||||||
|
@ -1848,13 +1866,13 @@ impl<'db> Type<'db> {
|
||||||
self,
|
self,
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
other: Type<'db>,
|
other: Type<'db>,
|
||||||
visitor: &PairVisitor<'db>,
|
visitor: &IsDisjointVisitor<'db>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
fn any_protocol_members_absent_or_disjoint<'db>(
|
fn any_protocol_members_absent_or_disjoint<'db>(
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
protocol: ProtocolInstanceType<'db>,
|
protocol: ProtocolInstanceType<'db>,
|
||||||
other: Type<'db>,
|
other: Type<'db>,
|
||||||
visitor: &PairVisitor<'db>,
|
visitor: &IsDisjointVisitor<'db>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
protocol.interface(db).members(db).any(|member| {
|
protocol.interface(db).members(db).any(|member| {
|
||||||
other
|
other
|
||||||
|
@ -5743,7 +5761,7 @@ impl<'db> Type<'db> {
|
||||||
self,
|
self,
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
type_mapping: &TypeMapping<'a, 'db>,
|
type_mapping: &TypeMapping<'a, 'db>,
|
||||||
visitor: &TypeTransformer<'db>,
|
visitor: &ApplyTypeMappingVisitor<'db>,
|
||||||
) -> Type<'db> {
|
) -> Type<'db> {
|
||||||
match self {
|
match self {
|
||||||
Type::TypeVar(bound_typevar) => match type_mapping {
|
Type::TypeVar(bound_typevar) => match type_mapping {
|
||||||
|
@ -6265,7 +6283,7 @@ impl<'db> TypeMapping<'_, 'db> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn normalized_impl(&self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self {
|
fn normalized_impl(&self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self {
|
||||||
match self {
|
match self {
|
||||||
TypeMapping::Specialization(specialization) => {
|
TypeMapping::Specialization(specialization) => {
|
||||||
TypeMapping::Specialization(specialization.normalized_impl(db, visitor))
|
TypeMapping::Specialization(specialization.normalized_impl(db, visitor))
|
||||||
|
@ -6351,7 +6369,7 @@ fn walk_known_instance_type<'db, V: visitor::TypeVisitor<'db> + ?Sized>(
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'db> KnownInstanceType<'db> {
|
impl<'db> KnownInstanceType<'db> {
|
||||||
fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self {
|
fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self {
|
||||||
match self {
|
match self {
|
||||||
Self::SubscriptedProtocol(context) => {
|
Self::SubscriptedProtocol(context) => {
|
||||||
Self::SubscriptedProtocol(context.normalized_impl(db, visitor))
|
Self::SubscriptedProtocol(context.normalized_impl(db, visitor))
|
||||||
|
@ -6777,7 +6795,7 @@ pub struct FieldInstance<'db> {
|
||||||
impl get_size2::GetSize for FieldInstance<'_> {}
|
impl get_size2::GetSize for FieldInstance<'_> {}
|
||||||
|
|
||||||
impl<'db> FieldInstance<'db> {
|
impl<'db> FieldInstance<'db> {
|
||||||
pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self {
|
pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self {
|
||||||
FieldInstance::new(
|
FieldInstance::new(
|
||||||
db,
|
db,
|
||||||
self.default_type(db).normalized_impl(db, visitor),
|
self.default_type(db).normalized_impl(db, visitor),
|
||||||
|
@ -6901,7 +6919,7 @@ impl<'db> TypeVarInstance<'db> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self {
|
pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self {
|
||||||
Self::new(
|
Self::new(
|
||||||
db,
|
db,
|
||||||
self.name(db),
|
self.name(db),
|
||||||
|
@ -6997,7 +7015,7 @@ impl<'db> BoundTypeVarInstance<'db> {
|
||||||
.map(|ty| ty.apply_type_mapping(db, &TypeMapping::BindLegacyTypevars(binding_context)))
|
.map(|ty| ty.apply_type_mapping(db, &TypeMapping::BindLegacyTypevars(binding_context)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self {
|
pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self {
|
||||||
Self::new(
|
Self::new(
|
||||||
db,
|
db,
|
||||||
self.typevar(db).normalized_impl(db, visitor),
|
self.typevar(db).normalized_impl(db, visitor),
|
||||||
|
@ -7056,7 +7074,7 @@ fn walk_type_var_bounds<'db, V: visitor::TypeVisitor<'db> + ?Sized>(
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'db> TypeVarBoundOrConstraints<'db> {
|
impl<'db> TypeVarBoundOrConstraints<'db> {
|
||||||
fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self {
|
fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self {
|
||||||
match self {
|
match self {
|
||||||
TypeVarBoundOrConstraints::UpperBound(bound) => {
|
TypeVarBoundOrConstraints::UpperBound(bound) => {
|
||||||
TypeVarBoundOrConstraints::UpperBound(bound.normalized_impl(db, visitor))
|
TypeVarBoundOrConstraints::UpperBound(bound.normalized_impl(db, visitor))
|
||||||
|
@ -8094,7 +8112,7 @@ impl<'db> BoundMethodType<'db> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self {
|
fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self {
|
||||||
Self::new(
|
Self::new(
|
||||||
db,
|
db,
|
||||||
self.function(db).normalized_impl(db, visitor),
|
self.function(db).normalized_impl(db, visitor),
|
||||||
|
@ -8211,7 +8229,7 @@ impl<'db> CallableType<'db> {
|
||||||
/// Return a "normalized" version of this `Callable` type.
|
/// Return a "normalized" version of this `Callable` type.
|
||||||
///
|
///
|
||||||
/// See [`Type::normalized`] for more details.
|
/// See [`Type::normalized`] for more details.
|
||||||
fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self {
|
fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self {
|
||||||
CallableType::new(
|
CallableType::new(
|
||||||
db,
|
db,
|
||||||
self.signatures(db).normalized_impl(db, visitor),
|
self.signatures(db).normalized_impl(db, visitor),
|
||||||
|
@ -8375,7 +8393,7 @@ impl<'db> MethodWrapperKind<'db> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self {
|
fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self {
|
||||||
match self {
|
match self {
|
||||||
MethodWrapperKind::FunctionTypeDunderGet(function) => {
|
MethodWrapperKind::FunctionTypeDunderGet(function) => {
|
||||||
MethodWrapperKind::FunctionTypeDunderGet(function.normalized_impl(db, visitor))
|
MethodWrapperKind::FunctionTypeDunderGet(function.normalized_impl(db, visitor))
|
||||||
|
@ -8559,7 +8577,7 @@ impl<'db> PEP695TypeAliasType<'db> {
|
||||||
definition_expression_type(db, definition, &type_alias_stmt_node.value)
|
definition_expression_type(db, definition, &type_alias_stmt_node.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn normalized_impl(self, _db: &'db dyn Db, _visitor: &TypeTransformer<'db>) -> Self {
|
fn normalized_impl(self, _db: &'db dyn Db, _visitor: &NormalizedVisitor<'db>) -> Self {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8601,7 +8619,7 @@ fn walk_bare_type_alias<'db, V: visitor::TypeVisitor<'db> + ?Sized>(
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'db> BareTypeAliasType<'db> {
|
impl<'db> BareTypeAliasType<'db> {
|
||||||
fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self {
|
fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self {
|
||||||
Self::new(
|
Self::new(
|
||||||
db,
|
db,
|
||||||
self.name(db),
|
self.name(db),
|
||||||
|
@ -8637,7 +8655,7 @@ fn walk_type_alias_type<'db, V: visitor::TypeVisitor<'db> + ?Sized>(
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'db> TypeAliasType<'db> {
|
impl<'db> TypeAliasType<'db> {
|
||||||
pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self {
|
pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self {
|
||||||
match self {
|
match self {
|
||||||
TypeAliasType::PEP695(type_alias) => {
|
TypeAliasType::PEP695(type_alias) => {
|
||||||
TypeAliasType::PEP695(type_alias.normalized_impl(db, visitor))
|
TypeAliasType::PEP695(type_alias.normalized_impl(db, visitor))
|
||||||
|
@ -8866,7 +8884,7 @@ impl<'db> UnionType<'db> {
|
||||||
self.normalized_impl(db, &TypeTransformer::default())
|
self.normalized_impl(db, &TypeTransformer::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self {
|
pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self {
|
||||||
let mut new_elements: Vec<Type<'db>> = self
|
let mut new_elements: Vec<Type<'db>> = self
|
||||||
.elements(db)
|
.elements(db)
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -8940,11 +8958,11 @@ impl<'db> IntersectionType<'db> {
|
||||||
self.normalized_impl(db, &TypeTransformer::default())
|
self.normalized_impl(db, &TypeTransformer::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self {
|
pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self {
|
||||||
fn normalized_set<'db>(
|
fn normalized_set<'db>(
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
elements: &FxOrderSet<Type<'db>>,
|
elements: &FxOrderSet<Type<'db>>,
|
||||||
visitor: &TypeTransformer<'db>,
|
visitor: &NormalizedVisitor<'db>,
|
||||||
) -> FxOrderSet<Type<'db>> {
|
) -> FxOrderSet<Type<'db>> {
|
||||||
let mut elements: FxOrderSet<Type<'db>> = elements
|
let mut elements: FxOrderSet<Type<'db>> = elements
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -9194,7 +9212,7 @@ impl<'db> TypedDictType<'db> {
|
||||||
self,
|
self,
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
type_mapping: &TypeMapping<'a, 'db>,
|
type_mapping: &TypeMapping<'a, 'db>,
|
||||||
visitor: &TypeTransformer<'db>,
|
visitor: &ApplyTypeMappingVisitor<'db>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
defining_class: self
|
defining_class: self
|
||||||
|
@ -9266,7 +9284,7 @@ pub enum SuperOwnerKind<'db> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'db> SuperOwnerKind<'db> {
|
impl<'db> SuperOwnerKind<'db> {
|
||||||
fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self {
|
fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self {
|
||||||
match self {
|
match self {
|
||||||
SuperOwnerKind::Dynamic(dynamic) => SuperOwnerKind::Dynamic(dynamic.normalized()),
|
SuperOwnerKind::Dynamic(dynamic) => SuperOwnerKind::Dynamic(dynamic.normalized()),
|
||||||
SuperOwnerKind::Class(class) => {
|
SuperOwnerKind::Class(class) => {
|
||||||
|
@ -9538,7 +9556,7 @@ impl<'db> BoundSuperType<'db> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self {
|
pub(super) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self {
|
||||||
Self::new(
|
Self::new(
|
||||||
db,
|
db,
|
||||||
self.pivot_class(db).normalized_impl(db, visitor),
|
self.pivot_class(db).normalized_impl(db, visitor),
|
||||||
|
|
|
@ -22,10 +22,11 @@ use crate::types::infer::nearest_enclosing_class;
|
||||||
use crate::types::signatures::{CallableSignature, Parameter, Parameters, Signature};
|
use crate::types::signatures::{CallableSignature, Parameter, Parameters, Signature};
|
||||||
use crate::types::tuple::{TupleSpec, TupleType};
|
use crate::types::tuple::{TupleSpec, TupleType};
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
BareTypeAliasType, Binding, BoundSuperError, BoundSuperType, CallableType, DataclassParams,
|
ApplyTypeMappingVisitor, BareTypeAliasType, Binding, BoundSuperError, BoundSuperType,
|
||||||
DeprecatedInstance, KnownInstanceType, StringLiteralType, TypeAliasType, TypeMapping,
|
CallableType, DataclassParams, DeprecatedInstance, HasRelationToVisitor, KnownInstanceType,
|
||||||
TypeRelation, TypeTransformer, TypeVarBoundOrConstraints, TypeVarInstance, TypeVarKind,
|
NormalizedVisitor, StringLiteralType, TypeAliasType, TypeMapping, TypeRelation,
|
||||||
declaration_type, infer_definition_types, todo_type,
|
TypeVarBoundOrConstraints, TypeVarInstance, TypeVarKind, declaration_type,
|
||||||
|
infer_definition_types, todo_type,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
Db, FxIndexMap, FxOrderSet, Program,
|
Db, FxIndexMap, FxOrderSet, Program,
|
||||||
|
@ -231,7 +232,7 @@ pub(super) fn walk_generic_alias<'db, V: super::visitor::TypeVisitor<'db> + ?Siz
|
||||||
impl get_size2::GetSize for GenericAlias<'_> {}
|
impl get_size2::GetSize for GenericAlias<'_> {}
|
||||||
|
|
||||||
impl<'db> GenericAlias<'db> {
|
impl<'db> GenericAlias<'db> {
|
||||||
pub(super) fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self {
|
pub(super) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self {
|
||||||
Self::new(
|
Self::new(
|
||||||
db,
|
db,
|
||||||
self.origin(db),
|
self.origin(db),
|
||||||
|
@ -255,7 +256,7 @@ impl<'db> GenericAlias<'db> {
|
||||||
self,
|
self,
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
type_mapping: &TypeMapping<'a, 'db>,
|
type_mapping: &TypeMapping<'a, 'db>,
|
||||||
visitor: &TypeTransformer<'db>,
|
visitor: &ApplyTypeMappingVisitor<'db>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self::new(
|
Self::new(
|
||||||
db,
|
db,
|
||||||
|
@ -319,7 +320,7 @@ impl<'db> ClassType<'db> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self {
|
pub(super) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self {
|
||||||
match self {
|
match self {
|
||||||
Self::NonGeneric(_) => self,
|
Self::NonGeneric(_) => self,
|
||||||
Self::Generic(generic) => Self::Generic(generic.normalized_impl(db, visitor)),
|
Self::Generic(generic) => Self::Generic(generic.normalized_impl(db, visitor)),
|
||||||
|
@ -406,7 +407,7 @@ impl<'db> ClassType<'db> {
|
||||||
self,
|
self,
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
type_mapping: &TypeMapping<'a, 'db>,
|
type_mapping: &TypeMapping<'a, 'db>,
|
||||||
visitor: &TypeTransformer<'db>,
|
visitor: &ApplyTypeMappingVisitor<'db>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
match self {
|
match self {
|
||||||
Self::NonGeneric(_) => self,
|
Self::NonGeneric(_) => self,
|
||||||
|
@ -469,7 +470,7 @@ impl<'db> ClassType<'db> {
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
other: Self,
|
other: Self,
|
||||||
relation: TypeRelation,
|
relation: TypeRelation,
|
||||||
visitor: &PairVisitor<'db>,
|
visitor: &HasRelationToVisitor<'db>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
self.iter_mro(db).any(|base| {
|
self.iter_mro(db).any(|base| {
|
||||||
match base {
|
match base {
|
||||||
|
|
|
@ -2,8 +2,9 @@ use crate::Db;
|
||||||
use crate::types::generics::Specialization;
|
use crate::types::generics::Specialization;
|
||||||
use crate::types::tuple::TupleType;
|
use crate::types::tuple::TupleType;
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
ClassLiteral, ClassType, DynamicType, KnownClass, KnownInstanceType, MroError, MroIterator,
|
ApplyTypeMappingVisitor, ClassLiteral, ClassType, DynamicType, KnownClass, KnownInstanceType,
|
||||||
SpecialFormType, Type, TypeMapping, TypeTransformer, todo_type,
|
MroError, MroIterator, NormalizedVisitor, SpecialFormType, Type, TypeMapping, TypeTransformer,
|
||||||
|
todo_type,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Enumeration of the possible kinds of types we allow in class bases.
|
/// Enumeration of the possible kinds of types we allow in class bases.
|
||||||
|
@ -33,7 +34,7 @@ impl<'db> ClassBase<'db> {
|
||||||
Self::Dynamic(DynamicType::Unknown)
|
Self::Dynamic(DynamicType::Unknown)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self {
|
pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self {
|
||||||
match self {
|
match self {
|
||||||
Self::Dynamic(dynamic) => Self::Dynamic(dynamic.normalized()),
|
Self::Dynamic(dynamic) => Self::Dynamic(dynamic.normalized()),
|
||||||
Self::Class(class) => Self::Class(class.normalized_impl(db, visitor)),
|
Self::Class(class) => Self::Class(class.normalized_impl(db, visitor)),
|
||||||
|
@ -269,7 +270,7 @@ impl<'db> ClassBase<'db> {
|
||||||
self,
|
self,
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
type_mapping: &TypeMapping<'a, 'db>,
|
type_mapping: &TypeMapping<'a, 'db>,
|
||||||
visitor: &TypeTransformer<'db>,
|
visitor: &ApplyTypeMappingVisitor<'db>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
match self {
|
match self {
|
||||||
Self::Class(class) => {
|
Self::Class(class) => {
|
||||||
|
|
|
@ -18,17 +18,20 @@
|
||||||
//! `visitor.visit` when visiting a protocol type, and then internal `has_relation_to_impl` methods
|
//! `visitor.visit` when visiting a protocol type, and then internal `has_relation_to_impl` methods
|
||||||
//! of the Rust types implementing protocols also call `visitor.visit`. The best way to avoid this
|
//! of the Rust types implementing protocols also call `visitor.visit`. The best way to avoid this
|
||||||
//! is to prefer always calling `visitor.visit` only in the main recursive method on `Type`.
|
//! is to prefer always calling `visitor.visit` only in the main recursive method on `Type`.
|
||||||
|
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::cmp::Eq;
|
||||||
|
use std::hash::Hash;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
|
|
||||||
use crate::FxIndexSet;
|
use crate::FxIndexSet;
|
||||||
use crate::types::Type;
|
use crate::types::Type;
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::cmp::Eq;
|
|
||||||
use std::hash::Hash;
|
|
||||||
|
|
||||||
pub(crate) type TypeTransformer<'db> = CycleDetector<Type<'db>, Type<'db>>;
|
pub(crate) type TypeTransformer<'db, Tag> = CycleDetector<Tag, Type<'db>, Type<'db>>;
|
||||||
|
|
||||||
impl Default for TypeTransformer<'_> {
|
impl<Tag> Default for TypeTransformer<'_, Tag> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
// TODO: proper recursive type handling
|
// TODO: proper recursive type handling
|
||||||
|
|
||||||
|
@ -38,10 +41,10 @@ impl Default for TypeTransformer<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) type PairVisitor<'db> = CycleDetector<(Type<'db>, Type<'db>), bool>;
|
pub(crate) type PairVisitor<'db, Tag> = CycleDetector<Tag, (Type<'db>, Type<'db>), bool>;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct CycleDetector<T, R> {
|
pub(crate) struct CycleDetector<Tag, T, R> {
|
||||||
/// If the type we're visiting is present in `seen`, it indicates that we've hit a cycle (due
|
/// If the type we're visiting is present in `seen`, it indicates that we've hit a cycle (due
|
||||||
/// to a recursive type); we need to immediately short circuit the whole operation and return
|
/// to a recursive type); we need to immediately short circuit the whole operation and return
|
||||||
/// the fallback value. That's why we pop items off the end of `seen` after we've visited them.
|
/// the fallback value. That's why we pop items off the end of `seen` after we've visited them.
|
||||||
|
@ -56,14 +59,17 @@ pub(crate) struct CycleDetector<T, R> {
|
||||||
cache: RefCell<FxHashMap<T, R>>,
|
cache: RefCell<FxHashMap<T, R>>,
|
||||||
|
|
||||||
fallback: R,
|
fallback: R,
|
||||||
|
|
||||||
|
_tag: PhantomData<Tag>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Hash + Eq + Copy, R: Copy> CycleDetector<T, R> {
|
impl<Tag, T: Hash + Eq + Copy, R: Copy> CycleDetector<Tag, T, R> {
|
||||||
pub(crate) fn new(fallback: R) -> Self {
|
pub(crate) fn new(fallback: R) -> Self {
|
||||||
CycleDetector {
|
CycleDetector {
|
||||||
seen: RefCell::new(FxIndexSet::default()),
|
seen: RefCell::new(FxIndexSet::default()),
|
||||||
cache: RefCell::new(FxHashMap::default()),
|
cache: RefCell::new(FxHashMap::default()),
|
||||||
fallback,
|
fallback,
|
||||||
|
_tag: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -77,8 +77,8 @@ use crate::types::signatures::{CallableSignature, Signature};
|
||||||
use crate::types::visitor::any_over_type;
|
use crate::types::visitor::any_over_type;
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
BoundMethodType, BoundTypeVarInstance, CallableType, ClassBase, ClassLiteral, ClassType,
|
BoundMethodType, BoundTypeVarInstance, CallableType, ClassBase, ClassLiteral, ClassType,
|
||||||
DeprecatedInstance, DynamicType, KnownClass, Truthiness, Type, TypeMapping, TypeRelation,
|
DeprecatedInstance, DynamicType, KnownClass, NormalizedVisitor, Truthiness, Type, TypeMapping,
|
||||||
TypeTransformer, UnionBuilder, all_members, walk_type_mapping,
|
TypeRelation, TypeTransformer, UnionBuilder, all_members, walk_type_mapping,
|
||||||
};
|
};
|
||||||
use crate::{Db, FxOrderSet, ModuleName, resolve_module};
|
use crate::{Db, FxOrderSet, ModuleName, resolve_module};
|
||||||
|
|
||||||
|
@ -604,7 +604,7 @@ impl<'db> FunctionLiteral<'db> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self {
|
fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self {
|
||||||
let context = self
|
let context = self
|
||||||
.inherited_generic_context(db)
|
.inherited_generic_context(db)
|
||||||
.map(|ctx| ctx.normalized_impl(db, visitor));
|
.map(|ctx| ctx.normalized_impl(db, visitor));
|
||||||
|
@ -923,7 +923,7 @@ impl<'db> FunctionType<'db> {
|
||||||
self.normalized_impl(db, &TypeTransformer::default())
|
self.normalized_impl(db, &TypeTransformer::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self {
|
pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self {
|
||||||
let mappings: Box<_> = self
|
let mappings: Box<_> = self
|
||||||
.type_mappings(db)
|
.type_mappings(db)
|
||||||
.iter()
|
.iter()
|
||||||
|
|
|
@ -14,9 +14,10 @@ use crate::types::instance::{Protocol, ProtocolInstanceType};
|
||||||
use crate::types::signatures::{Parameter, Parameters, Signature};
|
use crate::types::signatures::{Parameter, Parameters, Signature};
|
||||||
use crate::types::tuple::{TupleSpec, TupleType, walk_tuple_type};
|
use crate::types::tuple::{TupleSpec, TupleType, walk_tuple_type};
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
BoundTypeVarInstance, KnownClass, KnownInstanceType, Type, TypeMapping, TypeRelation,
|
ApplyTypeMappingVisitor, BoundTypeVarInstance, HasRelationToVisitor, KnownClass,
|
||||||
TypeTransformer, TypeVarBoundOrConstraints, TypeVarInstance, TypeVarVariance, UnionType,
|
KnownInstanceType, NormalizedVisitor, Type, TypeMapping, TypeRelation, TypeTransformer,
|
||||||
binding_type, cyclic::PairVisitor, declaration_type,
|
TypeVarBoundOrConstraints, TypeVarInstance, TypeVarVariance, UnionType, binding_type,
|
||||||
|
declaration_type,
|
||||||
};
|
};
|
||||||
use crate::{Db, FxOrderSet};
|
use crate::{Db, FxOrderSet};
|
||||||
|
|
||||||
|
@ -355,7 +356,7 @@ impl<'db> GenericContext<'db> {
|
||||||
Specialization::new(db, self, expanded.into_boxed_slice(), None)
|
Specialization::new(db, self, expanded.into_boxed_slice(), None)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self {
|
pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self {
|
||||||
let variables: FxOrderSet<_> = self
|
let variables: FxOrderSet<_> = self
|
||||||
.variables(db)
|
.variables(db)
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -471,7 +472,7 @@ impl<'db> Specialization<'db> {
|
||||||
self,
|
self,
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
type_mapping: &TypeMapping<'a, 'db>,
|
type_mapping: &TypeMapping<'a, 'db>,
|
||||||
visitor: &TypeTransformer<'db>,
|
visitor: &ApplyTypeMappingVisitor<'db>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let types: Box<[_]> = self
|
let types: Box<[_]> = self
|
||||||
.types(db)
|
.types(db)
|
||||||
|
@ -522,7 +523,7 @@ impl<'db> Specialization<'db> {
|
||||||
Specialization::new(db, self.generic_context(db), types, None)
|
Specialization::new(db, self.generic_context(db), types, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self {
|
pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self {
|
||||||
let types: Box<[_]> = self
|
let types: Box<[_]> = self
|
||||||
.types(db)
|
.types(db)
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -563,7 +564,7 @@ impl<'db> Specialization<'db> {
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
other: Self,
|
other: Self,
|
||||||
relation: TypeRelation,
|
relation: TypeRelation,
|
||||||
visitor: &PairVisitor<'db>,
|
visitor: &HasRelationToVisitor<'db>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let generic_context = self.generic_context(db);
|
let generic_context = self.generic_context(db);
|
||||||
if generic_context != other.generic_context(db) {
|
if generic_context != other.generic_context(db) {
|
||||||
|
@ -716,7 +717,7 @@ impl<'db> PartialSpecialization<'_, 'db> {
|
||||||
pub(crate) fn normalized_impl(
|
pub(crate) fn normalized_impl(
|
||||||
&self,
|
&self,
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
visitor: &TypeTransformer<'db>,
|
visitor: &NormalizedVisitor<'db>,
|
||||||
) -> PartialSpecialization<'db, 'db> {
|
) -> PartialSpecialization<'db, 'db> {
|
||||||
let generic_context = self.generic_context.normalized_impl(db, visitor);
|
let generic_context = self.generic_context.normalized_impl(db, visitor);
|
||||||
let types: Cow<_> = self
|
let types: Cow<_> = self
|
||||||
|
|
|
@ -7,11 +7,13 @@ use super::protocol_class::ProtocolInterface;
|
||||||
use super::{BoundTypeVarInstance, ClassType, KnownClass, SubclassOfType, Type, TypeVarVariance};
|
use super::{BoundTypeVarInstance, ClassType, KnownClass, SubclassOfType, Type, TypeVarVariance};
|
||||||
use crate::place::PlaceAndQualifiers;
|
use crate::place::PlaceAndQualifiers;
|
||||||
use crate::semantic_index::definition::Definition;
|
use crate::semantic_index::definition::Definition;
|
||||||
use crate::types::cyclic::PairVisitor;
|
|
||||||
use crate::types::enums::is_single_member_enum;
|
use crate::types::enums::is_single_member_enum;
|
||||||
use crate::types::protocol_class::walk_protocol_interface;
|
use crate::types::protocol_class::walk_protocol_interface;
|
||||||
use crate::types::tuple::{TupleSpec, TupleType};
|
use crate::types::tuple::{TupleSpec, TupleType};
|
||||||
use crate::types::{ClassBase, DynamicType, TypeMapping, TypeRelation, TypeTransformer};
|
use crate::types::{
|
||||||
|
ApplyTypeMappingVisitor, ClassBase, DynamicType, HasRelationToVisitor, IsDisjointVisitor,
|
||||||
|
NormalizedVisitor, TypeMapping, TypeRelation, TypeTransformer,
|
||||||
|
};
|
||||||
use crate::{Db, FxOrderSet};
|
use crate::{Db, FxOrderSet};
|
||||||
|
|
||||||
pub(super) use synthesized_protocol::SynthesizedProtocolType;
|
pub(super) use synthesized_protocol::SynthesizedProtocolType;
|
||||||
|
@ -241,7 +243,7 @@ impl<'db> NominalInstanceType<'db> {
|
||||||
pub(super) fn normalized_impl(
|
pub(super) fn normalized_impl(
|
||||||
self,
|
self,
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
visitor: &TypeTransformer<'db>,
|
visitor: &NormalizedVisitor<'db>,
|
||||||
) -> Type<'db> {
|
) -> Type<'db> {
|
||||||
match self.0 {
|
match self.0 {
|
||||||
NominalInstanceInner::ExactTuple(tuple) => {
|
NominalInstanceInner::ExactTuple(tuple) => {
|
||||||
|
@ -267,7 +269,7 @@ impl<'db> NominalInstanceType<'db> {
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
other: Self,
|
other: Self,
|
||||||
relation: TypeRelation,
|
relation: TypeRelation,
|
||||||
visitor: &PairVisitor<'db>,
|
visitor: &HasRelationToVisitor<'db>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
match (self.0, other.0) {
|
match (self.0, other.0) {
|
||||||
(
|
(
|
||||||
|
@ -297,7 +299,7 @@ impl<'db> NominalInstanceType<'db> {
|
||||||
self,
|
self,
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
other: Self,
|
other: Self,
|
||||||
visitor: &PairVisitor<'db>,
|
visitor: &IsDisjointVisitor<'db>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
if let Some(self_spec) = self.tuple_spec(db) {
|
if let Some(self_spec) = self.tuple_spec(db) {
|
||||||
if let Some(other_spec) = other.tuple_spec(db) {
|
if let Some(other_spec) = other.tuple_spec(db) {
|
||||||
|
@ -345,7 +347,7 @@ impl<'db> NominalInstanceType<'db> {
|
||||||
self,
|
self,
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
type_mapping: &TypeMapping<'a, 'db>,
|
type_mapping: &TypeMapping<'a, 'db>,
|
||||||
visitor: &TypeTransformer<'db>,
|
visitor: &ApplyTypeMappingVisitor<'db>,
|
||||||
) -> Type<'db> {
|
) -> Type<'db> {
|
||||||
match self.0 {
|
match self.0 {
|
||||||
NominalInstanceInner::ExactTuple(tuple) => {
|
NominalInstanceInner::ExactTuple(tuple) => {
|
||||||
|
@ -480,7 +482,7 @@ impl<'db> ProtocolInstanceType<'db> {
|
||||||
pub(super) fn normalized_impl(
|
pub(super) fn normalized_impl(
|
||||||
self,
|
self,
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
visitor: &TypeTransformer<'db>,
|
visitor: &NormalizedVisitor<'db>,
|
||||||
) -> Type<'db> {
|
) -> Type<'db> {
|
||||||
let object = Type::object(db);
|
let object = Type::object(db);
|
||||||
if object.satisfies_protocol(db, self, TypeRelation::Subtyping) {
|
if object.satisfies_protocol(db, self, TypeRelation::Subtyping) {
|
||||||
|
@ -532,7 +534,7 @@ impl<'db> ProtocolInstanceType<'db> {
|
||||||
self,
|
self,
|
||||||
_db: &'db dyn Db,
|
_db: &'db dyn Db,
|
||||||
_other: Self,
|
_other: Self,
|
||||||
_visitor: &PairVisitor<'db>,
|
_visitor: &IsDisjointVisitor<'db>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
@ -558,7 +560,7 @@ impl<'db> ProtocolInstanceType<'db> {
|
||||||
self,
|
self,
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
type_mapping: &TypeMapping<'a, 'db>,
|
type_mapping: &TypeMapping<'a, 'db>,
|
||||||
visitor: &TypeTransformer<'db>,
|
visitor: &ApplyTypeMappingVisitor<'db>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
match self.inner {
|
match self.inner {
|
||||||
Protocol::FromClass(class) => {
|
Protocol::FromClass(class) => {
|
||||||
|
@ -619,7 +621,10 @@ impl<'db> Protocol<'db> {
|
||||||
mod synthesized_protocol {
|
mod synthesized_protocol {
|
||||||
use crate::semantic_index::definition::Definition;
|
use crate::semantic_index::definition::Definition;
|
||||||
use crate::types::protocol_class::ProtocolInterface;
|
use crate::types::protocol_class::ProtocolInterface;
|
||||||
use crate::types::{BoundTypeVarInstance, TypeMapping, TypeTransformer, TypeVarVariance};
|
use crate::types::{
|
||||||
|
ApplyTypeMappingVisitor, BoundTypeVarInstance, NormalizedVisitor, TypeMapping,
|
||||||
|
TypeVarVariance,
|
||||||
|
};
|
||||||
use crate::{Db, FxOrderSet};
|
use crate::{Db, FxOrderSet};
|
||||||
|
|
||||||
/// A "synthesized" protocol type that is dissociated from a class definition in source code.
|
/// A "synthesized" protocol type that is dissociated from a class definition in source code.
|
||||||
|
@ -640,7 +645,7 @@ mod synthesized_protocol {
|
||||||
pub(super) fn new(
|
pub(super) fn new(
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
interface: ProtocolInterface<'db>,
|
interface: ProtocolInterface<'db>,
|
||||||
visitor: &TypeTransformer<'db>,
|
visitor: &NormalizedVisitor<'db>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self(interface.normalized_impl(db, visitor))
|
Self(interface.normalized_impl(db, visitor))
|
||||||
}
|
}
|
||||||
|
@ -653,7 +658,7 @@ mod synthesized_protocol {
|
||||||
self,
|
self,
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
type_mapping: &TypeMapping<'a, 'db>,
|
type_mapping: &TypeMapping<'a, 'db>,
|
||||||
_visitor: &TypeTransformer<'db>,
|
_visitor: &ApplyTypeMappingVisitor<'db>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self(self.0.specialized_and_normalized(db, type_mapping))
|
Self(self.0.specialized_and_normalized(db, type_mapping))
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,10 +12,9 @@ use crate::{
|
||||||
place::{Boundness, Place, PlaceAndQualifiers, place_from_bindings, place_from_declarations},
|
place::{Boundness, Place, PlaceAndQualifiers, place_from_bindings, place_from_declarations},
|
||||||
semantic_index::{definition::Definition, use_def_map},
|
semantic_index::{definition::Definition, use_def_map},
|
||||||
types::{
|
types::{
|
||||||
BoundTypeVarInstance, CallableType, ClassBase, ClassLiteral, KnownFunction,
|
BoundTypeVarInstance, CallableType, ClassBase, ClassLiteral, IsDisjointVisitor,
|
||||||
PropertyInstanceType, Signature, Type, TypeMapping, TypeQualifiers, TypeRelation,
|
KnownFunction, NormalizedVisitor, PropertyInstanceType, Signature, Type, TypeMapping,
|
||||||
TypeTransformer,
|
TypeQualifiers, TypeRelation, TypeTransformer,
|
||||||
cyclic::PairVisitor,
|
|
||||||
signatures::{Parameter, Parameters},
|
signatures::{Parameter, Parameters},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -165,7 +164,7 @@ impl<'db> ProtocolInterface<'db> {
|
||||||
.all(|member_name| other.inner(db).contains_key(member_name))
|
.all(|member_name| other.inner(db).contains_key(member_name))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self {
|
pub(super) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self {
|
||||||
Self::new(
|
Self::new(
|
||||||
db,
|
db,
|
||||||
self.inner(db)
|
self.inner(db)
|
||||||
|
@ -252,7 +251,7 @@ impl<'db> ProtocolMemberData<'db> {
|
||||||
self.normalized_impl(db, &TypeTransformer::default())
|
self.normalized_impl(db, &TypeTransformer::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn normalized_impl(&self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self {
|
fn normalized_impl(&self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
kind: self.kind.normalized_impl(db, visitor),
|
kind: self.kind.normalized_impl(db, visitor),
|
||||||
qualifiers: self.qualifiers,
|
qualifiers: self.qualifiers,
|
||||||
|
@ -327,7 +326,7 @@ enum ProtocolMemberKind<'db> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'db> ProtocolMemberKind<'db> {
|
impl<'db> ProtocolMemberKind<'db> {
|
||||||
fn normalized_impl(&self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self {
|
fn normalized_impl(&self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self {
|
||||||
match self {
|
match self {
|
||||||
ProtocolMemberKind::Method(callable) => {
|
ProtocolMemberKind::Method(callable) => {
|
||||||
ProtocolMemberKind::Method(callable.normalized_impl(db, visitor))
|
ProtocolMemberKind::Method(callable.normalized_impl(db, visitor))
|
||||||
|
@ -432,7 +431,7 @@ impl<'a, 'db> ProtocolMember<'a, 'db> {
|
||||||
&self,
|
&self,
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
other: Type<'db>,
|
other: Type<'db>,
|
||||||
visitor: &PairVisitor<'db>,
|
visitor: &IsDisjointVisitor<'db>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
match &self.kind {
|
match &self.kind {
|
||||||
// TODO: implement disjointness for property/method members as well as attribute members
|
// TODO: implement disjointness for property/method members as well as attribute members
|
||||||
|
|
|
@ -15,10 +15,12 @@ use std::{collections::HashMap, slice::Iter};
|
||||||
use itertools::EitherOrBoth;
|
use itertools::EitherOrBoth;
|
||||||
use smallvec::{SmallVec, smallvec_inline};
|
use smallvec::{SmallVec, smallvec_inline};
|
||||||
|
|
||||||
use super::{DynamicType, Type, TypeTransformer, TypeVarVariance, definition_expression_type};
|
use super::{DynamicType, Type, TypeVarVariance, definition_expression_type};
|
||||||
use crate::semantic_index::definition::Definition;
|
use crate::semantic_index::definition::Definition;
|
||||||
use crate::types::generics::{GenericContext, walk_generic_context};
|
use crate::types::generics::{GenericContext, walk_generic_context};
|
||||||
use crate::types::{BoundTypeVarInstance, KnownClass, TypeMapping, TypeRelation, todo_type};
|
use crate::types::{
|
||||||
|
BoundTypeVarInstance, KnownClass, NormalizedVisitor, TypeMapping, TypeRelation, todo_type,
|
||||||
|
};
|
||||||
use crate::{Db, FxOrderSet};
|
use crate::{Db, FxOrderSet};
|
||||||
use ruff_python_ast::{self as ast, name::Name};
|
use ruff_python_ast::{self as ast, name::Name};
|
||||||
|
|
||||||
|
@ -61,7 +63,11 @@ impl<'db> CallableSignature<'db> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn normalized_impl(&self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self {
|
pub(crate) fn normalized_impl(
|
||||||
|
&self,
|
||||||
|
db: &'db dyn Db,
|
||||||
|
visitor: &NormalizedVisitor<'db>,
|
||||||
|
) -> Self {
|
||||||
Self::from_overloads(
|
Self::from_overloads(
|
||||||
self.overloads
|
self.overloads
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -380,7 +386,11 @@ impl<'db> Signature<'db> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn normalized_impl(&self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self {
|
pub(crate) fn normalized_impl(
|
||||||
|
&self,
|
||||||
|
db: &'db dyn Db,
|
||||||
|
visitor: &NormalizedVisitor<'db>,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
generic_context: self
|
generic_context: self
|
||||||
.generic_context
|
.generic_context
|
||||||
|
@ -1360,7 +1370,11 @@ impl<'db> Parameter<'db> {
|
||||||
/// Normalize nested unions and intersections in the annotated type, if any.
|
/// Normalize nested unions and intersections in the annotated type, if any.
|
||||||
///
|
///
|
||||||
/// See [`Type::normalized`] for more details.
|
/// See [`Type::normalized`] for more details.
|
||||||
pub(crate) fn normalized_impl(&self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self {
|
pub(crate) fn normalized_impl(
|
||||||
|
&self,
|
||||||
|
db: &'db dyn Db,
|
||||||
|
visitor: &NormalizedVisitor<'db>,
|
||||||
|
) -> Self {
|
||||||
let Parameter {
|
let Parameter {
|
||||||
annotated_type,
|
annotated_type,
|
||||||
kind,
|
kind,
|
||||||
|
|
|
@ -3,8 +3,9 @@ use ruff_python_ast::name::Name;
|
||||||
use crate::place::PlaceAndQualifiers;
|
use crate::place::PlaceAndQualifiers;
|
||||||
use crate::semantic_index::definition::Definition;
|
use crate::semantic_index::definition::Definition;
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
BindingContext, BoundTypeVarInstance, ClassType, DynamicType, KnownClass, MemberLookupPolicy,
|
ApplyTypeMappingVisitor, BindingContext, BoundTypeVarInstance, ClassType, DynamicType,
|
||||||
Type, TypeMapping, TypeRelation, TypeTransformer, TypeVarInstance, cyclic::PairVisitor,
|
HasRelationToVisitor, KnownClass, MemberLookupPolicy, NormalizedVisitor, Type, TypeMapping,
|
||||||
|
TypeRelation, TypeVarInstance,
|
||||||
};
|
};
|
||||||
use crate::{Db, FxOrderSet};
|
use crate::{Db, FxOrderSet};
|
||||||
|
|
||||||
|
@ -116,7 +117,7 @@ impl<'db> SubclassOfType<'db> {
|
||||||
self,
|
self,
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
type_mapping: &TypeMapping<'a, 'db>,
|
type_mapping: &TypeMapping<'a, 'db>,
|
||||||
visitor: &TypeTransformer<'db>,
|
visitor: &ApplyTypeMappingVisitor<'db>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
match self.subclass_of {
|
match self.subclass_of {
|
||||||
SubclassOfInner::Class(class) => Self {
|
SubclassOfInner::Class(class) => Self {
|
||||||
|
@ -159,7 +160,7 @@ impl<'db> SubclassOfType<'db> {
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
other: SubclassOfType<'db>,
|
other: SubclassOfType<'db>,
|
||||||
relation: TypeRelation,
|
relation: TypeRelation,
|
||||||
visitor: &PairVisitor<'db>,
|
visitor: &HasRelationToVisitor<'db>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
match (self.subclass_of, other.subclass_of) {
|
match (self.subclass_of, other.subclass_of) {
|
||||||
(SubclassOfInner::Dynamic(_), SubclassOfInner::Dynamic(_)) => {
|
(SubclassOfInner::Dynamic(_), SubclassOfInner::Dynamic(_)) => {
|
||||||
|
@ -191,7 +192,7 @@ impl<'db> SubclassOfType<'db> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self {
|
pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
subclass_of: self.subclass_of.normalized_impl(db, visitor),
|
subclass_of: self.subclass_of.normalized_impl(db, visitor),
|
||||||
}
|
}
|
||||||
|
@ -254,7 +255,7 @@ impl<'db> SubclassOfInner<'db> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self {
|
pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self {
|
||||||
match self {
|
match self {
|
||||||
Self::Class(class) => Self::Class(class.normalized_impl(db, visitor)),
|
Self::Class(class) => Self::Class(class.normalized_impl(db, visitor)),
|
||||||
Self::Dynamic(dynamic) => Self::Dynamic(dynamic.normalized()),
|
Self::Dynamic(dynamic) => Self::Dynamic(dynamic.normalized()),
|
||||||
|
|
|
@ -25,8 +25,8 @@ use crate::semantic_index::definition::Definition;
|
||||||
use crate::types::Truthiness;
|
use crate::types::Truthiness;
|
||||||
use crate::types::class::{ClassType, KnownClass};
|
use crate::types::class::{ClassType, KnownClass};
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
BoundTypeVarInstance, Type, TypeMapping, TypeRelation, TypeTransformer, TypeVarVariance,
|
ApplyTypeMappingVisitor, BoundTypeVarInstance, HasRelationToVisitor, IsDisjointVisitor,
|
||||||
UnionBuilder, UnionType, cyclic::PairVisitor,
|
NormalizedVisitor, Type, TypeMapping, TypeRelation, TypeVarVariance, UnionBuilder, UnionType,
|
||||||
};
|
};
|
||||||
use crate::util::subscript::{Nth, OutOfBoundsError, PyIndex, PySlice, StepSizeZeroError};
|
use crate::util::subscript::{Nth, OutOfBoundsError, PyIndex, PySlice, StepSizeZeroError};
|
||||||
use crate::{Db, FxOrderSet, Program};
|
use crate::{Db, FxOrderSet, Program};
|
||||||
|
@ -221,7 +221,7 @@ impl<'db> TupleType<'db> {
|
||||||
pub(crate) fn normalized_impl(
|
pub(crate) fn normalized_impl(
|
||||||
self,
|
self,
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
visitor: &TypeTransformer<'db>,
|
visitor: &NormalizedVisitor<'db>,
|
||||||
) -> Option<Self> {
|
) -> Option<Self> {
|
||||||
TupleType::new(db, &self.tuple(db).normalized_impl(db, visitor))
|
TupleType::new(db, &self.tuple(db).normalized_impl(db, visitor))
|
||||||
}
|
}
|
||||||
|
@ -234,7 +234,7 @@ impl<'db> TupleType<'db> {
|
||||||
self,
|
self,
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
type_mapping: &TypeMapping<'a, 'db>,
|
type_mapping: &TypeMapping<'a, 'db>,
|
||||||
visitor: &TypeTransformer<'db>,
|
visitor: &ApplyTypeMappingVisitor<'db>,
|
||||||
) -> Option<Self> {
|
) -> Option<Self> {
|
||||||
TupleType::new(
|
TupleType::new(
|
||||||
db,
|
db,
|
||||||
|
@ -259,7 +259,7 @@ impl<'db> TupleType<'db> {
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
other: Self,
|
other: Self,
|
||||||
relation: TypeRelation,
|
relation: TypeRelation,
|
||||||
visitor: &PairVisitor<'db>,
|
visitor: &HasRelationToVisitor<'db>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
self.tuple(db)
|
self.tuple(db)
|
||||||
.has_relation_to_impl(db, other.tuple(db), relation, visitor)
|
.has_relation_to_impl(db, other.tuple(db), relation, visitor)
|
||||||
|
@ -377,7 +377,7 @@ impl<'db> FixedLengthTuple<Type<'db>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn normalized_impl(&self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self {
|
fn normalized_impl(&self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self {
|
||||||
Self::from_elements(self.0.iter().map(|ty| ty.normalized_impl(db, visitor)))
|
Self::from_elements(self.0.iter().map(|ty| ty.normalized_impl(db, visitor)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -389,7 +389,7 @@ impl<'db> FixedLengthTuple<Type<'db>> {
|
||||||
&self,
|
&self,
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
type_mapping: &TypeMapping<'a, 'db>,
|
type_mapping: &TypeMapping<'a, 'db>,
|
||||||
visitor: &TypeTransformer<'db>,
|
visitor: &ApplyTypeMappingVisitor<'db>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self::from_elements(
|
Self::from_elements(
|
||||||
self.0
|
self.0
|
||||||
|
@ -414,7 +414,7 @@ impl<'db> FixedLengthTuple<Type<'db>> {
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
other: &Tuple<Type<'db>>,
|
other: &Tuple<Type<'db>>,
|
||||||
relation: TypeRelation,
|
relation: TypeRelation,
|
||||||
visitor: &PairVisitor<'db>,
|
visitor: &HasRelationToVisitor<'db>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
match other {
|
match other {
|
||||||
Tuple::Fixed(other) => {
|
Tuple::Fixed(other) => {
|
||||||
|
@ -658,7 +658,7 @@ impl<'db> VariableLengthTuple<Type<'db>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn normalized_impl(&self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> TupleSpec<'db> {
|
fn normalized_impl(&self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> TupleSpec<'db> {
|
||||||
let prefix = self
|
let prefix = self
|
||||||
.prenormalized_prefix_elements(db, None)
|
.prenormalized_prefix_elements(db, None)
|
||||||
.map(|ty| ty.normalized_impl(db, visitor))
|
.map(|ty| ty.normalized_impl(db, visitor))
|
||||||
|
@ -687,7 +687,7 @@ impl<'db> VariableLengthTuple<Type<'db>> {
|
||||||
&self,
|
&self,
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
type_mapping: &TypeMapping<'a, 'db>,
|
type_mapping: &TypeMapping<'a, 'db>,
|
||||||
visitor: &TypeTransformer<'db>,
|
visitor: &ApplyTypeMappingVisitor<'db>,
|
||||||
) -> TupleSpec<'db> {
|
) -> TupleSpec<'db> {
|
||||||
Self::mixed(
|
Self::mixed(
|
||||||
self.prefix
|
self.prefix
|
||||||
|
@ -722,7 +722,7 @@ impl<'db> VariableLengthTuple<Type<'db>> {
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
other: &Tuple<Type<'db>>,
|
other: &Tuple<Type<'db>>,
|
||||||
relation: TypeRelation,
|
relation: TypeRelation,
|
||||||
visitor: &PairVisitor<'db>,
|
visitor: &HasRelationToVisitor<'db>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
match other {
|
match other {
|
||||||
Tuple::Fixed(other) => {
|
Tuple::Fixed(other) => {
|
||||||
|
@ -983,7 +983,11 @@ impl<'db> Tuple<Type<'db>> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn normalized_impl(&self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self {
|
pub(crate) fn normalized_impl(
|
||||||
|
&self,
|
||||||
|
db: &'db dyn Db,
|
||||||
|
visitor: &NormalizedVisitor<'db>,
|
||||||
|
) -> Self {
|
||||||
match self {
|
match self {
|
||||||
Tuple::Fixed(tuple) => Tuple::Fixed(tuple.normalized_impl(db, visitor)),
|
Tuple::Fixed(tuple) => Tuple::Fixed(tuple.normalized_impl(db, visitor)),
|
||||||
Tuple::Variable(tuple) => tuple.normalized_impl(db, visitor),
|
Tuple::Variable(tuple) => tuple.normalized_impl(db, visitor),
|
||||||
|
@ -1001,7 +1005,7 @@ impl<'db> Tuple<Type<'db>> {
|
||||||
&self,
|
&self,
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
type_mapping: &TypeMapping<'a, 'db>,
|
type_mapping: &TypeMapping<'a, 'db>,
|
||||||
visitor: &TypeTransformer<'db>,
|
visitor: &ApplyTypeMappingVisitor<'db>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
match self {
|
match self {
|
||||||
Tuple::Fixed(tuple) => {
|
Tuple::Fixed(tuple) => {
|
||||||
|
@ -1028,7 +1032,7 @@ impl<'db> Tuple<Type<'db>> {
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
other: &Self,
|
other: &Self,
|
||||||
relation: TypeRelation,
|
relation: TypeRelation,
|
||||||
visitor: &PairVisitor<'db>,
|
visitor: &HasRelationToVisitor<'db>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Tuple::Fixed(self_tuple) => {
|
Tuple::Fixed(self_tuple) => {
|
||||||
|
@ -1056,7 +1060,7 @@ impl<'db> Tuple<Type<'db>> {
|
||||||
&self,
|
&self,
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
other: &Self,
|
other: &Self,
|
||||||
visitor: &PairVisitor<'db>,
|
visitor: &IsDisjointVisitor<'db>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
// Two tuples with an incompatible number of required elements must always be disjoint.
|
// Two tuples with an incompatible number of required elements must always be disjoint.
|
||||||
let (self_min, self_max) = self.len().size_hint();
|
let (self_min, self_max) = self.len().size_hint();
|
||||||
|
@ -1074,7 +1078,7 @@ impl<'db> Tuple<Type<'db>> {
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
a: impl IntoIterator<Item = &'s Type<'db>>,
|
a: impl IntoIterator<Item = &'s Type<'db>>,
|
||||||
b: impl IntoIterator<Item = &'s Type<'db>>,
|
b: impl IntoIterator<Item = &'s Type<'db>>,
|
||||||
visitor: &PairVisitor<'db>,
|
visitor: &IsDisjointVisitor<'db>,
|
||||||
) -> bool
|
) -> bool
|
||||||
where
|
where
|
||||||
'db: 's,
|
'db: 's,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue