mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-15 08:00:19 +00:00
[ty] Handle typevars that have other typevars as a default (#17956)
It's possible for a typevar to list another typevar as its default value: ```py class C[T, U = T]: ... ``` When specializing this class, if a type isn't provided for `U`, we would previously use the default as-is, leaving an unspecialized `T` typevar in the specialization. Instead, we want to use what `T` is mapped to as the type of `U`. ```py reveal_type(C()) # revealed: C[Unknown, Unknown] reveal_type(C[int]()) # revealed: C[int, int] reveal_type(C[int, str]()) # revealed: C[int, str] ``` This is especially important for the `slice` built-in type.
This commit is contained in:
parent
f51f1f7153
commit
b705664d49
11 changed files with 226 additions and 102 deletions
|
@ -45,7 +45,7 @@ use crate::types::call::{Bindings, CallArgumentTypes, CallableBinding};
|
|||
pub(crate) use crate::types::class_base::ClassBase;
|
||||
use crate::types::context::{LintDiagnosticGuard, LintDiagnosticGuardBuilder};
|
||||
use crate::types::diagnostic::{INVALID_TYPE_FORM, UNSUPPORTED_BOOL_CONVERSION};
|
||||
use crate::types::generics::{GenericContext, Specialization};
|
||||
use crate::types::generics::{GenericContext, Specialization, TypeMapping};
|
||||
use crate::types::infer::infer_unpack_types;
|
||||
use crate::types::mro::{Mro, MroError, MroIterator};
|
||||
pub(crate) use crate::types::narrow::infer_narrowing_constraint;
|
||||
|
@ -342,13 +342,13 @@ pub struct PropertyInstanceType<'db> {
|
|||
}
|
||||
|
||||
impl<'db> PropertyInstanceType<'db> {
|
||||
fn apply_specialization(self, db: &'db dyn Db, specialization: Specialization<'db>) -> Self {
|
||||
fn apply_type_mapping<'a>(self, db: &'db dyn Db, type_mapping: TypeMapping<'a, 'db>) -> Self {
|
||||
let getter = self
|
||||
.getter(db)
|
||||
.map(|ty| ty.apply_specialization(db, specialization));
|
||||
.map(|ty| ty.apply_type_mapping(db, type_mapping));
|
||||
let setter = self
|
||||
.setter(db)
|
||||
.map(|ty| ty.apply_specialization(db, specialization));
|
||||
.map(|ty| ty.apply_type_mapping(db, type_mapping));
|
||||
Self::new(db, getter, setter)
|
||||
}
|
||||
|
||||
|
@ -5043,75 +5043,83 @@ impl<'db> Type<'db> {
|
|||
self,
|
||||
db: &'db dyn Db,
|
||||
specialization: Specialization<'db>,
|
||||
) -> Type<'db> {
|
||||
self.apply_type_mapping(db, specialization.type_mapping())
|
||||
}
|
||||
|
||||
fn apply_type_mapping<'a>(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
type_mapping: TypeMapping<'a, 'db>,
|
||||
) -> Type<'db> {
|
||||
match self {
|
||||
Type::TypeVar(typevar) => specialization.get(db, typevar).unwrap_or(self),
|
||||
Type::TypeVar(typevar) => type_mapping.get(db, typevar).unwrap_or(self),
|
||||
|
||||
Type::FunctionLiteral(function) => {
|
||||
Type::FunctionLiteral(function.apply_specialization(db, specialization))
|
||||
Type::FunctionLiteral(function.apply_type_mapping(db, type_mapping))
|
||||
}
|
||||
|
||||
Type::BoundMethod(method) => Type::BoundMethod(BoundMethodType::new(
|
||||
db,
|
||||
method.function(db).apply_specialization(db, specialization),
|
||||
method.self_instance(db).apply_specialization(db, specialization),
|
||||
method.function(db).apply_type_mapping(db, type_mapping),
|
||||
method.self_instance(db).apply_type_mapping(db, type_mapping),
|
||||
)),
|
||||
|
||||
Type::NominalInstance(instance) => Type::NominalInstance(
|
||||
instance.apply_specialization(db, specialization),
|
||||
instance.apply_type_mapping(db, type_mapping),
|
||||
),
|
||||
|
||||
Type::MethodWrapper(MethodWrapperKind::FunctionTypeDunderGet(function)) => {
|
||||
Type::MethodWrapper(MethodWrapperKind::FunctionTypeDunderGet(
|
||||
function.apply_specialization(db, specialization),
|
||||
function.apply_type_mapping(db, type_mapping),
|
||||
))
|
||||
}
|
||||
|
||||
Type::MethodWrapper(MethodWrapperKind::FunctionTypeDunderCall(function)) => {
|
||||
Type::MethodWrapper(MethodWrapperKind::FunctionTypeDunderCall(
|
||||
function.apply_specialization(db, specialization),
|
||||
function.apply_type_mapping(db, type_mapping),
|
||||
))
|
||||
}
|
||||
|
||||
Type::MethodWrapper(MethodWrapperKind::PropertyDunderGet(property)) => {
|
||||
Type::MethodWrapper(MethodWrapperKind::PropertyDunderGet(
|
||||
property.apply_specialization(db, specialization),
|
||||
property.apply_type_mapping(db, type_mapping),
|
||||
))
|
||||
}
|
||||
|
||||
Type::MethodWrapper(MethodWrapperKind::PropertyDunderSet(property)) => {
|
||||
Type::MethodWrapper(MethodWrapperKind::PropertyDunderSet(
|
||||
property.apply_specialization(db, specialization),
|
||||
property.apply_type_mapping(db, type_mapping),
|
||||
))
|
||||
}
|
||||
|
||||
Type::Callable(callable) => {
|
||||
Type::Callable(callable.apply_specialization(db, specialization))
|
||||
Type::Callable(callable.apply_type_mapping(db, type_mapping))
|
||||
}
|
||||
|
||||
Type::GenericAlias(generic) => {
|
||||
let specialization = generic
|
||||
.specialization(db)
|
||||
.apply_specialization(db, specialization);
|
||||
.apply_type_mapping(db, type_mapping);
|
||||
Type::GenericAlias(GenericAlias::new(db, generic.origin(db), specialization))
|
||||
}
|
||||
|
||||
Type::PropertyInstance(property) => {
|
||||
Type::PropertyInstance(property.apply_specialization(db, specialization))
|
||||
Type::PropertyInstance(property.apply_type_mapping(db, type_mapping))
|
||||
}
|
||||
|
||||
Type::Union(union) => union.map(db, |element| {
|
||||
element.apply_specialization(db, specialization)
|
||||
element.apply_type_mapping(db, type_mapping)
|
||||
}),
|
||||
Type::Intersection(intersection) => {
|
||||
let mut builder = IntersectionBuilder::new(db);
|
||||
for positive in intersection.positive(db) {
|
||||
builder =
|
||||
builder.add_positive(positive.apply_specialization(db, specialization));
|
||||
builder.add_positive(positive.apply_type_mapping(db, type_mapping));
|
||||
}
|
||||
for negative in intersection.negative(db) {
|
||||
builder =
|
||||
builder.add_negative(negative.apply_specialization(db, specialization));
|
||||
builder.add_negative(negative.apply_type_mapping(db, type_mapping));
|
||||
}
|
||||
builder.build()
|
||||
}
|
||||
|
@ -5119,7 +5127,7 @@ impl<'db> Type<'db> {
|
|||
db,
|
||||
tuple
|
||||
.iter(db)
|
||||
.map(|ty| ty.apply_specialization(db, specialization)),
|
||||
.map(|ty| ty.apply_type_mapping(db, type_mapping)),
|
||||
),
|
||||
|
||||
Type::Dynamic(_)
|
||||
|
@ -6844,6 +6852,10 @@ impl<'db> FunctionType<'db> {
|
|||
)
|
||||
}
|
||||
|
||||
fn apply_type_mapping<'a>(self, db: &'db dyn Db, type_mapping: TypeMapping<'a, 'db>) -> Self {
|
||||
self.apply_specialization(db, type_mapping.into_specialization(db))
|
||||
}
|
||||
|
||||
fn find_legacy_typevars(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
|
@ -7192,15 +7204,12 @@ impl<'db> CallableType<'db> {
|
|||
)
|
||||
}
|
||||
|
||||
/// Apply a specialization to this callable type.
|
||||
///
|
||||
/// See [`Type::apply_specialization`] for more details.
|
||||
fn apply_specialization(self, db: &'db dyn Db, specialization: Specialization<'db>) -> Self {
|
||||
fn apply_type_mapping<'a>(self, db: &'db dyn Db, type_mapping: TypeMapping<'a, 'db>) -> Self {
|
||||
CallableType::from_overloads(
|
||||
db,
|
||||
self.signatures(db)
|
||||
.iter()
|
||||
.map(|signature| signature.apply_specialization(db, specialization)),
|
||||
.map(|signature| signature.apply_type_mapping(db, type_mapping)),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -1368,21 +1368,6 @@ impl<'db> Binding<'db> {
|
|||
&self.parameter_tys
|
||||
}
|
||||
|
||||
/// Returns the bound types for each parameter, in parameter source order, with default values
|
||||
/// applied for arguments that weren't matched to a parameter. Returns `None` if there are any
|
||||
/// non-default arguments that weren't matched to a parameter.
|
||||
pub(crate) fn parameter_types_with_defaults(
|
||||
&self,
|
||||
signature: &Signature<'db>,
|
||||
) -> Option<Box<[Type<'db>]>> {
|
||||
signature
|
||||
.parameters()
|
||||
.iter()
|
||||
.zip(&self.parameter_tys)
|
||||
.map(|(parameter, parameter_ty)| parameter_ty.or(parameter.default_type()))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(crate) fn arguments_for_parameter<'a>(
|
||||
&'a self,
|
||||
argument_types: &'a CallArgumentTypes<'a, 'db>,
|
||||
|
|
|
@ -8,7 +8,7 @@ use super::{
|
|||
};
|
||||
use crate::semantic_index::definition::Definition;
|
||||
use crate::semantic_index::DeclarationWithConstraint;
|
||||
use crate::types::generics::{GenericContext, Specialization};
|
||||
use crate::types::generics::{GenericContext, Specialization, TypeMapping};
|
||||
use crate::types::signatures::{Parameter, Parameters};
|
||||
use crate::types::{
|
||||
CallableType, DataclassParams, DataclassTransformerParams, KnownInstanceType, Signature,
|
||||
|
@ -147,16 +147,11 @@ impl<'db> GenericAlias<'db> {
|
|||
self.origin(db).definition(db)
|
||||
}
|
||||
|
||||
pub(super) fn apply_specialization(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
specialization: Specialization<'db>,
|
||||
) -> Self {
|
||||
fn apply_type_mapping<'a>(self, db: &'db dyn Db, type_mapping: TypeMapping<'a, 'db>) -> Self {
|
||||
Self::new(
|
||||
db,
|
||||
self.origin(db),
|
||||
self.specialization(db)
|
||||
.apply_specialization(db, specialization),
|
||||
self.specialization(db).apply_type_mapping(db, type_mapping),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -236,16 +231,14 @@ impl<'db> ClassType<'db> {
|
|||
self.is_known(db, KnownClass::Object)
|
||||
}
|
||||
|
||||
pub(super) fn apply_specialization(
|
||||
pub(super) fn apply_type_mapping<'a>(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
specialization: Specialization<'db>,
|
||||
type_mapping: TypeMapping<'a, 'db>,
|
||||
) -> Self {
|
||||
match self {
|
||||
Self::NonGeneric(_) => self,
|
||||
Self::Generic(generic) => {
|
||||
Self::Generic(generic.apply_specialization(db, specialization))
|
||||
}
|
||||
Self::Generic(generic) => Self::Generic(generic.apply_type_mapping(db, type_mapping)),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::types::generics::{GenericContext, Specialization};
|
||||
use crate::types::generics::{GenericContext, Specialization, TypeMapping};
|
||||
use crate::types::{
|
||||
todo_type, ClassType, DynamicType, KnownClass, KnownInstanceType, MroIterator, Type,
|
||||
};
|
||||
|
@ -215,13 +215,9 @@ impl<'db> ClassBase<'db> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn apply_specialization(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
specialization: Specialization<'db>,
|
||||
) -> Self {
|
||||
fn apply_type_mapping<'a>(self, db: &'db dyn Db, type_mapping: TypeMapping<'a, 'db>) -> Self {
|
||||
match self {
|
||||
Self::Class(class) => Self::Class(class.apply_specialization(db, specialization)),
|
||||
Self::Class(class) => Self::Class(class.apply_type_mapping(db, type_mapping)),
|
||||
Self::Dynamic(_) | Self::Generic(_) | Self::Protocol => self,
|
||||
}
|
||||
}
|
||||
|
@ -232,7 +228,7 @@ impl<'db> ClassBase<'db> {
|
|||
specialization: Option<Specialization<'db>>,
|
||||
) -> Self {
|
||||
if let Some(specialization) = specialization {
|
||||
self.apply_specialization(db, specialization)
|
||||
self.apply_type_mapping(db, specialization.type_mapping())
|
||||
} else {
|
||||
self
|
||||
}
|
||||
|
|
|
@ -130,12 +130,7 @@ impl<'db> GenericContext<'db> {
|
|||
}
|
||||
|
||||
pub(crate) fn default_specialization(self, db: &'db dyn Db) -> Specialization<'db> {
|
||||
let types = self
|
||||
.variables(db)
|
||||
.iter()
|
||||
.map(|typevar| typevar.default_ty(db).unwrap_or(Type::unknown()))
|
||||
.collect();
|
||||
self.specialize(db, types)
|
||||
self.specialize_partial(db, &vec![None; self.variables(db).len()])
|
||||
}
|
||||
|
||||
pub(crate) fn identity_specialization(self, db: &'db dyn Db) -> Specialization<'db> {
|
||||
|
@ -157,7 +152,9 @@ impl<'db> GenericContext<'db> {
|
|||
}
|
||||
|
||||
/// Creates a specialization of this generic context. Panics if the length of `types` does not
|
||||
/// match the number of typevars in the generic context.
|
||||
/// match the number of typevars in the generic context. You must provide a specific type for
|
||||
/// each typevar; no defaults are used. (Use [`specialize_partial`](Self::specialize_partial)
|
||||
/// if you might not have types for every typevar.)
|
||||
pub(crate) fn specialize(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
|
@ -166,6 +163,50 @@ impl<'db> GenericContext<'db> {
|
|||
assert!(self.variables(db).len() == types.len());
|
||||
Specialization::new(db, self, types)
|
||||
}
|
||||
|
||||
/// Creates a specialization of this generic context. Panics if the length of `types` does not
|
||||
/// match the number of typevars in the generic context. If any provided type is `None`, we
|
||||
/// will use the corresponding typevar's default type.
|
||||
pub(crate) fn specialize_partial(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
types: &[Option<Type<'db>>],
|
||||
) -> Specialization<'db> {
|
||||
let variables = self.variables(db);
|
||||
assert!(variables.len() == types.len());
|
||||
|
||||
// Typevars can have other typevars as their default values, e.g.
|
||||
//
|
||||
// ```py
|
||||
// class C[T, U = T]: ...
|
||||
// ```
|
||||
//
|
||||
// If there is a mapping for `T`, we want to map `U` to that type, not to `T`. To handle
|
||||
// this, we repeatedly apply the specialization to itself, until we reach a fixed point.
|
||||
let mut expanded = vec![Type::unknown(); types.len()];
|
||||
for (idx, (ty, typevar)) in types.iter().zip(variables).enumerate() {
|
||||
if let Some(ty) = ty {
|
||||
expanded[idx] = *ty;
|
||||
continue;
|
||||
}
|
||||
|
||||
let Some(default) = typevar.default_ty(db) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
// Typevars are only allowed to refer to _earlier_ typevars in their defaults. (This is
|
||||
// statically enforced for PEP-695 contexts, and is explicitly called out as a
|
||||
// requirement for legacy contexts.)
|
||||
let type_mapping = TypeMapping::Partial {
|
||||
generic_context: self,
|
||||
types: &expanded[0..idx],
|
||||
};
|
||||
let default = default.apply_type_mapping(db, type_mapping);
|
||||
expanded[idx] = default;
|
||||
}
|
||||
|
||||
Specialization::new(db, self, expanded.into_boxed_slice())
|
||||
}
|
||||
}
|
||||
|
||||
/// An assignment of a specific type to each type variable in a generic scope.
|
||||
|
@ -180,6 +221,10 @@ pub struct Specialization<'db> {
|
|||
}
|
||||
|
||||
impl<'db> Specialization<'db> {
|
||||
pub(crate) fn type_mapping(self) -> TypeMapping<'db, 'db> {
|
||||
TypeMapping::Specialization(self)
|
||||
}
|
||||
|
||||
/// Applies a specialization to this specialization. This is used, for instance, when a generic
|
||||
/// class inherits from a generic alias:
|
||||
///
|
||||
|
@ -194,10 +239,18 @@ impl<'db> Specialization<'db> {
|
|||
/// That lets us produce the generic alias `A[int]`, which is the corresponding entry in the
|
||||
/// MRO of `B[int]`.
|
||||
pub(crate) fn apply_specialization(self, db: &'db dyn Db, other: Specialization<'db>) -> Self {
|
||||
self.apply_type_mapping(db, other.type_mapping())
|
||||
}
|
||||
|
||||
pub(crate) fn apply_type_mapping<'a>(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
type_mapping: TypeMapping<'a, 'db>,
|
||||
) -> Self {
|
||||
let types: Box<[_]> = self
|
||||
.types(db)
|
||||
.into_iter()
|
||||
.map(|ty| ty.apply_specialization(db, other))
|
||||
.map(|ty| ty.apply_type_mapping(db, type_mapping))
|
||||
.collect();
|
||||
Specialization::new(db, self.generic_context(db), types)
|
||||
}
|
||||
|
@ -244,16 +297,6 @@ impl<'db> Specialization<'db> {
|
|||
Self::new(db, self.generic_context(db), types)
|
||||
}
|
||||
|
||||
/// Returns the type that a typevar is specialized to, or None if the typevar isn't part of
|
||||
/// this specialization.
|
||||
pub(crate) fn get(self, db: &'db dyn Db, typevar: TypeVarInstance<'db>) -> Option<Type<'db>> {
|
||||
let index = self
|
||||
.generic_context(db)
|
||||
.variables(db)
|
||||
.get_index_of(&typevar)?;
|
||||
Some(self.types(db)[index])
|
||||
}
|
||||
|
||||
pub(crate) fn is_subtype_of(self, db: &'db dyn Db, other: Specialization<'db>) -> bool {
|
||||
let generic_context = self.generic_context(db);
|
||||
if generic_context != other.generic_context(db) {
|
||||
|
@ -403,6 +446,57 @@ impl<'db> Specialization<'db> {
|
|||
}
|
||||
}
|
||||
|
||||
/// A mapping between type variables and types.
|
||||
///
|
||||
/// You will usually use [`Specialization`] instead of this type. This type is used when we need to
|
||||
/// substitute types for type variables before we have fully constructed a [`Specialization`].
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub(crate) enum TypeMapping<'a, 'db> {
|
||||
Specialization(Specialization<'db>),
|
||||
Partial {
|
||||
generic_context: GenericContext<'db>,
|
||||
types: &'a [Type<'db>],
|
||||
},
|
||||
}
|
||||
|
||||
impl<'db> TypeMapping<'_, 'db> {
|
||||
fn generic_context(self, db: &'db dyn Db) -> GenericContext<'db> {
|
||||
match self {
|
||||
Self::Specialization(specialization) => specialization.generic_context(db),
|
||||
Self::Partial {
|
||||
generic_context, ..
|
||||
} => generic_context,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the type that a typevar is mapped to, or None if the typevar isn't part of this
|
||||
/// mapping.
|
||||
pub(crate) fn get(self, db: &'db dyn Db, typevar: TypeVarInstance<'db>) -> Option<Type<'db>> {
|
||||
let index = self
|
||||
.generic_context(db)
|
||||
.variables(db)
|
||||
.get_index_of(&typevar)?;
|
||||
match self {
|
||||
Self::Specialization(specialization) => specialization.types(db).get(index).copied(),
|
||||
Self::Partial { types, .. } => types.get(index).copied(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn into_specialization(self, db: &'db dyn Db) -> Specialization<'db> {
|
||||
match self {
|
||||
Self::Specialization(specialization) => specialization,
|
||||
Self::Partial {
|
||||
generic_context,
|
||||
types,
|
||||
} => {
|
||||
let mut types = types.to_vec();
|
||||
types.resize(generic_context.variables(db).len(), Type::unknown());
|
||||
Specialization::new(db, generic_context, types.into_boxed_slice())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Performs type inference between parameter annotations and argument types, producing a
|
||||
/// specialization of a generic function.
|
||||
pub(crate) struct SpecializationBuilder<'db> {
|
||||
|
|
|
@ -6899,8 +6899,10 @@ impl<'db> TypeInferenceBuilder<'db> {
|
|||
}
|
||||
_ => CallArgumentTypes::positional([self.infer_type_expression(slice_node)]),
|
||||
};
|
||||
let signature = generic_context.signature(self.db());
|
||||
let signatures = Signatures::single(CallableSignature::single(value_ty, signature.clone()));
|
||||
let signatures = Signatures::single(CallableSignature::single(
|
||||
value_ty,
|
||||
generic_context.signature(self.db()),
|
||||
));
|
||||
let bindings = match Bindings::match_parameters(signatures, &call_argument_types)
|
||||
.check_types(self.db(), &call_argument_types)
|
||||
{
|
||||
|
@ -6918,10 +6920,8 @@ impl<'db> TypeInferenceBuilder<'db> {
|
|||
.matching_overloads()
|
||||
.next()
|
||||
.expect("valid bindings should have matching overload");
|
||||
let parameters = overload
|
||||
.parameter_types_with_defaults(&signature)
|
||||
.expect("matching overload should not have missing arguments");
|
||||
let specialization = generic_context.specialize(self.db(), parameters);
|
||||
let specialization =
|
||||
generic_context.specialize_partial(self.db(), overload.parameter_types());
|
||||
Type::from(GenericAlias::new(self.db(), generic_class, specialization))
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
use super::protocol_class::ProtocolInterface;
|
||||
use super::{ClassType, KnownClass, SubclassOfType, Type};
|
||||
use crate::symbol::{Symbol, SymbolAndQualifiers};
|
||||
use crate::types::generics::Specialization;
|
||||
use crate::types::generics::TypeMapping;
|
||||
use crate::Db;
|
||||
|
||||
pub(super) use synthesized_protocol::SynthesizedProtocolType;
|
||||
|
@ -113,13 +113,13 @@ impl<'db> NominalInstanceType<'db> {
|
|||
SubclassOfType::from(db, self.class)
|
||||
}
|
||||
|
||||
pub(super) fn apply_specialization(
|
||||
pub(super) fn apply_type_mapping<'a>(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
specialization: Specialization<'db>,
|
||||
type_mapping: TypeMapping<'a, 'db>,
|
||||
) -> Self {
|
||||
Self {
|
||||
class: self.class.apply_specialization(db, specialization),
|
||||
class: self.class.apply_type_mapping(db, type_mapping),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ use smallvec::{smallvec, SmallVec};
|
|||
|
||||
use super::{definition_expression_type, DynamicType, Type};
|
||||
use crate::semantic_index::definition::Definition;
|
||||
use crate::types::generics::{GenericContext, Specialization};
|
||||
use crate::types::generics::{GenericContext, Specialization, TypeMapping};
|
||||
use crate::types::{todo_type, TypeVarInstance};
|
||||
use crate::{Db, FxOrderSet};
|
||||
use ruff_python_ast::{self as ast, name::Name};
|
||||
|
@ -313,14 +313,22 @@ impl<'db> Signature<'db> {
|
|||
&self,
|
||||
db: &'db dyn Db,
|
||||
specialization: Specialization<'db>,
|
||||
) -> Self {
|
||||
self.apply_type_mapping(db, specialization.type_mapping())
|
||||
}
|
||||
|
||||
pub(crate) fn apply_type_mapping<'a>(
|
||||
&self,
|
||||
db: &'db dyn Db,
|
||||
type_mapping: TypeMapping<'a, 'db>,
|
||||
) -> Self {
|
||||
Self {
|
||||
generic_context: self.generic_context,
|
||||
inherited_generic_context: self.inherited_generic_context,
|
||||
parameters: self.parameters.apply_specialization(db, specialization),
|
||||
parameters: self.parameters.apply_type_mapping(db, type_mapping),
|
||||
return_ty: self
|
||||
.return_ty
|
||||
.map(|ty| ty.apply_specialization(db, specialization)),
|
||||
.map(|ty| ty.apply_type_mapping(db, type_mapping)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1053,12 +1061,12 @@ impl<'db> Parameters<'db> {
|
|||
)
|
||||
}
|
||||
|
||||
fn apply_specialization(&self, db: &'db dyn Db, specialization: Specialization<'db>) -> Self {
|
||||
fn apply_type_mapping<'a>(&self, db: &'db dyn Db, type_mapping: TypeMapping<'a, 'db>) -> Self {
|
||||
Self {
|
||||
value: self
|
||||
.value
|
||||
.iter()
|
||||
.map(|param| param.apply_specialization(db, specialization))
|
||||
.map(|param| param.apply_type_mapping(db, type_mapping))
|
||||
.collect(),
|
||||
is_gradual: self.is_gradual,
|
||||
}
|
||||
|
@ -1225,12 +1233,12 @@ impl<'db> Parameter<'db> {
|
|||
self
|
||||
}
|
||||
|
||||
fn apply_specialization(&self, db: &'db dyn Db, specialization: Specialization<'db>) -> Self {
|
||||
fn apply_type_mapping<'a>(&self, db: &'db dyn Db, type_mapping: TypeMapping<'a, 'db>) -> Self {
|
||||
Self {
|
||||
annotated_type: self
|
||||
.annotated_type
|
||||
.map(|ty| ty.apply_specialization(db, specialization)),
|
||||
kind: self.kind.apply_specialization(db, specialization),
|
||||
.map(|ty| ty.apply_type_mapping(db, type_mapping)),
|
||||
kind: self.kind.apply_type_mapping(db, type_mapping),
|
||||
form: self.form,
|
||||
}
|
||||
}
|
||||
|
@ -1422,24 +1430,24 @@ pub(crate) enum ParameterKind<'db> {
|
|||
}
|
||||
|
||||
impl<'db> ParameterKind<'db> {
|
||||
fn apply_specialization(&self, db: &'db dyn Db, specialization: Specialization<'db>) -> Self {
|
||||
fn apply_type_mapping<'a>(&self, db: &'db dyn Db, type_mapping: TypeMapping<'a, 'db>) -> Self {
|
||||
match self {
|
||||
Self::PositionalOnly { default_type, name } => Self::PositionalOnly {
|
||||
default_type: default_type
|
||||
.as_ref()
|
||||
.map(|ty| ty.apply_specialization(db, specialization)),
|
||||
.map(|ty| ty.apply_type_mapping(db, type_mapping)),
|
||||
name: name.clone(),
|
||||
},
|
||||
Self::PositionalOrKeyword { default_type, name } => Self::PositionalOrKeyword {
|
||||
default_type: default_type
|
||||
.as_ref()
|
||||
.map(|ty| ty.apply_specialization(db, specialization)),
|
||||
.map(|ty| ty.apply_type_mapping(db, type_mapping)),
|
||||
name: name.clone(),
|
||||
},
|
||||
Self::KeywordOnly { default_type, name } => Self::KeywordOnly {
|
||||
default_type: default_type
|
||||
.as_ref()
|
||||
.map(|ty| ty.apply_specialization(db, specialization)),
|
||||
.map(|ty| ty.apply_type_mapping(db, type_mapping)),
|
||||
name: name.clone(),
|
||||
},
|
||||
Self::Variadic { .. } | Self::KeywordVariadic { .. } => self.clone(),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue