mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-30 13:51:16 +00:00
[ty] improve cycle-detection coverage for apply_type_mapping (#20159)
Some checks failed
CI / Determine changes (push) Has been cancelled
CI / cargo fmt (push) Has been cancelled
CI / cargo build (release) (push) Has been cancelled
CI / python package (push) Has been cancelled
CI / pre-commit (push) Has been cancelled
CI / mkdocs (push) Has been cancelled
[ty Playground] Release / publish (push) Has been cancelled
CI / cargo clippy (push) Has been cancelled
CI / cargo test (linux) (push) Has been cancelled
CI / cargo test (linux, release) (push) Has been cancelled
CI / cargo test (windows) (push) Has been cancelled
CI / cargo test (wasm) (push) Has been cancelled
CI / cargo build (msrv) (push) Has been cancelled
CI / cargo fuzz build (push) Has been cancelled
CI / fuzz parser (push) Has been cancelled
CI / test scripts (push) Has been cancelled
CI / ecosystem (push) Has been cancelled
CI / Fuzz for new ty panics (push) Has been cancelled
CI / cargo shear (push) Has been cancelled
CI / formatter instabilities and black similarity (push) Has been cancelled
CI / test ruff-lsp (push) Has been cancelled
CI / check playground (push) Has been cancelled
CI / benchmarks-instrumented (push) Has been cancelled
CI / benchmarks-walltime (push) Has been cancelled
Some checks failed
CI / Determine changes (push) Has been cancelled
CI / cargo fmt (push) Has been cancelled
CI / cargo build (release) (push) Has been cancelled
CI / python package (push) Has been cancelled
CI / pre-commit (push) Has been cancelled
CI / mkdocs (push) Has been cancelled
[ty Playground] Release / publish (push) Has been cancelled
CI / cargo clippy (push) Has been cancelled
CI / cargo test (linux) (push) Has been cancelled
CI / cargo test (linux, release) (push) Has been cancelled
CI / cargo test (windows) (push) Has been cancelled
CI / cargo test (wasm) (push) Has been cancelled
CI / cargo build (msrv) (push) Has been cancelled
CI / cargo fuzz build (push) Has been cancelled
CI / fuzz parser (push) Has been cancelled
CI / test scripts (push) Has been cancelled
CI / ecosystem (push) Has been cancelled
CI / Fuzz for new ty panics (push) Has been cancelled
CI / cargo shear (push) Has been cancelled
CI / formatter instabilities and black similarity (push) Has been cancelled
CI / test ruff-lsp (push) Has been cancelled
CI / check playground (push) Has been cancelled
CI / benchmarks-instrumented (push) Has been cancelled
CI / benchmarks-walltime (push) Has been cancelled
## Summary Thread visitors through the rest of `apply_type_mapping`: callable and protocol types. ## Test Plan Added mdtest that previously stack overflowed.
This commit is contained in:
parent
17dc2e4d80
commit
6f2b874d6c
5 changed files with 112 additions and 44 deletions
|
@ -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
|
||||
|
|
|
@ -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),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -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::<BTreeMap<_, _>>(),
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue