Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions crates/ty_python_semantic/src/place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1671,7 +1671,7 @@ mod implicit_globals {
Place::Defined(
DefinedPlace::new(KnownClass::Dict.to_specialized_instance(
db,
[Type::any(), KnownClass::Int.to_instance(db)],
&[Type::any(), KnownClass::Int.to_instance(db)],
))
.with_definedness(Definedness::PossiblyUndefined),
)
Expand All @@ -1689,7 +1689,7 @@ mod implicit_globals {
),
KnownClass::Dict.to_specialized_instance(
db,
[KnownClass::Str.to_instance(db), Type::any()],
&[KnownClass::Str.to_instance(db), Type::any()],
),
);
Place::Defined(
Expand Down
12 changes: 6 additions & 6 deletions crates/ty_python_semantic/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4127,7 +4127,7 @@ impl<'db> Type<'db> {
.with_annotated_type(
KnownClass::Dict.to_specialized_instance(
db,
[str_instance, Type::any()],
&[str_instance, Type::any()],
),
),
],
Expand Down Expand Up @@ -4377,7 +4377,7 @@ impl<'db> Type<'db> {
.with_annotated_type(
KnownClass::Iterable.to_specialized_instance(
db,
[Type::TypeVar(element_ty)],
&[Type::TypeVar(element_ty)],
),
)],
),
Expand Down Expand Up @@ -5840,7 +5840,7 @@ impl<'db> Type<'db> {
pub(crate) fn dunder_class(self, db: &'db dyn Db) -> Type<'db> {
if self.is_typed_dict() {
return KnownClass::Dict
.to_specialized_class_type(db, [KnownClass::Str.to_instance(db), Type::object()])
.to_specialized_class_type(db, &[KnownClass::Str.to_instance(db), Type::object()])
.map(Type::from)
// Guard against user-customized typesheds with a broken `dict` class
.unwrap_or_else(Type::unknown);
Expand Down Expand Up @@ -8370,7 +8370,7 @@ impl<'db> BoundTypeVarInstance<'db> {
let upper_bound = TypeVarBoundOrConstraints::UpperBound(match kind {
ParamSpecAttrKind::Args => Type::homogeneous_tuple(db, Type::object()),
ParamSpecAttrKind::Kwargs => KnownClass::Dict
.to_specialized_instance(db, [KnownClass::Str.to_instance(db), Type::any()])
.to_specialized_instance(db, &[KnownClass::Str.to_instance(db), Type::any()])
.top_materialization(db),
});

Expand Down Expand Up @@ -13079,11 +13079,11 @@ pub(crate) mod tests {
let recursive = UnionType::from_elements(
&db,
[
KnownClass::List.to_specialized_instance(&db, [div]),
KnownClass::List.to_specialized_instance(&db, &[div]),
Type::none(&db),
],
);
let nested_rec = KnownClass::List.to_specialized_instance(&db, [recursive]);
let nested_rec = KnownClass::List.to_specialized_instance(&db, &[recursive]);
assert_eq!(
nested_rec.display(&db).to_string(),
"list[list[Divergent] | None]"
Expand Down
2 changes: 1 addition & 1 deletion crates/ty_python_semantic/src/types/bound_super.rs
Original file line number Diff line number Diff line change
Expand Up @@ -603,7 +603,7 @@ impl<'db> BoundSuperType<'db> {
}
return delegate_to(
KnownClass::Dict
.to_specialized_instance(db, [key_builder.build(), value_builder.build()]),
.to_specialized_instance(db, &[key_builder.build(), value_builder.build()]),
);
}
Type::NewTypeInstance(newtype) => {
Expand Down
4 changes: 2 additions & 2 deletions crates/ty_python_semantic/src/types/call/bind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -662,7 +662,7 @@ impl<'db> Bindings<'db> {
if let Some(enum_instance) = bound_method.self_instance(db).to_instance(db)
{
overload.set_return_type(
KnownClass::Iterator.to_specialized_instance(db, [enum_instance]),
KnownClass::Iterator.to_specialized_instance(db, &[enum_instance]),
);
}
}
Expand Down Expand Up @@ -993,7 +993,7 @@ impl<'db> Bindings<'db> {
let specialization = UnionType::from_elements(db, member_names);
overload.set_return_type(
KnownClass::FrozenSet
.to_specialized_instance(db, [specialization]),
.to_specialized_instance(db, &[specialization]),
);
}
}
Expand Down
69 changes: 36 additions & 33 deletions crates/ty_python_semantic/src/types/class.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::borrow::Cow;
use std::cell::RefCell;
use std::fmt::Write;
use std::sync::{LazyLock, Mutex};
Expand Down Expand Up @@ -1091,7 +1092,7 @@ impl<'db> ClassType<'db> {
let mut tuple_elements = tuple.iter_all_elements();
iterable_parameter = iterable_parameter.with_annotated_type(
KnownClass::Iterable
.to_specialized_instance(db, [tuple_elements.next().unwrap()]),
.to_specialized_instance(db, &[tuple_elements.next().unwrap()]),
);
assert_eq!(
tuple_elements.next(),
Expand Down Expand Up @@ -2061,7 +2062,7 @@ impl<'db> ClassLiteral<'db> {
let name = Type::string_literal(db, self.name(db));
let bases = Type::heterogeneous_tuple(db, self.explicit_bases(db));
let namespace = KnownClass::Dict
.to_specialized_instance(db, [KnownClass::Str.to_instance(db), Type::any()]);
.to_specialized_instance(db, &[KnownClass::Str.to_instance(db), Type::any()]);

// TODO: Other keyword arguments?
let arguments = CallArguments::positional([name, bases, namespace]);
Expand Down Expand Up @@ -2308,9 +2309,9 @@ impl<'db> ClassLiteral<'db> {
return Member {
inner: Place::declared(KnownClass::Dict.to_specialized_instance(
db,
[
&[
KnownClass::Str.to_instance(db),
KnownClass::Field.to_specialized_instance(db, [Type::any()]),
KnownClass::Field.to_specialized_instance(db, &[Type::any()]),
],
))
.with_qualifiers(TypeQualifiers::CLASS_VAR),
Expand Down Expand Up @@ -5197,18 +5198,26 @@ impl KnownClass {
///
/// If the class cannot be found in typeshed, or if you provide a specialization with the wrong
/// number of types, a debug-level log message will be emitted stating this.
pub(crate) fn to_specialized_class_type<'db>(
pub(crate) fn to_specialized_class_type<'t, 'db, T>(
self,
db: &'db dyn Db,
specialization: impl IntoIterator<Item = Type<'db>>,
) -> Option<ClassType<'db>> {
fn to_specialized_class_type_impl<'db>(
specialization: T,
) -> Option<ClassType<'db>>
where
T: Into<Cow<'t, [Type<'db>]>>,
'db: 't,
{
fn inner<'db>(
db: &'db dyn Db,
class: KnownClass,
class_literal: ClassLiteral<'db>,
specialization: Box<[Type<'db>]>,
generic_context: GenericContext<'db>,
) -> ClassType<'db> {
specialization: Cow<[Type<'db>]>,
) -> Option<ClassType<'db>> {
let Type::ClassLiteral(class_literal) = class.to_class_literal(db) else {
return None;
};

let generic_context = class_literal.generic_context(db)?;

if specialization.len() != generic_context.len(db) {
// a cache of the `KnownClass`es that we have already seen mismatched-arity
// specializations for (and therefore that we've already logged a warning for)
Expand All @@ -5217,31 +5226,21 @@ impl KnownClass {
if MESSAGES.lock().unwrap().insert(class) {
tracing::info!(
"Wrong number of types when specializing {}. \
Falling back to default specialization for the symbol instead.",
Falling back to default specialization for the symbol instead.",
class.display(db)
);
}
return class_literal.default_specialization(db);
return Some(class_literal.default_specialization(db));
}

class_literal
.apply_specialization(db, |_| generic_context.specialize(db, specialization))
Some(
class_literal
.apply_specialization(db, |_| generic_context.specialize(db, specialization)),
)
}

let Type::ClassLiteral(class_literal) = self.to_class_literal(db) else {
return None;
};

let generic_context = class_literal.generic_context(db)?;
let types = specialization.into_iter().collect::<Box<[_]>>();

Some(to_specialized_class_type_impl(
db,
self,
class_literal,
types,
generic_context,
))
let specialization = specialization.into();
inner(db, self, specialization)
}

/// Lookup a [`KnownClass`] in typeshed and return a [`Type`]
Expand All @@ -5250,11 +5249,15 @@ impl KnownClass {
/// If the class cannot be found in typeshed, or if you provide a specialization with the wrong
/// number of types, a debug-level log message will be emitted stating this.
#[track_caller]
pub(crate) fn to_specialized_instance<'db>(
pub(crate) fn to_specialized_instance<'t, 'db, T>(
self,
db: &'db dyn Db,
specialization: impl IntoIterator<Item = Type<'db>>,
) -> Type<'db> {
specialization: T,
) -> Type<'db>
where
T: Into<Cow<'t, [Type<'db>]>>,
'db: 't,
{
debug_assert_ne!(
self,
KnownClass::Tuple,
Expand Down
23 changes: 15 additions & 8 deletions crates/ty_python_semantic/src/types/generics.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::borrow::Cow;
use std::cell::RefCell;
use std::collections::hash_map::Entry;
use std::fmt::Display;
Expand Down Expand Up @@ -500,13 +501,17 @@ impl<'db> GenericContext<'db> {

/// Returns a specialization of this generic context where each typevar is mapped to itself.
pub(crate) fn identity_specialization(self, db: &'db dyn Db) -> Specialization<'db> {
let types = self.variables(db).map(Type::TypeVar).collect();
let types: Vec<Type> = self.variables(db).map(Type::TypeVar).collect();
self.specialize(db, types)
}

pub(crate) fn unknown_specialization(self, db: &'db dyn Db) -> Specialization<'db> {
let types = vec![Type::unknown(); self.len(db)];
self.specialize(db, types.into())
match self.len(db) {
0 => self.specialize(db, &[]),
1 => self.specialize(db, &[Type::unknown(); 1]),
2 => self.specialize(db, &[Type::unknown(); 2]),
len => self.specialize(db, vec![Type::unknown(); len]),
}
}

pub(crate) fn is_subset_of(self, db: &'db dyn Db, other: GenericContext<'db>) -> bool {
Expand Down Expand Up @@ -545,11 +550,13 @@ impl<'db> GenericContext<'db> {
/// otherwise, you will be left with a partial specialization. (Use
/// [`specialize_recursive`](Self::specialize_recursive) if your types might mention typevars
/// in this generic context.)
pub(crate) fn specialize(
self,
db: &'db dyn Db,
types: Box<[Type<'db>]>,
) -> Specialization<'db> {
pub(crate) fn specialize<'t, T>(self, db: &'db dyn Db, types: T) -> Specialization<'db>
where
T: Into<Cow<'t, [Type<'db>]>>,
'db: 't,
{
let types = types.into();

assert_eq!(self.len(db), types.len());
Specialization::new(db, self, types, None, None)
}
Expand Down
Loading
Loading