diff --git a/crates/ty_python_semantic/resources/mdtest/pep695_type_aliases.md b/crates/ty_python_semantic/resources/mdtest/pep695_type_aliases.md index 0beca03adb..097b6c347b 100644 --- a/crates/ty_python_semantic/resources/mdtest/pep695_type_aliases.md +++ b/crates/ty_python_semantic/resources/mdtest/pep695_type_aliases.md @@ -276,6 +276,17 @@ def h(x: Intersection[A, B]): reveal_type(x) # revealed: tuple[B] | None ``` +### Self-recursive callable type + +```py +from typing import Callable + +type C = Callable[[], C | None] + +def _(x: C): + reveal_type(x) # revealed: () -> C | None +``` + ### Union inside generic #### With old-style union diff --git a/crates/ty_python_semantic/src/types.rs b/crates/ty_python_semantic/src/types.rs index 15f652e3b4..509ff9af45 100644 --- a/crates/ty_python_semantic/src/types.rs +++ b/crates/ty_python_semantic/src/types.rs @@ -489,13 +489,18 @@ fn walk_property_instance_type<'db, V: visitor::TypeVisitor<'db> + ?Sized>( impl get_size2::GetSize for PropertyInstanceType<'_> {} impl<'db> PropertyInstanceType<'db> { - fn apply_type_mapping<'a>(self, db: &'db dyn Db, type_mapping: &TypeMapping<'a, 'db>) -> Self { + fn apply_type_mapping_impl<'a>( + self, + db: &'db dyn Db, + type_mapping: &TypeMapping<'a, 'db>, + visitor: &ApplyTypeMappingVisitor<'db>, + ) -> Self { let getter = self .getter(db) - .map(|ty| ty.apply_type_mapping(db, type_mapping)); + .map(|ty| ty.apply_type_mapping_impl(db, type_mapping, visitor)); let setter = self .setter(db) - .map(|ty| ty.apply_type_mapping(db, type_mapping)); + .map(|ty| ty.apply_type_mapping_impl(db, type_mapping, visitor)); Self::new(db, getter, setter) } @@ -6077,18 +6082,18 @@ impl<'db> Type<'db> { Type::MethodWrapper(MethodWrapperKind::PropertyDunderGet(property)) => { Type::MethodWrapper(MethodWrapperKind::PropertyDunderGet( - property.apply_type_mapping(db, type_mapping), + property.apply_type_mapping_impl(db, type_mapping, visitor), )) } Type::MethodWrapper(MethodWrapperKind::PropertyDunderSet(property)) => { Type::MethodWrapper(MethodWrapperKind::PropertyDunderSet( - property.apply_type_mapping(db, type_mapping), + property.apply_type_mapping_impl(db, type_mapping, visitor), )) } Type::Callable(callable) => { - Type::Callable(callable.apply_type_mapping(db, type_mapping)) + Type::Callable(callable.apply_type_mapping_impl(db, type_mapping, visitor)) } Type::GenericAlias(generic) => { @@ -6104,7 +6109,7 @@ impl<'db> Type<'db> { ), Type::PropertyInstance(property) => { - Type::PropertyInstance(property.apply_type_mapping(db, type_mapping)) + Type::PropertyInstance(property.apply_type_mapping_impl(db, type_mapping, visitor)) } Type::Union(union) => union.map(db, |element| { @@ -8985,10 +8990,16 @@ impl<'db> CallableType<'db> { ) } - fn apply_type_mapping<'a>(self, db: &'db dyn Db, type_mapping: &TypeMapping<'a, 'db>) -> Self { + fn apply_type_mapping_impl<'a>( + self, + db: &'db dyn Db, + type_mapping: &TypeMapping<'a, 'db>, + visitor: &ApplyTypeMappingVisitor<'db>, + ) -> Self { CallableType::new( db, - self.signatures(db).apply_type_mapping(db, type_mapping), + self.signatures(db) + .apply_type_mapping_impl(db, type_mapping, visitor), self.is_function_like(db), ) } diff --git a/crates/ty_python_semantic/src/types/function.rs b/crates/ty_python_semantic/src/types/function.rs index a59b51ad28..9cda288267 100644 --- a/crates/ty_python_semantic/src/types/function.rs +++ b/crates/ty_python_semantic/src/types/function.rs @@ -569,7 +569,7 @@ impl<'db> FunctionLiteral<'db> { if overloads.is_empty() { return CallableSignature::single(type_mappings.iter().fold( implementation.signature(db, inherited_generic_context), - |ty, mapping| ty.apply_type_mapping(db, mapping), + |sig, mapping| sig.apply_type_mapping(db, mapping), )); } } @@ -577,7 +577,7 @@ impl<'db> FunctionLiteral<'db> { CallableSignature::from_overloads(overloads.iter().map(|overload| { type_mappings.iter().fold( overload.signature(db, inherited_generic_context), - |ty, mapping| ty.apply_type_mapping(db, mapping), + |sig, mapping| sig.apply_type_mapping(db, mapping), ) })) } @@ -602,7 +602,7 @@ impl<'db> FunctionLiteral<'db> { type_mappings.iter().fold( self.last_definition(db) .signature(db, inherited_generic_context), - |ty, mapping| ty.apply_type_mapping(db, mapping), + |sig, mapping| sig.apply_type_mapping(db, mapping), ) } diff --git a/crates/ty_python_semantic/src/types/protocol_class.rs b/crates/ty_python_semantic/src/types/protocol_class.rs index 20811ca497..f375885512 100644 --- a/crates/ty_python_semantic/src/types/protocol_class.rs +++ b/crates/ty_python_semantic/src/types/protocol_class.rs @@ -17,10 +17,10 @@ use crate::{ place::{Boundness, Place, PlaceAndQualifiers, place_from_bindings, place_from_declarations}, semantic_index::{definition::Definition, use_def_map}, types::{ - BoundTypeVarInstance, CallableType, ClassBase, ClassLiteral, FindLegacyTypeVarsVisitor, - HasRelationToVisitor, IsDisjointVisitor, KnownFunction, MaterializationKind, - NormalizedVisitor, PropertyInstanceType, Signature, Type, TypeMapping, TypeQualifiers, - TypeRelation, VarianceInferable, + ApplyTypeMappingVisitor, BoundTypeVarInstance, CallableType, ClassBase, ClassLiteral, + FindLegacyTypeVarsVisitor, HasRelationToVisitor, IsDisjointVisitor, KnownFunction, + MaterializationKind, NormalizedVisitor, PropertyInstanceType, Signature, Type, TypeMapping, + TypeQualifiers, TypeRelation, VarianceInferable, constraints::{Constraints, IteratorConstraintsExtension}, signatures::{Parameter, Parameters}, }, @@ -282,7 +282,12 @@ impl<'db> ProtocolInterface<'db> { .map(|(name, data)| { ( name.clone(), - data.apply_type_mapping(db, type_mapping).normalized(db), + data.apply_type_mapping_impl( + db, + type_mapping, + &ApplyTypeMappingVisitor::default(), + ) + .normalized(db), ) }) .collect::>(), @@ -354,9 +359,14 @@ impl<'db> ProtocolMemberData<'db> { } } - fn apply_type_mapping<'a>(&self, db: &'db dyn Db, type_mapping: &TypeMapping<'a, 'db>) -> Self { + fn apply_type_mapping_impl<'a>( + &self, + db: &'db dyn Db, + type_mapping: &TypeMapping<'a, 'db>, + visitor: &ApplyTypeMappingVisitor<'db>, + ) -> Self { Self { - kind: self.kind.apply_type_mapping(db, type_mapping), + kind: self.kind.apply_type_mapping_impl(db, type_mapping, visitor), qualifiers: self.qualifiers, } } @@ -444,16 +454,21 @@ impl<'db> ProtocolMemberKind<'db> { } } - fn apply_type_mapping<'a>(&self, db: &'db dyn Db, type_mapping: &TypeMapping<'a, 'db>) -> Self { + fn apply_type_mapping_impl<'a>( + &self, + db: &'db dyn Db, + type_mapping: &TypeMapping<'a, 'db>, + visitor: &ApplyTypeMappingVisitor<'db>, + ) -> Self { match self { - ProtocolMemberKind::Method(callable) => { - ProtocolMemberKind::Method(callable.apply_type_mapping(db, type_mapping)) - } - ProtocolMemberKind::Property(property) => { - ProtocolMemberKind::Property(property.apply_type_mapping(db, type_mapping)) - } + ProtocolMemberKind::Method(callable) => ProtocolMemberKind::Method( + callable.apply_type_mapping_impl(db, type_mapping, visitor), + ), + ProtocolMemberKind::Property(property) => ProtocolMemberKind::Property( + property.apply_type_mapping_impl(db, type_mapping, visitor), + ), ProtocolMemberKind::Other(ty) => { - ProtocolMemberKind::Other(ty.apply_type_mapping(db, type_mapping)) + ProtocolMemberKind::Other(ty.apply_type_mapping_impl(db, type_mapping, visitor)) } } } diff --git a/crates/ty_python_semantic/src/types/signatures.rs b/crates/ty_python_semantic/src/types/signatures.rs index 509c1b4ffb..70c1641a0c 100644 --- a/crates/ty_python_semantic/src/types/signatures.rs +++ b/crates/ty_python_semantic/src/types/signatures.rs @@ -20,9 +20,9 @@ use crate::semantic_index::definition::Definition; use crate::types::constraints::{ConstraintSet, Constraints, IteratorConstraintsExtension}; use crate::types::generics::{GenericContext, walk_generic_context}; use crate::types::{ - BindingContext, BoundTypeVarInstance, FindLegacyTypeVarsVisitor, HasRelationToVisitor, - IsEquivalentVisitor, KnownClass, MaterializationKind, NormalizedVisitor, TypeMapping, - TypeRelation, VarianceInferable, todo_type, + ApplyTypeMappingVisitor, BindingContext, BoundTypeVarInstance, FindLegacyTypeVarsVisitor, + HasRelationToVisitor, IsEquivalentVisitor, KnownClass, MaterializationKind, NormalizedVisitor, + TypeMapping, TypeRelation, VarianceInferable, todo_type, }; use crate::{Db, FxOrderSet}; use ruff_python_ast::{self as ast, name::Name}; @@ -82,15 +82,16 @@ impl<'db> CallableSignature<'db> { ) } - pub(crate) fn apply_type_mapping<'a>( + pub(crate) fn apply_type_mapping_impl<'a>( &self, db: &'db dyn Db, type_mapping: &TypeMapping<'a, 'db>, + visitor: &ApplyTypeMappingVisitor<'db>, ) -> Self { Self::from_overloads( self.overloads .iter() - .map(|signature| signature.apply_type_mapping(db, type_mapping)), + .map(|signature| signature.apply_type_mapping_impl(db, type_mapping, visitor)), ) } @@ -458,15 +459,26 @@ impl<'db> Signature<'db> { &self, db: &'db dyn Db, type_mapping: &TypeMapping<'a, 'db>, + ) -> Self { + self.apply_type_mapping_impl(db, type_mapping, &ApplyTypeMappingVisitor::default()) + } + + pub(crate) fn apply_type_mapping_impl<'a>( + &self, + db: &'db dyn Db, + type_mapping: &TypeMapping<'a, 'db>, + visitor: &ApplyTypeMappingVisitor<'db>, ) -> Self { Self { generic_context: self.generic_context, inherited_generic_context: self.inherited_generic_context, definition: self.definition, - parameters: self.parameters.apply_type_mapping(db, type_mapping), + parameters: self + .parameters + .apply_type_mapping_impl(db, type_mapping, visitor), return_ty: self .return_ty - .map(|ty| ty.apply_type_mapping(db, type_mapping)), + .map(|ty| ty.apply_type_mapping_impl(db, type_mapping, visitor)), } } @@ -504,7 +516,11 @@ impl<'db> Signature<'db> { let mut parameters = Parameters::new(self.parameters().iter().skip(1).cloned()); let mut return_ty = self.return_ty; if let Some(self_type) = self_type { - parameters = parameters.apply_type_mapping(db, &TypeMapping::BindSelf(self_type)); + parameters = parameters.apply_type_mapping_impl( + db, + &TypeMapping::BindSelf(self_type), + &ApplyTypeMappingVisitor::default(), + ); return_ty = return_ty.map(|ty| ty.apply_type_mapping(db, &TypeMapping::BindSelf(self_type))); } @@ -1232,12 +1248,17 @@ impl<'db> Parameters<'db> { ) } - fn apply_type_mapping<'a>(&self, db: &'db dyn Db, type_mapping: &TypeMapping<'a, 'db>) -> Self { + fn apply_type_mapping_impl<'a>( + &self, + db: &'db dyn Db, + type_mapping: &TypeMapping<'a, 'db>, + visitor: &ApplyTypeMappingVisitor<'db>, + ) -> Self { Self { value: self .value .iter() - .map(|param| param.apply_type_mapping(db, type_mapping)) + .map(|param| param.apply_type_mapping_impl(db, type_mapping, visitor)) .collect(), is_gradual: self.is_gradual, } @@ -1416,12 +1437,17 @@ impl<'db> Parameter<'db> { } } - fn apply_type_mapping<'a>(&self, db: &'db dyn Db, type_mapping: &TypeMapping<'a, 'db>) -> Self { + fn apply_type_mapping_impl<'a>( + &self, + db: &'db dyn Db, + type_mapping: &TypeMapping<'a, 'db>, + visitor: &ApplyTypeMappingVisitor<'db>, + ) -> Self { Self { annotated_type: self .annotated_type - .map(|ty| ty.apply_type_mapping(db, type_mapping)), - kind: self.kind.apply_type_mapping(db, type_mapping), + .map(|ty| ty.apply_type_mapping_impl(db, type_mapping, visitor)), + kind: self.kind.apply_type_mapping_impl(db, type_mapping, visitor), form: self.form, } } @@ -1625,24 +1651,29 @@ pub(crate) enum ParameterKind<'db> { } impl<'db> ParameterKind<'db> { - fn apply_type_mapping<'a>(&self, db: &'db dyn Db, type_mapping: &TypeMapping<'a, 'db>) -> Self { + fn apply_type_mapping_impl<'a>( + &self, + db: &'db dyn Db, + type_mapping: &TypeMapping<'a, 'db>, + visitor: &ApplyTypeMappingVisitor<'db>, + ) -> Self { match self { Self::PositionalOnly { default_type, name } => Self::PositionalOnly { default_type: default_type .as_ref() - .map(|ty| ty.apply_type_mapping(db, type_mapping)), + .map(|ty| ty.apply_type_mapping_impl(db, type_mapping, visitor)), name: name.clone(), }, Self::PositionalOrKeyword { default_type, name } => Self::PositionalOrKeyword { default_type: default_type .as_ref() - .map(|ty| ty.apply_type_mapping(db, type_mapping)), + .map(|ty| ty.apply_type_mapping_impl(db, type_mapping, visitor)), name: name.clone(), }, Self::KeywordOnly { default_type, name } => Self::KeywordOnly { default_type: default_type .as_ref() - .map(|ty| ty.apply_type_mapping(db, type_mapping)), + .map(|ty| ty.apply_type_mapping_impl(db, type_mapping, visitor)), name: name.clone(), }, Self::Variadic { .. } | Self::KeywordVariadic { .. } => self.clone(),